检查后表达式已更改。先前的值:“ ngTemplateOutlet:未定义”。当前值:'ngTemplateOutlet:[对象对象]'

时间:2018-07-04 10:05:34

标签: angular

有这样的错误:

  

错误错误:ExpressionChangedAfterItHasBeenCheckedError:表达   检查后已更改。上一个值:'ngTemplateOutlet:   未定义”。当前值:“ ngTemplateOutlet:[对象对象]”。

     

在viewDebugError(core.js:9775)

     

在expressionChangedAfterItHasBeenCheckedError(core.js:9753)

     

在checkBindingNoChanges(core.js:9920)

     

在checkNoChangesNodeInline(core.js:13970)

     

在checkNoChangesNode(core.js:13942)

     

在debugCheckNoChangesNode(core.js:14771)

     

在debugCheckDirectivesFn(core.js:14673)

     

at Object.eval [作为updateDirectives](ShowEventComponent.html:73)

     

在Object.debugUpdateDirectives [作为updateDirectives](core.js:14655)

     

在checkNoChangesView(core.js:13780)

她之所以出现是因为

<tr *ngFor="let user of users">
    <ng-template [ngTemplateOutlet]="loadTemplate(user)" 
                [ngTemplateOutletContext]="{ $implicit: user}">
    </ng-template>
</tr>

我该如何解决?

我使用Angular 5.2.0,rxjs 5.5.6

4 个答案:

答案 0 :(得分:2)

我最近解决了一个类似的问题,但找不到太多帮助,所以我将提供一些帮助。

首先,这仅在开发人员模式下发生,但这是一个严重的问题。当Angular运行变更检测时,它将跟踪其所有绑定值(例如ngTemplateOutlet),然后将其与变更检测周期结束后的值进行比较。

出现此错误的原因是因为您在html中设置了[ngTemplateOutlet]的方法。这导致该方法(loadTemplate(user))每发生一次更改检测就运行一次。这可能是该方法运行的5或10倍,这并不理想。

第一次将该值设置为undefined,然后在随后的周期中更新该值。我猜想loadTemplate返回的是TemplateRef,但是第一次运行该方法时,未定义TemplateRef,这就是原因。

有很多方法可以解决此问题,我需要查看您的component.ts代码。但是必须进行2次更改。首先,您需要不使用方法来设置[ngTemplateOutlet]。您可以使用组件Observable或组件字段。但是,第二,您还需要在适当的时间设置该字段或可观察的字段。您要延迟直到定义了模板。您可以在ngOnInit中执行此操作,方法是将设置字段的代码包装在setTimeout()中,或者如果使用Observable,则使用lettable rxjs delay(0)。

再次,我需要查看loadTemplate(user)和component.ts中的逻辑,以确切显示如何安排它。

您还可以将所需数据从父组件输入到此组件,然后将使用该数据的逻辑放在[ngTemplate]

之后

答案 1 :(得分:1)

这与更改检测有关。你可以在这里读更多关于它的内容。我通过使用ChangeDetectorRef的detectChanges()方法解决了这个问题。

constructor(private cdr: ChangeDetectorRef) {}

  ngOnInit() {}

  ngAfterViewInit(): void {
    this.cdr.detectChanges();
  }

您需要实现AfterViewInit接口。

答案 2 :(得分:0)

就像Envil一样,您可以将loadTemplate()函数的内容包装到setTimeout中,例如:

    setTimeout(() => {
        yourTemplateLoadingMechanism();
    });

但是通常我会避免在模板中调用函数,因为它们一遍又一遍地调用,这使调试变得很困难,并且降低了性能。相反,您可以预取所有模板,并像往常一样以双向绑定的方式提供它们,甚至可以将rxjs Observablesasync键一起使用,这样做可以更有效地规避您的问题。

答案 3 :(得分:0)

您应该在TemplateRef功能上设置AfterContentInit