I want to duplicate a form using alpinejs and there is another form that can be duplicated inside this parent form. I’m doing very well so far. In the child form, there is a and its content depends on the choice in the parent form. Clicking on a choice in the parent form triggers a function call that fetches the corresponding results from the back end, and these results are used as choices in the child form.
How do I fill in and manage the choice in this child form?
here is my livewire component:
view:
<div>
<form action="" x-data="{
produits: @entangle('produits'),
getNextId(items) {
const ids = items.map(item => item.id);
return ids.length > 0 ? Math.max(...ids) + 1 : 1;
},
duplicateProduct() {
// const newProduct = JSON.parse(JSON.stringify(this.produits[0]));
const defaultProduct = {
id: this.getNextId(this.produits),
produit: '',
masses: [{
id: 1,
masse_unite: '',
nombre: '',
}],
};
// newProduct.id = this.getNextId(this.produits);
this.produits.push({ ...defaultProduct });
},
duplicateMasse(productIndex) {
const product = this.produits[productIndex];
const newMasse = { id: this.getNextId(product.masses), masse_unite: '', nombre: '' };
product.masses.push(newMasse);
},
removeProduct(productIndex) {
if (this.produits.length > 1) {
this.produits.splice(productIndex, 1);
}
},
removeMasse(productIndex, masseIndex) {
const product = this.produits[productIndex];
if (product.masses.length > 1) {
product.masses.splice(masseIndex, 1);
}
},
}">
<div class="flex justify-start">
<div class="">
<label for="" class="text-gray-700">Date</label>
<div class="relative mt-1 mb-3" data-te-input-wrapper-init id="datepicker-disabled-dates"
data-te-format="dd mmmm yyyy">
<input type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[te-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-neutral-200 dark:placeholder:text-neutral-200 dark:peer-focus:text-primary [&:not([data-te-input-placeholder-active])]:placeholder:opacity-0"
placeholder="Select a date" />
</div>
</div>
</div>
<hr class="my-6">
<template x-for="(product, productIndex) in produits" :key="product.id">
<div>
<div class="inline-flex w-full items-center mb-4 pr-3">
<h4 class="underline">Article #<span x-text="productIndex + 1"></span></h4>
<button type="button" @click="removeProduct(productIndex)" x-show="produits.length > 1"
class="text-red-500 items-center ml-6 hover:underline hover:underline-offset-2">Supprimer</button>
</div>
<div class="grid grid-cols-3 gap-4">
<div>
<x-input-label ::for="'produit_' + product.id" :value="__('Produit')" />
<select name="produit" :id="'produit_' + product.id" wire:change='getMasseUnite(productIndex)'
x-model='product.produit'
class="w-full mt-1 rounded focus:border-blue-400 focus:ring-blue-400 focus:outline-none border-gray-300">
<option value="">--- Sélectionner ---</option>
@foreach ($stocks as $stock)
<option value="{{ $stock->produit_id . ',' . $stock->purete_id }}">
{{ $stock->produit->nom . ' ' . formatFrenchNumber($stock->purete->purete) . ' %' }}
</option>
@endforeach
</select>
</div>
<div class="col-span-2 ml-6">
<template x-for="(masse, masseIndex) in product.masses" :key="masse.id">
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<x-input-label ::for="'masse_bloc_' + masse.id" :value="__('Masse/bloc')" />
<select name="masse_bloc" :id="'masse_bloc_' + masse.id" x-model=masse.masse_unite
class="w-full mt-1 rounded focus:border-blue-400 focus:ring-blue-400 focus:outline-none border-gray-300">
@if (!is_null($masses['productIndex']))
@foreach ($masses['productIndex'] as $masse)
<option value="">{{ $masse->masse_unite . ' g' }}</option>
@endforeach
@endif
</select>
</div>
<div>
<x-input-label ::for="'nbr_masse_bloc_' + masse.id" :value="__('Nombre')" />
<div class="inline-flex items-center space-x-3 w-full">
<x-text-input ::id="'nbr_masse_bloc_' + masse.id" name="nbr_masse_bloc" x-model="masse.nombre"
type="text" class="mt-1 block w-full" required placeholder='12' />
<button type="button" class="text-red-500 transition-transform hover:scale-110"
x-show="product.masses.length > 1"
@click="removeMasse(productIndex, masseIndex)">
<svg data-slot="icon" fill="none" class="w-5 h-5" stroke-width="1.5"
stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0">
</path>
</svg>
</button>
</div>
</div>
</div>
</template>
{{-- bouton ajouter d'autre masse bloc --}}
<div class="flex w-full justify-end items-center">
<div class="mb-3 mt-5">
<button type="button" @click="duplicateMasse(productIndex)"
class="text-blue-500 inline-flex items-center hover:underline hover:underline-offset-2">
<svg fill="none" class="w-5 h-5 mr-2" stroke="currentColor" stroke-width="1.5"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
Ajouter un autre bloc
</button>
</div>
</div>
</div>
<hr class="mb-4 col-span-3" x-show="produits.length > 1 && produits.length != productIndex + 1">
</div>
</div>
</template>
<div class="mb-3">
<button type="button" @click="duplicateProduct()"
class="text-blue-500 inline-flex items-center hover:underline hover:underline-offset-2">
<svg fill="none" class="w-5 h-5 mr-2" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
Ajouter d'autre produit
</button>
</div>
{{-- <hr class="my-3">
<div class="grid grid-cols-5 pt-3 gap-x-4">
<div>
<x-input-label for="type_transformation" :value="__('Transformer en')" />
<select name="type_transformation" id="type_transformation"
class="w-full mt-1 rounded focus:border-blue-400 focus:ring-blue-400 focus:outline-none border-gray-300">
<option value="">Lingot</option>
<option value="">barette</option>
<option value="">Bille</option>
</select>
</div>
<div>
<x-input-label for="dimension" :value="__('Dimension')" />
<x-text-input id="dimension" name="dimension" type="text" class="mt-1 block w-full" required
placeholder='100 x 400 x 25' />
</div>
<div>
<x-input-label for="purete_attendue" :value="__('Purété final')" />
<x-text-input id="purete_attendue" name="purete_attendue" type="text" class="mt-1 block w-full"
placeholder='99,99%' />
</div>
<div>
<x-input-label for="masse_unite_final" :value="__('Masse par Unité')" />
<x-text-input id="masse_unite_final" name="masse_unite_final" type="text"
class="mt-1 block w-full" placeholder='2 150 g' />
</div>
<div>
<x-input-label for="nombre_final" :value="__('Nombre')" />
<x-text-input id="nombre_final" name="nombre_final" type="text" class="mt-1 block w-full"
placeholder='25' />
</div>
</div> --}}
<div class="flex items-center justify-end space-x-6 mt-6">
<button type="button"
class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200">
Annuler
</button>
<button type="button"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-[0_4px_9px_-4px_#3b71ca] transition duration-150 ease-in-out hover:bg-primary-600 hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:bg-primary-600 focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] focus:outline-none focus:ring-0 active:bg-primary-700 active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.3),0_4px_18px_0_rgba(59,113,202,0.2)] dark:shadow-[0_4px_9px_-4px_rgba(59,113,202,0.5)] dark:hover:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:focus:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)] dark:active:shadow-[0_8px_9px_-4px_rgba(59,113,202,0.2),0_4px_18px_0_rgba(59,113,202,0.1)]">
Enregistrer
</button>
</div>
</form>
</div>
livewire:
<?php
namespace AppLivewireTransformation;
use AppModelsStock;
use LivewireComponent;
class NewTransformation extends Component
{
public $date_transformation;
public $produits = [
[
'id' => 1,
'produit' => '',
'masses'=> [
[
'id' => 1,
'masse_unite' => '',
'nombre' => '',
]
],
]
];
public $stocks;
public $masses = [];
public function mount() {
$this->stocks = Stock::select('produit_id', 'purete_id')
->groupBy('produit_id', 'purete_id')
->with('produit', 'purete')
->orderBy('produit_id')
->orderBy('purete_id')
->get();
}
public function render()
{
return view('livewire.transformation.new-transformation');
}
public function getMasseUnite($index) {
$prod = $this->produits[$index];
$arrayId = explode(',', $prod['produit']);
$this->masses[$index] = Stock::where('produit_id', $arrayId[0])
->where('purete_id', $arrayId[1])
->get();
}
}