Reputation: 7755
I'm confused on how would i get the checkbox value so i get the "amount" and the "total" values. The computation is pretty simple. The checkbox value is 1.20 or 20%. The amount is (quantity * price) / checkbox value, if the checkbox value have a check on it. And the total value is only (quantity * price). Here's the link to my codes.
UPDATE!!! Now it's working but the problem is that it doesn't automatically calculates but i have to click outside the input field to update it.
onChange(isChecked, id){
console.log(isChecked)
let quantity = (<FormArray>this.myForm.controls['rows']).controls[id]['controls']['quantity'].value
let price = (<FormArray>this.myForm.controls['rows']).controls[id]['controls']['price'].value
let checkbox = (<FormArray>this.myForm.controls['rows']).controls[id]['controls']['checkbox'].value
let x = (<FormArray>this.myForm.controls['rows']).at(id);
if(isChecked){
x.patchValue({
amount: (quantity * price)/checkbox,
total: quantity * price
});
}
else {
x.patchValue({
amount: (quantity * price)/checkbox,
total: (quantity * price)/checkbox,
});
}
}
Upvotes: 0
Views: 510
Reputation: 57939
Sorry the delay. I you want to use a "auxiliar variable" "totals" you must
//declare the variable at first
totals:any[]=[] //totals will be like, e.g. [{total:0,amount:0},{total:10,amount:23}...]
//In patchValues
this.orders.forEach(material => {
material.materials.forEach(x => {
rows.push(this.fb.group({
material_id: x.id,
material_name: x.name,
quantity: [null, Validators.required],
price: [null, Validators.required],
dis_checkbox: [true],
checkbox: [1.20]
})) //see that total and amount is NOT in the form
this.totals.push({amount:0,total:0}); //<--add this line
})
})
//And finally, we change the "setOnchange" (I commented the lines that you don't need)
setOnChange()
{
const formarray=this.myForm.get('rows') as FormArray;
for (let i=0;i<formarray.length;i++)
{
formarray.at(i).valueChanges.subscribe(val=>{
//"total" and "amount" are simply variables
//we needn't look for the controls (not exist)
// let controlTotal=(this.myForm.get('rows') as FormArray).at(i).get('total')
// let controlAmount=(this.myForm.get('rows') as FormArray).at(i).get('amount')
let value=(val.quantity)*(val.price);
this.totals[i].total=value; //<--just update the value of the variable
// if (controlTotal.value!=value)
// controlTotal.setValue(value);
value=val.dis_checkbox?value/val.checkbox:value;
this.totals[i].amount=value; //<--idem
// if (controlAmount.value!=value)
// controlAmount.setValue(value);
});
}
}
Upvotes: 1
Reputation: 57939
Josep, when we use ReactiveForm, we usually control the changes subscribing to AbstractControl.valuesChange.
So your form don't need (cange) nor (NgModel), simply
<form class="form-horizontal" [formGroup]="myForm" (ngSubmit)="onCreateProduct()" >
<div class="card">
<div class="card-block" formArrayName="rows">
<table class="table">
...
</thead>
<tbody>
<tr *ngFor="let row of myForm.controls.rows.controls; let i = index" [formGroupName]="i">
<td>{{row.value.material_id}}</td>
<td>{{row.value.material_name}}</td>
<td><input class="col-md-6" type ="number" formControlName="quantity" ></td>
<td><input class="col-md-6" type ="number" formControlName="price" ></td>
<td><input type="checkbox" class="col-md-6" formControlName="dis_checkbox" > 20 %</td>
<td><input class="col-md-6" formControlName="amount" readonly disabled ></td>
<td><input class="col-md-6" formControlName="total" readonly disabled></td>
</tr>
</tbody>
</table>
</div>
</div>
</form>
Then we control the "changes" adding in your code, after pathValues
patchValues() {
let rows = this.myForm.get('rows') as FormArray;
this.orders.forEach(material => {
...
})
setOnChange() //<--call a function
}
setOnChange()
{
const formarray=this.myForm.get('rows') as FormArray;
for (let i=0;i<rows.length;i++)
{
formarray.at(i).valueChanges.subscribe(val=>{
//see that in val we have all the values
//val.quantity,val.price,val.dis_checkbox...
//I use an auxiliar variables to get the controls "total" and "amount"
let controlTotal=(this.myForm.get('rows') as FormArray).at(i).get('total')
let controlAmount=(this.myForm.get('rows') as FormArray).at(i).get('amount')
let value=(val.quantity)*(val.price);
if (controlTotal.value!=value) //Only when the values are not equal
controlTotal.setValue(value);
value=val.dis_checkbox?value/val.checkbox:value;
if (controlAmount.value!=value) //Only when the values are not equal
controlAmount.setValue(value);
});
}
}
When we're using valueChanges, we can subscribing to a uniq control, to one row of the formArray (mychoice) or to all the form. Ok, the code it's not complete. normally if we have "calculated field" (in this case "total" and "amount") We needn't make this fields belong to the form. Why not use an array of object (e.g.totals=[{total:0,ammount:0}{total:0,ammount:0}..] and change/display the values?
<tr *ngFor="let row of myForm.controls.rows.controls; let i = index" [formGroupName]="i">
...
<td><input class="col-md-6" type ="number" formControlName="quantity" ></td>
<td><input class="col-md-6" type ="number" formControlName="price" ></td>
<td><input type="checkbox" class="col-md-6" formControlName="dis_checkbox" > 20 %</td>
<!--see that don't belong to the form, I use the variable "totals"-->
<td><input class="col-md-6" [value]="totals[i].amount" readonly disabled ></td>
<td><input class="col-md-6" [value]="totals[i].amount" readonly disabled></td>
</tr>
Upvotes: 0