双向数据绑定无法在Angular的subscribe中运行?

时间:2018-02-27 05:41:55

标签: angular angular-services angular-components angular-observable

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

Service.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秒后记录标题,并且视图上突然发生变化。如何记录值可以在视图上更改它?

1 个答案:

答案 0 :(得分:2)

由于您使用的是基本主题,因此您需要在从同步调用接收数据之前订阅主题(除非您嘲笑它,否则不应使用getDistanceMatrix)。也就是说,因为默认情况下基本主题不会重播最后发布的值。

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

service.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);
      }
    );
  }
}

component.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();
    });
  }
}

工作示例here

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

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