ng2 update template after making a simple meteor.c

2019-07-07 19:30发布

问题:

This has been asked before but I cannot find an answer that helps. I want oResult to change its value after the call is made. The answer has to be appropriate to running ng2, meteor and angular-meteor. Thanks!

/// <reference path="../../typings/angular2-meteor.d.ts" />

import {Input, Component, View, NgZone} from 'angular2/core';
import {MeteorComponent} from 'angular2-meteor';

@Component({
  selector: 'testcall',
  template: `
    <button (click)="testCall()">Get TestCall Data</button>
    <code><pre>{{oResult}}</pre></code>
  `
})

export class TestCall extends MeteorComponent {

  oResult:any

  constructor(private _ngZone: NgZone) {
    super();
    this.oResult = JSON.stringify({res: 'start'});
  }

  testCall(): void {
    Meteor.call('testCall', function(error,result) {
      if (error) {
        console.log('failed', error);
      } else {
          console.log('successful call', result);
          this._ngZone.run(() => {
              this.oResult = result
          });
      }
    });
  }
}

Edit

I've shortened the code and tried to explore if 'this' was the problem. Absence of the angular-meteor component makes to difference to execution of the Meteor.call. But ng2 still fails to change template after the call has executed. And I've tried with and without NgZone. Might dump ng2 'cos I sure haven't the brains or time to get stuck on trivial stuff like this!

/// <reference path="../../typings/angular2-meteor.d.ts" />

import {Input, Component, View} from 'angular2/core';

@Component({
  selector: 'testcall',
  template: `
    <button (click)="testCall()">Get TestCall Data</button>
    <code><pre>{{oResult}}</pre></code>
  `
})

export class TestCall {

  oResult:any

  testCall(): void {
    Meteor.call('testCall', (error:any, result:any) => error ? 
    console.log('failed', error) : 
    (this.oResult=result, console.log('successful call', result, this.oResult)));
  }
}

Edit

This clunky bit of code works to a fashion. Could anyone suggest how to make the Meteor.call a callback of the setTimeout?

  testCall(): void {
    var self:any = this
    Meteor.call('testCall', (error:any, result:string) => error ?
      console.log('failed', error) :
      (self.oResult=result, console.log('successful call', self.oResult)));
    setTimeout(()=>{
      this.oResult=self.oResult;
    },2000);
  }

回答1:

I personally prefer entire async callback logic runs synchronously within the Angular zone.

export class TestComponent {
  oResult: any;

  constructor(private ngZone: NgZone) {
  }

  testCall(): void {
    Meteor.call('testCall', (error, result) => this.ngZone.run(() => {

      if (error)
        console.log('failed', error);
      else {
        console.log('successful call', result);
        this.oResult = result;
      }

    }));
  }
}


回答2:

export class TestCall extends MeteorComponent {

  oResult:any

  constructor(private zone: NgZone) {
    super();
    this.oResult = JSON.stringify({res: 'start'});
  }

  testCall(): void {
    Meteor.call('testCall', function(error,result) {
      if (error) {
        console.log('failed', error);
      } else {
          console.log('successful call', result);
        this.zone.run(() => { // do updates within Angular zones 
          this.oResult = result
        });
      }
    });
  }
}

See also Triggering Angular2 change detection manually



回答3:

After 3 weekends (I'm a weekend coder) I found something that worked!

This doesn't seem to need the ng2-meteor package.

/// <reference path="../../typings/angular2-meteor.d.ts" />

import {Component, View, NgZone} from 'angular2/core';

@Component({
  selector: 'testcall',
  template: `
    <button (click)="testCall()">Get TestCall Data</button>
    <div>{{oResult}}</div>
  `,
  inputs: ['oResult']
})


export class TestCall {

  oResult:any

  constructor(private _ngZone: NgZone) {
  }

  testCall(): void {

      var promise = function() {
        return new Promise((resolve, reject) =>
          Meteor.call('testCall', (error:any, result:string) => error ? reject(error) : resolve(result))
        );
      };

      promise()
        .then(
          (result) => {
            this._ngZone.run(()=>{
              this.oResult = result;
              console.log(result);
            })
          }
        )
  }
}