Skip to content

@if @else (or *ngIf) issue and change detection #59478

@hammad-awan

Description

@hammad-awan

Which @angular/* package(s) are the source of the bug?

Don't known / other

Is this a regression?

No

Description

I have a component that has conditional logic using an @if (or *ngIf) condition on a flag, e.g., @if (model.editable) or <ngContainer *ngIf="model.editable"...>, in its html file, which displays one set of controls for the true condition and another for false.

In ngOnChanges in the typescript file I call a service method that returns the model which has multiple properties including editable. The other properties are bound to various different control properties, e.g., <input [value]="model.wbsNumber" ...>.

app-field-dropdown and app-field-text-input are components that implement ControlValueAccessor and wrap existing HTML elements like selects or inputs and add additional functionality. The value property on app-field-text-input is just a passthrough to the value property on the underlying input control.

If the @input value to the component changes and triggers the code in ngOnChanges to retrieve a new model from the server and the model.editable property changes, e.g., from true to false or vice versa, I seem to have binding issues where control values are not being updated and reflecting the correct values, i.e., model.wbsNumber is not being set on the input control. This doesn't happen if the model.editable property does not change when ngOnChanges is triggered. The values are updated correctly in the ui.

I'm sure it has to do with dynamic control construction due to the @if, but I am at a loss as to why it does not work and how to get it so that the controls reflect the correct values in the ui.

One thing that helps the display as part of the first @if condition, i.e., model?.editable, is if I change this.ngModelGroup.reset(this.model) to setTimeout(() => this.ngModelGroup.reset(this.model), 50) for some reason. But this doesn't work for the @else condition because those controls are just one-way data-bound through the value properties. So the setTimeout call is hinting at something, but I don't know what.

@if (model?.editable) {
<ng-container ngModelGroup="wbs">
    <app-field-dropdown #wbsProgram
                        id="project-wbs-wbsProgramId"
                        name="wbsProgramId"
                        [field]="PMBField.ProjectSummaryProgram"
                        [required]="true"
                        [options]="wbsPrograms"
                        (change)="getWbsChildren(wbsProgram.name)"
                        ngModel />

   <!--Other controls-->
</ng-container>
}
@else {
<app-field-text-input id="project-wbs-wbsProgramName"
                      [field]="PMBField.ProjectSummaryProgram"
                      [readonly]="true"
                      [value]="model?.wbsProgramName" />

<!--Other controls-->
}

@ViewChild(NgModelGroup) ngModelGroup: NgModelGroup | undefined;

ngOnChanges(changes: SimpleChanges): void {
    if (changes["projectId"]?.previousValue !== this.projectId) {
        if (this.projectId) {
            this._projectWbsService.getProjectWbs({ request: this.projectId.id }).subscribe(response => {
                this.model = response;
                if (this.model.editable) {
                    // Other code...

                    this.ngModelGroup?.reset(this.model);
                   // Mostly works if I replace above with:
                   setTimeout(() => this.ngModelGroup?.reset(this.model), 50);
               }
        });
        } else {
            this.model = undefined;
            // Other code...
        }
    }
}

### Please provide a link to a minimal reproduction of the bug

_No response_

### Please provide the exception or error you saw

```true

Please provide the environment you discovered this bug in (run ng version)


Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtimeneeds reproductionThis issue needs a reproduction in order for the team to investigate further

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions