【问题标题】:Two way data binding not working from subscribe in Angular?两种方式的数据绑定在Angular中的订阅不起作用?
【发布时间】:2018-08-06 16:46:41
【问题描述】:

我正在订阅 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 秒后记录标题,但它突然在视图上发生了变化。仅记录值如何在视图上更改它?

【问题讨论】:

  • 请发表您的看法
  • @ShakeerHussain 完成
  • 我的猜测:this.title 的范围错误。所以this 没有引用你的组件。尝试在其中添加一个 console.log 或断点。不太确定,但也许你可以写this.GMapsService.mysubject.subscribe(value =&gt; this.title = value);
  • 你能把this.GMapsService.getData('dallas, tx', 'austin, tx');的线移到订阅线下面吗?我的意思是,先订阅然后调用函数。
  • 我认为你错过了声明访问修饰符例如:公共标题:any = 'app';

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


【解决方案1】:

由于您使用的是基本主题,因此您需要在接收来自同步调用的数据之前订阅该主题(除非您模拟它,否则 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

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

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

【讨论】:

  • 嘿,谢谢。当我通过实际的 API 时,这对我不起作用:(
  • 无。当我在 5 秒后检查变量时,我刚刚意识到我的代码工作正常,在 settimeout 时视图上的值发生了变化。我也更新了我的代码。你能检查一下吗?
  • 不推荐使用超时更新视图。你能在你的组件订阅中添加console.log 并告诉我它是否被记录了吗?
  • 是的。例如,在订阅中分配的值是 0.4。现在,如果我在 settimeout 中记录相同的值,它仍然是 0.4,但现在它会在视图上更新。我很困惑如何只记录更新视图?
  • 嘿,那个变化检测器让它工作了,谢谢!但是我仍然很困惑,为什么标题值在控制台中更新,而不是在视图中更新?为什么只是在 settimeout 中记录它会在视图上更新它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-27
  • 2015-11-07
  • 1970-01-01
  • 2017-04-06
  • 2018-10-03
相关资源
最近更新 更多