订阅返回值后,未更新Angular 7 uI

时间:2019-03-08 07:08:07

标签: angular ngzone

对于以下代码,似乎UI并未使用该值进行更新,但是,我可以看到该值已正确设置为字段。

我尝试了2种不同的方法,但我还没有尝试过变更检测方法,因为我相信下面代码中的一种,应该可以工作。

在我的服务中,我监听路由结束事件,其原因是,根据我的路由中参数的存在,需要更改服务中的某些内容,例如:'/ page /:id'

在一种情况下,URL可能是/ page,在另一种情况下是/ page / 12,因此基于这一事实,我需要从两个不同的服务返回值,如果ID不存在,请使用SERVICE1否则,请使用SERVICE2。

我基本上有一个订阅,该订阅从另一个订阅返回值。为此,我依靠“订阅”从内部订阅中发出值,该方法有效(请参见下面的示例)。我的苦恼是,UI无法呈现值。

主要服务

注意:为简洁起见,省略了整个类,只是为了显示所讨论的方法:

  get getCourse(): Observable<CoursesDTO> {
    let subject = new Subject<CoursesDTO>();

    this.router.events.pipe(filter(e => e instanceof NavigationEnd))
      .subscribe(x => {       

        let course: CoursesDTO = {
          courseName: '',
          courseId: ''
        };

        const route = this.router.routerState.snapshot.root;

        let courseId: string = '';

        if (route.children.length >= 1) {
          const obj = route.children[route.children.length - 1];
          const value = (obj.params as any).value;

          // we have a courseID, interact with the course workflow
          if (!_.isEmpty(value)) {
            this.courseWorkflowProxy.interact(value.courseId, 'CourseMaterial', null)
              .subscribe((b: InteractionResponseDTO) => {

                const x: CourseDTO = <any>b.workflowResult;

                course = {
                  courseName: x.courseName,
                  courseId: x.courseId
                };

                subject.next(course);
                subject.complete();

                return course; // I don't feel this is necessary
              });
          }          
        }

        // we don't have the courseID, so assume there is a JWT token
        // for example, that authenticated the user + courseID
        // and we can get this in the code behind
        this.coursesProxy
          .getCourseInfo()
          .subscribe(b => {

            course = {
              courseName: b.courseName,
              courseId: b.courseid
            };

            subject.next(course);
            subject.complete();

            return course; // I don't feel this is necessary
          }); 
      });

    return subject;
  }

请注意,此代码已被修改为代表该代码,而不是“实际”情况,如果感觉不对,则用于代码演示。

此方法在名为WatchBlock.ts的组件中的实现,显示了我尝试通过ngZone进行的可能的修复之一:

this.whatBlockService.getCourse.subscribe((r: CourseDTO) => {
  this._ngZone.run(() => {
    this.title = r.courseName;
    this.id = r.courseId;

    console.dir({ title: this.title, id: this.id }); // this prints the values to the console
  });
});

以下代码在“返回结果”的意义上阻止了“工作”,但是如上所述,它不会出现在呈现的HTML中。

HTML文件:

  <div fxLayout="row" fxLayoutAlign="start center">
    <div class="ml-16">
      <label class="identi">{{id}}</label>
    </div>
  </div>

  <div class="px-8 px-mat-16">
    <span class="mat-title">{{title}}</span>
  </div>

data_returned

我也尝试过BehaviorSubject方法,但这对我也不起作用。

我没有尝试过变更检测器路由,因为如果我了解分区的工作原理,我认为ngZone应该自己进行变更检测。

我不知道这一点,并希望得到那里的专家的帮助。

1 个答案:

答案 0 :(得分:0)

实际上,不可以,在NgZone中运行代码不能确保更改检测器将检测到更改。如果组件或任何父组件设置为ChangeDetectionStrategy.OnPush,它将仅检查输入。如果您不致电zone.runOutsideAngular,则通常不需要运行ngZone.run

但是您可以尝试在组件private _changeDetectorRef: ChangeDetectorRef回调中注入this._changeDetectorRef.markForCheck()并调用subscribe。使用markForCheck策略时,OnPush将组件标记为手动更改。 Docs