Reputation: 799
Hello fellow programmer,
after i make an API call i convert the JSON to an array.
This array will display in an Component inside an HTML table, after you pressed the "edit" button the Component will change his content from an HTML table to an HTML form, where you can edit the Data, which Data you can send back to the API server.
component.html
<div *ngFor="let rule of generateArray(gutschein['ruleset_list']['rulesets']); let i = index" >
<div class="form-group">
<label>Rule: </label> <input type="text" class="form-control" id="rule{{i}}"
requierd
[(ngModel)]="rule['condition']['expression']" name="rule" #rule="ngModel">
<div [hidden]="rule.valid || rule.pristine" class="alert alert-danger">
Rule is not valid
</div>
</div>
<div class="form-group">
<label>Discount: </label> <input type="text" class="form-control" id="discount{{i}}"
requierd
[(ngModel)]="rule['results']['results'][i+1]['calculation']" name="discount" #discount="ngModel">
<div [hidden]="discount.valid || discount.pristine" class="alert alert-danger">
Discount is not valid
</div>
</div>
component.ts
generateArray(obj) {
return Object.keys(obj).map((key) => { return obj[key] });
}
it seems like the ngModel
cant reache my this.rule['condition']['expression']
Data.
If i changed it to this.rule['condition']
it works perfectly.
Any Idea how I can fixed this problem? I would be thankfull for an explanation not only the fixed code.
JSON
{
"id": "1",
"code": "A1234",
"valid": null,
"ruleset_list": {
"rulesets": {
"1": {
"id": "1",
"voucher_id": "1",
"condition": {
"expression": "shop.totalamount > `15` && current_datetime < `1490021400`"
},
"results": {
"results": {
"1": {
"id": "1",
"value_path": "shop.totalamount",
"calculation": "#VALUE * 0.9",
"new_value": null
}
}
}
},
"2": {
"id": "2",
"voucher_id": "1",
"condition": {
"expression": "shop.totalamount > `20` && current_datetime < `1490021400`"
},
"results": {
"results": {
"2": {
"id": "2",
"value_path": "shop.totalamount",
"calculation": "#VALUE * 0.8",
"new_value": null
}
}
}
}
}
}
}
Upvotes: 1
Views: 2114
Reputation: 73367
Your root cause is #rule="ngModel"
and #discount="ngModel"
. You are already using two-way binding, so do not declare a template reference as ngModel. The template reference value and the two way binding do not go together. As per said here:
Template input and reference variable names have their own namespaces. The
hero
inlet hero
is never the same variable as thehero
declared as#hero
.
So I guess you could basically say that there two variables "fight each other" and clash.
Furthermore, you can also use dot notation in your ngModels, so the following are equal:
rule['condition']['expression']
and
rule.condition.expression
I won't go into that any closer, since here are great answers: Access / process (nested) objects, arrays or JSON. But you can of course use bracket notation if you like :)
EDIT:
Missed the fact, that each name attribute needs to be unique so that the form fields are evaluated as different form fields, and not one and the same. So you can use the index to do that:
name="rule{{i}}"
and name="discount{{i}}"
Finally, a plunker to play with:
PS. I would perhaps actually suggest you use reactive forms here now, that would be easier to handle, since by removing the template reference you will have trouble with the validation. With reactive forms, you can skip the ngModels altogether and set the default values to the form control and also handle the validation. Here more info about dynamic forms and nested dynamic forms, as that is what you would need.
Here's a recent question and answer with values coming from http-request, meaning just like yours you need to set empty form controls first and when you want to edit form use setvalue
or patchvalue
to set the pre values to your form. Depending on your use case, maybe you won't need to use patchValue at all. BUT in case you need.
Upvotes: 3