ljgw
ljgw

Reputation: 2771

access local variable within *ngIf

I have a primeng (angular 2) dialog with a dropdown. I want to set focus to the dropdown when the dialog shows. The problem appears to be that my div is rendered conditionally.

My code:

<p-dialog (onShow)="fe.applyFocus()">
  <div *ngIf="selectedItem">
    <button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
    <p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason" ></p-dropdown>
  </div>
</p-dialog>

In this code the button works fine, but the onShow() (outside the *ngIf div) tells me fe is undefined.

How can I access the local variable inside the *ngIf?

Upvotes: 2

Views: 4201

Answers (2)

Vincent
Vincent

Reputation: 1304

You can separate the use of template on NgIf level:

<ng-container *ngIf="selectedItem; else elseTemplate">
    <p-dialog (onShow)="fe.applyFocus()">
        <div>
            <button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
            <p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason"></p-dropdown>
        </div>
    </p-dialog>
</ng-container>
<ng-template #elseTemplate>
    <p-dialog>
    </p-dialog>
</ng-template>

Upvotes: 2

NightCabbage
NightCabbage

Reputation: 489

Yes, this is a real pain. Unfortunately, due to the way *ngIf works, it completely encapsulates everything inside (including the tag it's on).

This means anything declared on, or inside, the tag with the ngIf will not be "visible" outside of the ngIf.

And you can't even simply put a @ViewChild in the ts, because on first run it might not be present... So there are 2 known solutions to this problem...

a) You can use @ViewChildren. This will give you a QueryList that you can subscribe to, which will fire off every time the tempalte variable changes (ie. the ngIf turns on or off).

(html template)

<div>{{thing.stuff}}</div>
<my-component #thing></my-component>

(ts code)

@ViewChildren('thing') thingQ: QueryList<MyComponent>;
thing: MyComponent;

ngAfterViewInit() {
    this.doChanges();
    this.thingQ.changes.subscribe(() => { this.doChanges(); });
}

doChanges() {
    this.thing = this.thingQ.first;
}

b) You can use @ViewChild with a setter. This will fire the setter every time the ngIf changes.

(html template)

<div>{{thing.stuff}}</div>
<my-component #thing></my-component>

(ts code)

@ViewChild('thing') set SetThing(e: MyComponent) {
    this.thing = e;
}
thing: MyComponent;

Both of these examples should give you a "thing" variable you can now use in your template, outside of the ngIf. You may want to give the ts variable a different name to the template (#) variable, in case there are clashes.

Upvotes: 3

Related Questions