nativescript-angular: *ngIf not working in Angular application for hide/show layout after upgrade to NS3

From @memphisvl on June 29, 2017 19:56

It used to work on {N} 2.5 and now it seems that the only way to show/hide some elements is using visibility option.

Before

<StackLayout class="page">
  <Label *ngIf="isPresent" text="{{showText}}"></Label>        
</StackLayout>

Now (Workaround)

<StackLayout class="page">
  <Label visibility="{{isPresent ? 'visible' : 'collapse'}}" text="{{showText}}"></Label>        
</StackLayout>

Is this expected and from now on I will have to use visibility for UI logic?

Versions

    "@angular/animations": "~4.1.0",
    "@angular/common": "~4.1.0",
    "@angular/compiler": "~4.1.0",
    "@angular/core": "~4.1.0",
    "@angular/forms": "~4.1.0",
    "@angular/http": "~4.1.0",
    "@angular/platform-browser": "~4.1.0",
    "@angular/platform-browser-dynamic": "~4.1.0",
    "@angular/router": "~4.1.0",
    "moment": "^2.18.1",
    "nativescript-angular": "^3.1.0",
    "nativescript-angular-snapshot": "1.5.2-5.5.372.32",
    "nativescript-carousel-view": "^2.9.0",
    "nativescript-google-maps-sdk": "^2.3.0",
    "nativescript-loading-indicator": "^2.3.2",
    "nativescript-local-notifications": "^1.2.1",
    "nativescript-platform-css": "^1.4.0",
    "nativescript-plugin-firebase": "^4.0.2",
    "nativescript-pulltorefresh": "^2.0.1",
    "nativescript-push-notifications": "^0.1.2",
    "nativescript-sidedrawer": "^1.0.6",
    "nativescript-theme-core": "~1.0.2",
    "reflect-metadata": "~0.1.8",
    "rxjs": "~5.3.0",
    "tns-core-modules": "^3.1.0",
    "zone.js": "~0.8.2"

TNS Paltform 3.1.0

Copied from original issue: NativeScript/NativeScript#4479

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 40 (4 by maintainers)

Commits related to this issue

Most upvoted comments

This issue was initially not about out-of-order rendering. It is about elements, where *ngIf is changed dynamically after the first render of the page, not getting rendered at all. This problem does and still only occur on iOS.

Code examples on Version 3.2.0:

<GridLayout rows="*">
    <RadListView row="0" [items]="accounts" pullToRefresh="true" (pullToRefreshInitiated)="refresh($event)" separatorColor="transparent">
        <ng-template let-item="item" let-i="index">
            <StackLayout>
                <GridLayout (tap)="selectAccount(item)"
                    <Label *ngIf="item.selected" col="0" row="0" class="fa text-center select-indicator" text="&#xf111;"></Label>
                    <Label *ngIf="!item.selected" col="1" row="0" class="fa text-center select-indicator" text="&#xf10c;"></Label>
                </GridLayout>
            </StackLayout>
        </ng-template>
    </RadListView>
</GridLayout>

selectAccount(item) toggles the selected boolean attribute. When changed, both directives arent rendered again. When toggling back they arent also not rendered again. Replacing it with [visibility]:

<GridLayout rows="*">
    <RadListView row="0" [items]="accounts" pullToRefresh="true" (pullToRefreshInitiated)="refresh($event)" separatorColor="transparent">
        <ng-template let-item="item" let-i="index">
            <StackLayout>
                <GridLayout (tap)="selectAccount(item)"
                    <Label [visibility]="item.selected ? 'visible' : 'collapse'" col="0" row="0" class="fa text-center select-indicator" text="&#xf111;"></Label>
                    <Label [visibility]="!item.selected ? 'visible' : 'collapse'" col="1" row="0" class="fa text-center select-indicator" text="&#xf10c;"></Label>
                </GridLayout>
            </StackLayout>
        </ng-template>
    </RadListView>
</GridLayout>

Leads to not rendering when toggling for the first time, but toggling back renders the elements again!

All in all this issue should not have been closed, because the problem persists, elements with *ngIf are not rerendered when their values are changed dynamically. [visibility] as workaround is not working fully either!

I’m having some similiar issues with *ngIf, sometimes the elements are rendered out of order, sometimes aren’t even rendered. Seems to be related with the last version (3.1.0).

For me, this is still an issue. Can’t really use *ngIf properly in NS+Angular

also having trouble with *ngIf, its rendering my element outside of parent element

I have found visibility to be more stable generally. Perhaps a directive should be added here out of the box to make visibility more like ngIf in that sense - maybe even call it ngShow which would use the visibility attribute under the hood?

Any updates on this issue?

@netowp @yassern @svzi @Raf197 @behrangs the issue seems to be related to this one. The fix for the linked issue is already in master branch and it will be included in the next official release. meanwhile, you can test the fix on your side with

npm i tns-core-modules@next --save

Keep in mind that the next version (master branch) is not meant for production but just for testing purposes.

After I did the upgrade and had to redo my Angular layout logic I’ve found these issues with ngIf:

  1. ngIf works as expected if value is available at time of rendering
  2. ngIf break any layout (out of order rendering of ngIf elements) if value was delayed (eg: async call)
  3. visibility seem to be good alternative

Overall it was unpleasant to find out that what used to work with {N}2.5 is not working in {N}3.x. At least I know, that am not alone) For anyone wondering about workarounds use [visibility] for Angular html layouts.

A possible workaround for out-of-order rendering could be separating the elements in different <StackLayout>s. My case was this:

<StackLayout>
  <GridLayout id="g1" *ngFor>
  </GridLayout>
  <GridLayout id="g2">
  </GridLayout>
</StackLayout>

Because of the ngFor “g2” was rendered before “g1”.

This fixed it:

<StackLayout>
  <StackLayout>
    <GridLayout id="g1" *ngFor>
    </GridLayout>
  </StackLayout>
  <StackLayout>
    <GridLayout id="g2">
    </GridLayout>
  </StackLayout>
</StackLayout>

Me to, not only with *ngIf but *ngFor too

Still in NS 4+, I found that using this.ngZone.run(() => { this.foo = false; }) works well in re-rendering the view content in case it doesn’t work

hey @NickIliev that was really helpful im really struggling with this issue for days. after updating tns-core-modules ng-if working perfectly in ios. Thanks a lot for help. npm i tns-core-modules@next --save

Same issue here. I hope they re-open this issue.

@EddyVerbruggen Your workaround resolved my issue with multiple *ngIf items better than the visibility workaround. Thanks!