强制Angular不对某些@Input进行更改检测

时间:2017-07-22 07:57:20

标签: angular dart angular-dart

我有一个Angular组件,在检测到变化时会做一些相当繁重的计算。

@Component (
    selector: 'my-table',
    ... 400+ lines of angular template ...
)
class MyTable implements OnDestroy, AfterContentInit, OnChanges {
    ...
    @override
    ngOnChanges(Map<String, SimpleChange> changes) {
        log.info("ngOnChanges" + changes.keys.toString());
        _buildTableContent();
    }
    ...
}

当所有输入都是Stringintbool时,此功能非常有效;换句话说,ngOnChanges仅在这些属性实际发生变化时触发。

我现在需要为其中一个字段添加自定义渲染器,以便呈现不仅仅是简单String的数据而且我使用

@Input("customRenderer") Function customRenderer;

customRenderer函数现在将决定是否应该按原样返回值,或者如果值是对象/列表,从中提取某些值并返回可读字符串而不仅仅是Instance of ___ ;

只要我添加此@Input("customRenderer")ngOnChanges就会一直触发,即使该功能参考没有改变。

enter image description here

有没有办法告诉Angular在设置初始值后不会在某些字段上触发更改检测?

快速破解就是在ngOnChanges函数中只有一个if语句,用于检查customRenderer是否是唯一的变化,但更改检测将继续触发,这会感觉效率低下。

Angular是否有一个我可以覆盖的钩子,基本上会说,如果字段为customRenderer,则不触发变化检测,否则进行正常的变化检测?

根据@ pankaj-parkar的回复更新

@Component (
    selector: 'my-table',
    ... 400+ lines of angular template ...
)
class MyTable implements OnDestroy, AfterContentInit, OnChanges, DoCheck {

    ...

    final ChangeDetectorRef cdr;

    int renderOldValue = 0;
    @Input() int render = 0;

    MyTable(this.cdr);

    @override
    ngOnChanges(Map<String, SimpleChange> changes) {
        log.info("ngOnChanges" + changes.keys.toString());
        _buildTableContent();
    }

    @override
    ngDoCheck() {
        if (renderOldValue != render) {
            cdr.reattach();
            cdr.detectChanges();
            cdr.detach();
            renderOldValue = render;
        }
    }

    @override
    ngAfterContentInit() {

        // detach table from angular change detection;
        cdr.detach();

       ...

    }

    ...

}

现在的想法是调用render++来手动触发变更检测

    <my-table 
        (change)="change(\$event)"
        (click2)="editResource(\$event)"
        [custom]="['tags', 'attributes']"
        [customRenderer]="customRenderer"
        [data]="data ?? []"
        [debug]="true"
        [editable]="enableQuickEdit ?? false"
        [loading]="loading ?? true"
        [render]="render ?? 0"
        [rowDropdownItems]="rowDropdownItems"
        [tableDropdownItems]="tableDropdownItems ?? []">
        <column *ngFor="let column of visibleColumns ?? []"
            [editable]="column.editable"
            [field]="column.field"
            [title]="column.title">
        </column>
    </my-table>

虽然不会有所作为......

2 个答案:

答案 0 :(得分:3)

对于这种情况,您应该从更改检测器树中考虑detach您的组件(您可以在ngOnInit挂钩内执行此操作或在组件元数据中使用ChangeDetectionStrategy.Detach)并添加添加{{1}生命周期钩子,每张CD都会触发。

ngDoCheck

在那个钩子中,您将专门检查您的状况。每当条件得到满足时,请连接您的变化检测器并再次将其拆下。因此,下一个更改检测周期将负责更新组件绑定并调用MyTable(this.cd); ngOnInit() { cd.detach(); } 方法。

ngOnChanges

答案 1 :(得分:1)

现在找到一个可行的解决方法。 通过将这些函数包装在地图中,更改检测似乎表现正确:

final Map renderers = {
    "tags": (List<TagVO> tags) {
        final List<String> tagStrings = [];
        tags.forEach((tag) => tagStrings.add(tag.name));
        return tagStrings.join(", ");
    },
    "attributes": (List<Attribute> attributes) {
        return "ATTRIBUTES!!!";
    }
};

并且因为某种原因将其传递出来:

<my-table 
    ...
    [render]="render ?? 0"
    [renderers]="renderers"
    ...
    <column *ngFor="let column of visibleColumns ?? []"
        [editable]="column.editable"
        [field]="column.field"
        [title]="column.title">
    </column>
</my-table>

和@Input:

@Input("renderers") Map<String, Function> renderers;

看看我是否可以在独立项目中的某个时刻重现该问题并为其记录错误。