UI does not update on property change


#1

I’m using the latest v2 beta.

Inside my class I have a property isOffline to keep track of the connection status.

I initialize this property and inside my component’s constructor I have 2 event listeners for ‘online’ and ‘offline’. Both listeners update the this.isOffline property.

Inside my page’s HTML I display the property via [(ngModel)].

When the page is loaded the initial connection status is displayed. The even listeners should work properly, as the updated status can be displayed with console.log inside the listeners. However, my UI does not update the status.

I have also tried to put the isOffline inside an object (so this.connection.isOffline instead of this.isOffline), but when I try to update the isOffline property I get an error stating I cannot change read only properties.

What should I do to get this working as expected?

Thanks in advance.


Ionic 2 button and [disabled] lag
#2

When you update component values inside functions form other libraries, Angular 2 doesn’t trigger the change, so you may need to correctly use arrow functions to avoid that, or use NgZone as last resource:

import { Component, NgZone } from "@angular/core";
...

export class MyComponentPage {
  constructor(
    private zone: NgZone,
    ...

  ionViewLoaded() {
    ...
    google.maps.event.addListener(this.map, 'dragend', () => {
      this.zone.run(() => {
        this.mapMoved = true;
      });
    });

In this example I needed to use the zone because it wasn’t updated properly on the Google Maps event.


Angular 2 Interpolation {{var}} not updating unless forced
#3

It seems that even with NgZone it still does not work.

window.addEventListener('offline', function(e) {
  console.log('switched to offline mode');
  //this.connection = {isOffline: true};
  _ngZone.run(() => {
    this.isOffline = true;
  });
}, false);


#4

this is not the Page component inside that annonymous function, you better use arrow functions to avoid those issues:

constructor(
  private nav: NavController,
  private data: Data
) {
  window.addEventListener('online', (e) => {
    console.log('switched to online mode');
    this.isOffline = false;
  }, false);

#5

Thanks for you assistance, but still no difference :frowning:

(How do I paste “formatted” code from my IDE?)


#6

No change? pretty weird…
maybe you need to execute that on Platform ready:

constructor(
  platform: Platform,
  private nav: NavController,
  private data: Data
) {
  platform.ready().then(() => {
    window.addEventListener('online', (e) => {
      console.log('switched to online mode');
      this.isOffline = false;
    }, false);
  }
}

(I use markdown for formatting: https://guides.github.com/features/mastering-markdown/)


#7

Currently I have the following:

import {Component} from '@angular/core';
import {NavController, Platform} from 'ionic-angular';
import {Data} from "../../providers/data/data";
import {SurveyModel} from "../../providers/survey-model/survey-model";
import {plainToConstructor} from "constructor-utils/index";
import {SurveyPage} from "../survey/survey";

@Component({
  templateUrl: 'build/pages/home/home.html',
})

export class HomePage {
  surveys: SurveyModel[];
  isOffline = false;

  constructor(private platform: Platform, private nav: NavController, private data: Data) {
    platform.ready().then(() => {
      window.addEventListener('online', (e) => {
        console.log('switched to online mode');
        this.isOffline = false;
      }, false);

    window.addEventListener('offline', (e) => {
      console.log('switched to offline mode');
      this.isOffline = true;
    }, false);
  });

and:

    <ion-buttons end>
      <button (click)="getSurveys()" [disabled]="isOffline"><ion-icon name="refresh"></ion-icon></button>
    </ion-buttons>

  <ion-card>
    <ion-card-header>
      OFFLINE: {{isOffline}}
    </ion-card-header>
  </ion-card>

#8

It seems it does not work due to the fact that isOffline is changed inside an event listener.

I have tried to achieve the same with Angular 1.

  document.addEventListener('online', function(e) {
    console.log('switched to online mode');
    $scope.$apply(function() {
      $scope.status = 'ONLINE';
    });
    me.network = 'ONLINE';
  }, false);

With the $scope.$apply in place I can get the current value of the property.

What is this in Angular 2?

If I am correct EventEmitters are only for communication between multiple components. Yesterday I have tried to put it inside a run() with NgZone, but it did not seem to work.


#9

I don’t know why zone.run didn’t work for you, it always does for me :frowning2:


#10

It works for me,too. thank you!


#11

Finally, does you find the trick with typescript Angular 2? I’m facing exactly the same behaviour.
Thanks.


#12

I was having a similar issue with address variable not getting updated every time on changing google maps marker. But, with NgZone, that issue is resolved once and for all.

Thanks a lot, @matheo!


#13

A bit late but another solution i found is using -> window.dispatchEvent(new Event(‘resize’));

Triggering the resize event will always force update the UI (kinda like $scope.$apply in angular 1)


#14

NgZone works fine for me. Thanks. :slight_smile:


#15

this code works fine. Thanks.