View doesn't update


#1

Hi, I have two different scenarios receiving data from service and one way data will not be rendered before I click on button or open menu. I don’t understand the difference, can somebody please explain.

This is my service where I hold and change two example values and also push event to detect change in page component.

import {Injectable} from 'angular2/core';
import {Events} from 'ionic-angular';
import {Http} from 'angular2/http';

@Injectable()
export class NFCService {
    static get parameters() {
        return [[Http], [Events]];
    }

    constructor(http, events) {
        this.http = http;
        this.events = events;

        this._nfcData = {};
        this.random = {}
    }

    parseNfcData(nfcEvent) {
        let tag = nfcEvent.tag;
        let ndefMessage = tag.ndefMessage;
        let parsedNfcData = nfc.bytesToString(ndefMessage[0].payload);
        this._nfcData = parsedNfcData;
        this.events.publish('nfc:gotNfcData');
    }

    renderRandom() {
        this.random = "renderRandom";
        this.events.publish('random:gotRandomData');
    }
}

This is my Page where I use event listeners for value changes. I also call this.renderRandomData() function in this component to show that this way data will be rendered if it got event back from service (random:gotRandomData). But if I read NFC tag and call service with the data from app.js I do receive data in console log on nfc:gotNfcData, but it renders after clicking on some button.

import {Page, NavController, NavParams, Events} from 'ionic-angular';
import {NFCService} from '../../providers/nfc-service';


@Page({
    templateUrl: 'build/pages/hello-ionic/hello-ionic.html'
})
export class HelloIonicPage {
    static get parameters() {
        return [[NavController], [NavParams], [Events], [NFCService]];
    }

    constructor(nav, navParams, events, nfcService) {
        this.nav = nav;
        this.events = events;

        this.nfcService = nfcService;
        this.data = {};

        this.random = {};

        this.listenToNFCEvents();
        setTimeout(() => {
            this.renderRandomData();
        }, 2000);

    }

    listenToNFCEvents() {
        this.events.subscribe('nfc:gotNfcData', () => {
            console.log("Got nfc data");
            this.data = this.nfcService._nfcData;
            console.log(this.data);
        });

        this.events.subscribe('random:gotRandomData', () => {
            console.log("Got random data");
            this.random = this.nfcService.random;
        });
    }

    renderRandomData() {
        this.nfcService.renderRandom();
    }
}

That’s how I detect nfc tag in app.js after platform ready and pass data for rendering to the same service

        nfc.addMimeTypeListener("text/any", (res) => {
            // console.log(res);
            return this.nfcService.parseNfcData(res);
        }, success, failure);

And this is HTML where I show them.

<h3>{{data}}</h3>
<h3>{{ random }}</h3>

#2

I think that the difference in name! I’ll try explain it: the first name has the set of chars, but the second name has the set of another chars! It is big difference, it is magic!11!1!

So can you put here your code?


#3

Yes sorry, clicked enter before my question was ready, edited now. Thanks.


#4

random don’t render?
:thinking: Your code looks good… You could try to update zone.js to last version (6.8)


#5

No this.data = {}; (after nfc:gotNfcData) doesn’t render before I click somewhere.

I even made changes, moved nfc listener inside the listenToNFCEvents() in HelloIonicPage and changed this._nfcData = “parsedNfcData”; (value to string to show hard coded value) so just one component and one service.

but still console prints it out but it renders only if I click somewhere. I just can’t work it out, what I am missing.

About the zone.js npm give me error while installing 0.6.8 that angular 2@2.0.0-beta.6 requires zone.js@0.5.14 but none was installed (0.5.14 is which I have).


#6

Yes, you need update Angular to beta13 too, and all dependencies. New zone.js fixed my problem with two-binding data.


#7

Libraries didn’t help, but thanks for suggestion.

I think it has something to do how I call thethis.nfcService.parseNfcData(); from mimeTypeListener Although I get right information after nfc:gotNfcData event and it renders just after clicking somewhere. So there is problem with some digesting or who knows what is blocking it :smiley:

nfc.addMimeTypeListener("text/any", (data) => {
    // console.log(res);
    this.nfcService.parseNfcData(data);
}, success, failure);

I tested, If I call this function this.nfcService.parseNfcData(); at the same place I call this.renderRandomData(); It will render the hard coded string, but if I call it from addMimeTypeListener it doesn’t.

So from nfc docs it should be called like this

nfc.addMimeTypeListener("text/any", this.nfcService.parseNfcData, success, failure);

parseNfcData still gets right data and console logs, but without using arrow functions it has no idea about “this” in service anymore… yet it still shouldn’t be the case, if it does render after clicking :rage:


#8

Assuming you’re using this NFC plugin, addMimeTypeListener appears to be calling document.addEventListener internally. Can you try throwing a breakpoint on there and seeing if that call to addEventListener is going through the zonejs patch or not?


#9

This might be the case, it does get into

Zone.prototype.runTask = function (task, applyThis, applyArgs)

But it ends in…

try {
      return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);
}
finally {
        _currentZone = oldZone; // < -- HERE
}

So is there any way to force it like angular 1 $scope.$apply?


#10

I haven’t used it yet, but ChangeDetectorRef looks potentially promising.


#11

this._ngZone.run()

google it.


#12

Thank you all and @xr0master, ngZone did the trick!