You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Native element not available in AfterViewInit on android #848
The native element is not available inside AfterViewInit on Android but is available on ios.
For example:
import {AfterViewInit, Component} from "@angular/core";
import {Page} from "tns-core-modules/ui/page";
import {Label} from "tns-core-modules/ui/label";
@Component({
selector: "lifecycle",
moduleId: module.id,
template: `
<GridLayout columns="auto" rows="auto">
<Label id="label1" col="0" row="0"></Label>
</GridLayout>
`
})
export class Lifecycle implements AfterViewInit {
private _page: Page;
constructor(page: Page) {
this._page = page;
}
public ngAfterViewInit(): void {
let label: Label = this._page.getViewById<Label>("label1");
// label.android will be undefined on android
console.log("ngAfterViewInit: " + label.android + label.ios);
}
}
label.android will be undefined when running on android. label.ios is defined when running on ios.
I would expect EVERYTHING to be loaded and ready when ngAfterViewInit is fired. Because the view is supposed to be ready at that point.
I know you can subscribe to loaded on the element to know when it is finished loading, but i would expect AfterViewInit to be called after the entire "dom" is loaded and ready.
@prolink007 I can confirm that this inconsistency i is observed on Android.
It is a timing issue and as a workaround, you can wrap your reference in 1 millisecond time out
I have the same issue...But in my situation I need to do it with 500ms because I have a lot of info to load...and I am pretty sure that in slower and older device it probably won't be enough...
There is a way to had a listener to when element is shown on page?
A similar issue can be observed when nativeElement.android is accessed from a directive as shown below. The @Input setter seems to be called before the android native component is initialized. Using the workaround given by @NickIliev works, but as @shabib3 states, this might not work on all devices.
@Directive({
selector: '[appShadow]'
})
export class ShadowDirective {
constructor(private element: ElementRef) { }
@Input() set appShadow(value: string) {
// Following prints "ANDROID NOT INITIALIZED YET"
this.setShadow(this.element.nativeElement, +value);
// Following works and prints "ANDROID INITIALIZED"
setTimeout(
() => this.setShadow(this.element.nativeElement, +value)
, 10
);
}
private setShadow(view: any, elevation: number) {
if (view.android) {
console.log("ANDROID INITIALIZED");
let backgroundColor = view.backgroundColor.android;
let nativeView = view.android;
nativeView.setBackgroundColor(backgroundColor);
nativeView.setElevation(elevation);
} else {
console.log("ANDROID NOT INITIALIZED YET");
}
}
}
Is there any update on this issue? I want to get the native view as it is loaded, but binding the loaded event breaks listviews (#1221) and using ngAfterViewInit just doesn't work on Android.
This also means plugins that bind the loaded event (like nativescript-ng-shadow, nativescript-ngx-shadow and nativescript-ng-ripple) just flat out break your app in some situations.
So i either have to add timeouts that might even break the code if a view is quickly created/destroyed, or add *ngIf everywhere potentially breaking component recycling.
@cjohn001 instead of using the top abstraction lifecycle events (meaning Angular and AfterViewInit) you should probably use the native elements loaded event - this way the native element will be 100% accessible. The thing is that Angular is the top abstraction and at the time when the top abstraction events are executed that doesn't mean that you will have the bottom ones finished as well - consider this a limitation.
Hello Nicklliev,
thanks for the feedback. I tried the loaded variant es well. Unfortunately it does not work for my use case. The loaded event is triggered separately for each component. In my use case I needed to compute a layout relative to other elements. If I am in a loaded callback event from one component I cannnot make asumptions that other components I need for my layout computation where already loaded. Hence hooking up to loaded events is not a solution. I worked around the issue now by hardcoding the layout. However, I think a livecycle hook for nativescript is here missing which is triggered once all components on the page were loaded. I found this article https://medium.com/developer-rants/the-curious-case-of-angular-lifecycle-hooks-in-nativescript-2be0386cb2fa
which describes a workaround. However, for a good integration with Angular I think it would make much more sense to support the toplevel api.
Activity
NickIliev commentedon Jun 16, 2017
@prolink007 I can confirm that this inconsistency i is observed on Android.
It is a timing issue and as a workaround, you can wrap your reference in 1 millisecond time out
e.g.
Test project demonstrating the issue here (remove the setTimeout to reproduce the problem in Android)
wandri commentedon Jul 28, 2017
I confirm the problem too.
I had to set a timeout of 50ms to resolve it, 1ms wasn't enough.
bzaruk commentedon Jan 10, 2018
Hi - @tsonevn @NickIliev :)
I have the same issue...But in my situation I need to do it with 500ms because I have a lot of info to load...and I am pretty sure that in slower and older device it probably won't be enough...
There is a way to had a listener to when element is shown on page?
Thanks guys :)
syntaxfoundry commentedon Jan 23, 2018
A similar issue can be observed when nativeElement.android is accessed from a directive as shown below. The
@Inputsetter seems to be called before the android native component is initialized. Using the workaround given by @NickIliev works, but as @shabib3 states, this might not work on all devices.edusperoni commentedon Sep 12, 2018
Is there any update on this issue? I want to get the native view as it is loaded, but binding the loaded event breaks listviews (#1221) and using ngAfterViewInit just doesn't work on Android.
This also means plugins that bind the loaded event (like nativescript-ng-shadow, nativescript-ngx-shadow and nativescript-ng-ripple) just flat out break your app in some situations.
So i either have to add timeouts that might even break the code if a view is quickly created/destroyed, or add *ngIf everywhere potentially breaking component recycling.
NathanWalker commentedon Jan 3, 2019
This seems to work under some conditions (perhaps not all):
NathanWalker commentedon Jan 3, 2019
Note the above strategy only works for UI components that have a
loadedevent. CuriouslySliderhttps://github.com/NativeScript/NativeScript/blob/master/tns-core-modules/ui/slider/slider.android.ts does not (for ios or android), not sure if intentional or just a small mistaken omission?@EmilStoychev @vakrilov
cjohn001 commentedon Apr 17, 2020
are there any updates to the topic? As of today the bug seems still to exist
NickIliev commentedon Apr 24, 2020
@cjohn001 instead of using the top abstraction lifecycle events (meaning Angular and
AfterViewInit) you should probably use the native elements loaded event - this way the native element will be 100% accessible. The thing is that Angular is the top abstraction and at the time when the top abstraction events are executed that doesn't mean that you will have the bottom ones finished as well - consider this a limitation.cjohn001 commentedon Apr 24, 2020
Hello Nicklliev,
thanks for the feedback. I tried the loaded variant es well. Unfortunately it does not work for my use case. The loaded event is triggered separately for each component. In my use case I needed to compute a layout relative to other elements. If I am in a loaded callback event from one component I cannnot make asumptions that other components I need for my layout computation where already loaded. Hence hooking up to loaded events is not a solution. I worked around the issue now by hardcoding the layout. However, I think a livecycle hook for nativescript is here missing which is triggered once all components on the page were loaded. I found this article
https://medium.com/developer-rants/the-curious-case-of-angular-lifecycle-hooks-in-nativescript-2be0386cb2fa
which describes a workaround. However, for a good integration with Angular I think it would make much more sense to support the toplevel api.
asciidiego commentedon Sep 4, 2020
I am in the same situation as @cjohn001
asciidiego commentedon Sep 4, 2020
I could use some guideline and I would be happy to try and fix this @NathanWalker @NickIliev
icefee commentedon Jan 23, 2024
Same problem, any update?