1

I'm new to Angular 2, trying to implement ngFor list of objects with editable inputs, be able to add a new object and save the data. The data is:

business: { email: "[email protected]", 
locations: [
{ country: "US", city: "city 1", address_line_1: "address 1"},
{ country: "Australia", city: "city 1", address_line_1: "address 2"}
]}

In the component:

ngOnInit() {
this.businessForm = new FormGroup({
        email: new FormControl(null, [Validators.required]), 
        locationCountry: new FormControl(null)
});
addLocation() {
    this.isFormChanged = true;
    let newLocation = {};
    this.business.locations.push(newLocation);
}

removeLocation(item){
    if (null !== item) {
        this.isFormChanged = true;
        this.business.locations.splice(item, 1);
    }
}

Html:

<div class="form-group">
            <label for="locations">Locations</label>
            <div class="row">
                <div class="col-md-3">
                <button
                        id="locations"
                        class="btn btn-secondary"
                        type="button"
                        (click)="addLocation()">Add new address</button>

                </div>
            </div>

            <!--LOCATIONS LIST-->
            <ul class="locations-tag">
                <li *ngFor="let location of business?.locations; let index=index;">
                    <a class="btn btn-danger categories-tag-btn" (click)="removeLocation(index)">X</a>
                    <span>{{business?.locations[index].country}}</span>
                    <input
                            id="locations-{{index}}"
                            [(ngModel)]="business?.locations[index].country"
                            formControlName="locationCountry"
                            name="locations-{{index}}"
                            type="text" 
                            class="form-control"
                            placeholder="Country" 
                            aria-label="Country"
                            value={{business?.locations[index].country}}>
                    ...

                </li>
            </ul>

    </div>

When it runs I get an error

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'US'. Current value: 'Australia'.

Looks like it changes all the inputs values to the last one. I tried to implement the same idea through FormBuilder, but it didn't work out either.

3
  • Can you try to remove the ? after let location of business?.locations Commented Sep 12, 2017 at 16:59
  • I don't think reactive forms are good for two-way databinding, I think you'd want to try that with a template-driven form. Commented Sep 12, 2017 at 17:12
  • I just tried to remove ? - the same error plus one more. Commented Sep 12, 2017 at 17:12

2 Answers 2

4

I have created a Plunker. I remove formControlName because it's not FormsModule, it's ReactiveFormsModule - that is different.

For more information between FormsModule(NgModel) vs ReactiveFormsModule read documentation. Also, it's better to delete value because you are using [(ngModel)] that is making two-way data-binding to the value.

  <input
                        id="locations-{{index}}"
                        [(ngModel)]="business?.locations[index].country"
                        name="locations-{{index}}"
                        type="text" 
                        class="form-control"
                        placeholder="Country" 
                        aria-label="Country"
                        >
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, @alexKhymenko! I will probably go on with ReactiveForms. The problem is there were more elements that worked with FormsModule and I hoped to solve it the same way.
@InnaZis Just remember to not use them both at the same time. Happy coding :-)
0

(Answering since I am not yet allowed to comment). In addition to @alexKhymenko's answer, if you want to stick with ReactiveForms(Module), you will have to add the parent formGroup, businessForm you created in your component, also to the template. Not sure if this will fix your issue though, but try to add this attribute to the top <div class="form-group"> like this <div class="form-group" [formGroup]="businessForm"> of the template. If you are happy with non-reactive forms, then @alexKhymenko's answer might be sufficient.

1 Comment

Thanks, tried with this attribute, didn't help. I'll probably rewrite according to @alexKhymenko's suggestion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.