I’ve got a page that binds to a class variable for content. But I’m noticing the page sometimes does not update when the variable changes.
Can anyone shed some light on ionic 2’s change detection strategy?
I’ve got a page that binds to a class variable for content. But I’m noticing the page sometimes does not update when the variable changes.
Can anyone shed some light on ionic 2’s change detection strategy?
Also, is there a recommended way to use @Input() annotations on a @Page? Or are they irrelevent?
One thing I’ve run into with Angular2 in general is that it inserts some voodoo into Promises that you create in your code that makes them magically work with change detection. Promises that come from external sources don’t get this treatment, and can end up not being reflected properly. A workaround that has worked for me is to wrap such things inside Promise.resolve()
in order to have them be enchanted.
Thanks for the suggestion. I hesitate to do this because I’m using observables exclusively in my app, and wrapping with a promise feels like a hack.
I’m sure I just don’t understand the Change Detection Strategy of Angular 2 as well as I should.
Im having trouble with changedetection in the Ionic framework as well - I can get it to work fine in the browser, but when it comes to the emulator or the actual device - the UI won’t update in real time. I’ve noticed its only when I click a button to change UI states that the data updates…
Did you ever find a solution or explaination? I suddenly experience this as well, however only in Android 4.4 device (Works in iOS device and desktop safari + chrome)
I am having the same issue. To solve, I end up doing a ref.detectChanges() in the @Component which feels entirely wrong.
Specifics:
angular 2.0.0-rc.4
ionic-angular 2.0.0-beta.10
Having issue on ios device when subscribing to an Observable.
Interestingly, I call next() on the Observable in 2 cases:
My issues ser caused by a Cordova plugin that provides its own promise polyfill causing change detection to break.
Are you using Cordova-plugin-inapppurchase by any chance?
No - I am not using inapppurchase. Pretty strange behavior. I am still stumped
Are you using ionic native with the plugin? If not, you should give it a shot
I am using ionic-native, yes. Perhaps I should try bypassing that??
I’ve run into this exact same issue, using a custom plugin.
The data / state is definitely updated, any console.logs are logged, however the UI does not change. In some cases running applicationRef.tick()
within the component does help, but in other situations it doesn’t at all.
I’ve found that wrapping applicationRef.tick()
in a long setTimeout works e.g. 1s, so does interacting with the UI e.g. launching the keyboard by pressing an input.
Has anyone found a solution for this? Works perfectly fine in the browser.
Update
Attempted solutions that didn’t work:
Promise.resolve(true)
in the finally block of an observablesetTimeout(doStuff, 0)
setTimeout( () => {applicationRef.tick()}, 0}
after updated the stateObject.assign
like in redux to create an new object, to facilitate change detectionIt would seem its a race condition that develops when calling a cordova plugin. Any help would be greatly appreciated.
Just an update if it helps anyone in the future.
TLDR;
Wrap plugin function in a promise to make Angular2 know about external callbacks.
Full description
The problem would only surface on iOS, and originally this is how I was invoking the plugin function:
Observable.bindCallback(cordova.plugins.myPlugin.doSomething)
although this works on the browser and Android, for some reason it prevents rerendering of the UI by Angular2. This is probably due to the Observable not using the patched Promise i.e. zoneAwarePromise.
The way around this was to do the following:
// Wrap the callback function in a Promise
function doSomethingAsPromise(...args) {
return new Promise( (resolve, reject) => {
cordova.plugins.myPlugin.doSomething(resolve, reject, ...args);
})
}
// Now make an Observable out of the Promise
Observable.fromPromise(doSomethingAsPromise())
This is in essence what ionic-native does from my sniffing their source on github. I hope this helps someone if you’re struggling with the same problem!
I have fixed by using ChangeDetectorRef
from angular core library; following example my help:
import { ChangeDetectorRef } from "@angular/core";
class MyClass {
public myVal: any;
constructor(private changeDetectorRef: ChangeDetectorRef) {
this.myVal = "initial value";
this.updates();
}
private update() {
setTimeout({
this.myVal = "New Value";
this.changeDetectorRef.detectChanges();
}, 3000);
}
}
Note: above example works well for Ionic 3.2.0 and Angular 4.1.0
This solution ended my head scratching frustration. Many thanks!! Mine needed a quicker response so I set the timeout value very small but works like a charm now.
Manual triggering of change detection is only needed in relatively rare circumstances, and setTimeout()
is in my experience a recipe for disaster, because it is a petri dish for unreproducible results. I would strongly urge anybody considering the advice referenced in the previous post to seek more robust alternatives.