1

我正在订阅 Angular 中的一个主题,在值更改时,我正在尝试更改组件中的变量值。在控制台中,该值显示更新,但在视图(HTML)上,它没有。

服务.ts

    export class GMapsService {
  public mysubject: Subject<any> = new Subject();

  getData(or, des) {
    var origin1 = or;
    var destinationA = des;
    var service = new google.maps.DistanceMatrixService();
    var self = this;

    service.getDistanceMatrix(
      {
        origins: [origin1],
        destinations: [destinationA],
        travelMode: 'DRIVING',
        avoidHighways: false,
        avoidTolls: true,
      },
      (response, status) => {
        // this.mysubject.next(response);

        setInterval(
          function () {
            self.mysubject.next(Math.random())
          },
          2000
        )
      }
    );


  }
}

app.component.ts

    export class AppComponent implements OnInit {
  title: any = 'app';

  constructor(private GMapsService: GMapsService) { }

  ngOnInit() {
    this.GMapsService.getData('dallas, tx', 'austin, tx');

    this.GMapsService.mysubject.subscribe((value) => {
      this.title = value;
      console.log(this.title);       
 //title is random number in console. ex: 0.4333333
 //title is still 'app' on view till now.
    });

setTimeout(() => {
      console.log(this.title);
    }, 5000);


//title is random number in console.  ex: 0.4333333
// title suddenly become 'random number  ex: 0.4333333' on view after it is logged after 5 secs. How does logging 'title' again after 5 seconds change its value?
  }
}

app.component.html

{{title}}

我相信,如果相同的值在控制台中发生变化,它也应该反映在视图部分。在其他问题上,它说,我错过了这个上下文,但是控制台中的值正在更新,所以我相信我没有错过这个上下文。

编辑:我在 5 秒后尝试记录标题,它突然在视图上改变。仅记录值如何在视图上更改它?

4

1 回答 1

4

由于您使用的是基本主题,因此您需要在接收来自同步调用的数据之前订阅主题(除非您模拟它,否则 getDistanceMatrix 不应该是这样)。也就是说,因为基本主题默认情况下不会重播上次发布的值。

如果你想避免这种情况,你可以使用 ReplaySubject 或 BehaviorSubject:

服务.ts

@Injectable()
export class GMapsService {
  public mysubject: ReplaySubject<any> = new ReplaySubject(1);

  getData(or, des) {
    var origin1 = or;
    var destinationA = des;
    var service = new google.maps.DistanceMatrixService();

    service.getDistanceMatrix(
      {
        origins: [origin1],
        destinations: [destinationA],
        travelMode: 'DRIVING',
        avoidHighways: false,
        avoidTolls: true,
      },
      (response, status) => {
        console.log('service callback');
        this.mysubject.next(response);
      }
    );
  }
}

组件.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  title: any = 'app';

  constructor(private GMapsService: GMapsService, private changeDetectorRef: ChangeDetectorRef) { }

  ngOnInit() {
    this.GMapsService.getData('dallas, tx', 'austin, tx');

    this.GMapsService.mysubject.subscribe((value) => {
      this.title = value;
      this.changeDetectorRef.detectChanges();
    });
  }
}

这里的工作示例

编辑:显然,谷歌DistanceMatrixService.getDistanceMatrix响应不会触发更改检测。尝试使用ChangeDetectorRef并手动查找更改。我相应地更改了代码示例。

附录:Angular 使用了一个更改检测系统,该系统挂钩到异步事件的典型触发器,以检测视图的哪些部分必须更新。触发器的示例是用户输入、计时器(setTimeout、setInterval)或 Websocket 事件。如果 Google DistanceMatrixService 使用一种方法来检索不触发 angular 更改检测系统的数据,则不会检查视图的数据是否有更改,因此不会正确更新。由于setTimeout触发了更改检测,因此在您使用setTimeout. 您可以在此处阅读有关角度变化检测系统的更多信息。

于 2018-02-27T06:58:52.987 回答