27

I have created a form in Angular 2 with which users can edit a SearchProfile which they can select from a list. Initially everything works fine but when i select a different item from the list of SearchProfiles I receive the following exception: There is no FormControl instance attached to form control element with name: controlName. The whole thing consists of 3 elements: 2 components SelectProfileComponent, SearchProfileComponent and a service ProfileService. ProfileService contains the ActiveProfile which is the selected SearchProfile for editing. ProfileService looks like this:

@Injectable()
export class ProfileService {
    private activeProfileSource = new ReplaySubject<ISearchProfile>();
    activeProfile$ = this.activeProfileSource.asObservable();

    constructor(private http: Http) {
        this.selectProfile();
    }

    public getSearchProfile(profileId: number = null): Observable<ISearchProfile> {
        let url = `<url>?profileid=${profileId}`;
        this.http.get(url).map((result) => {
            return <ISearchProfile>.result.json();
        });
    }

    public selectProfile(profileId: number = null) {
        this.getSearchProfile(profileId).subscribe((p) => {
            this.activeProfileSource.next(p);
        });
    }
}

SelectProfileComponent contains a list with profile which triggers a change-event when a SearchProfile is selected.

<select (change)="setActiveProfile($event.target.value)">
    <option *ngFor="let profile of profiles" [value]="profile.Id" [innerHtml]="profile.name"></option>
</select>

export class ProfileSelectionComponent implements OnInit {
    private profiles: ISearchProfile[] = null;

    constructor(private profileService: ProfileService) {}

    //get profiles logic

    public setActiveProfile(profileId: number): void {
        this.profileService.selectProfile(profileId);
    }
}

The SearchProfileComponent has a Subscription to the activeProfile and should show the properties of the activeProfile so the user can edit them. SearchProfileComponent looks like this:

<form [formGroup]="profileForm" *ngIf="!isLoading">
    <input type="text" name="name" formControlName="name" [(ngModel)]="searchProfile.name" />
</form>

export class SearchProfileComponent implements OnInit {
    private isLoading: boolean = true;
    private activeProfileSubscription: Subscription;
    private searchProfile: ISearchProfile = null;
    public profileForm: FormGroup;

    constructor(private profilService: ProfileService
        private formBuilder: FormBuilder) { }

    ngOnInit() {
        this.activeProfileSubscription = this.profileService.activeProfile$.subscribe((profile: ISearchProfile) => {
            this.searchProfile = profile;
            this.createForm();
            this.isLoading = false;
        });
    }
    private createForm() {
        this.profileForm = this.formBuilder.group({
            ["name"]: [this.searchProfile.name, null]
        });
    }
}

5 Answers 5

97

I solved it in this way:

Before:

formControlName="description"

After:

[formControl]="form.controls['description']"
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @Kuzenko Lubko this is working! I was wondering, this looks like a bug, can you tell why formControlName isn't working in this case?
@benshabatnoam maybe because form will be created after async request. If you are using formControlName you should have form created before view render.
You're kind of right, I'm building the formGroup dynamically after the view was rendered, but I have an *ngIf on my form. I guess this is the problem. Thanks!
I was only crashing on my up/down arrows in my number control, this cured it. So it was something happening with the view rendering.
I create a custom control within a formArray, thing was okie after form rendered but later when I trigger change to load new form value it's show the issue. your solution do fix it while the copilot don't see this solution :(
6

I solved this issue by initializing form once in the component constructor i.e.

constructor() {
        this.form = this.initForm();
}

OR

ngOnInit() {
        this.form = this.initForm();
}

and remove the re-initialization of the form in the component anywhere in the component without constructor i.e.

this.form = this.initForm();

1 Comment

Thanks, My issue was due to else condition in edit form, where I was checking for data to fill the form or if data is not present then re-initializing the form. @Saad
4

The creation of your FormGroup is a little bit wrong. You dont need to wrap the control name in brackets and double quotes. Read more about reactive forms on official angular docs.

Change your creation of FormGroup from this:

this.profileForm = this.formBuilder.group({
            ["name"]: [this.searchProfile.name, null]
});

to this:

this.profileForm = this.formBuilder.group({
            name: [this.searchProfile.name]
});

And you should make some changes in your html. Hint: If you are using reactive forms, you don't need [(ngModel)] on inputs, remove that. Here is right html for you input:

<form [formGroup]="profileForm" *ngIf="!isLoading">
    <input type="text" name="name" formControlName="name" />
</form>

Comments

0

We experienced a similar issue using angular 18. We were removing a control perfoming some logic and adding the control again. The error was occuring interminantly.

We solved it by detecting changes before adding the control. i.e adding the line this.cdr.detectChanges()

this.formGroup.removeControl(field, {
  emitEvent: false,
});
 ...
 //some logic here
 ...
this.cdr.detectChanges()
this.formGroup.addControl(field, {
  emitEvent: false,
});

Comments

-2

I found that using the [formControl]="$form.something" method worked well. Clunky, but that's Angular for you.

Comments

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.