2017-07-22 1 views
2

変更を検出するとかなり重い計算をするAngularコンポーネントがあります。特定の@Inputで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 ___の代わりに読み込み可能なStringを返します。

@Input("customRenderer")を追加すると、ngOnChangesは、その関数参照が変更されていなくても、すべての時間を起動します。

enter image description here

私は初期値が設定された後、特定のフィールドに変化検出をトリガしないように角度伝えることができる方法はありますか?

ngOnChanges関数でcustomRendererが唯一の変更であるかどうかをチェックするifステートメントがありますが、変更検出は引き続き非効率的なトリガーとなります。

Angularはフックを持っていますか?フィールドがcustomRendererなら基本的にはオーバーライドできますが、変更検出をトリガーしないでください。 @パンカジ・パーカーの回答に基づいて

更新:

@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(); 

     ... 

    } 

    ... 

} 

は今アイデアが手動で変更検出

<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> 

をトリガーするrender++を呼び出すことですけれども違いはありません。..

+1

私は、変更検出が誤って2つの異なる機能(おそらく関数の同等性を持つAngularまたはDartのバグ)と同じ関数参照を認識していると思います。ラッパークラスで関数をラップし、このようにして目的の動作が得られるかどうかを調べることができます。あなたの質問には、再現するのに十分な情報が含まれていません(customRendererはどこから来たのですか)。値が実際に変更されなかった場合は、高価な計算をスキップすることもできます。 –

+0

私はマップでそれをラップアップして、それが正しく動作するようです。私の答えを見てください。 –

+0

バグレポートの作成を検討しましたか?私は変更の検出機能の参照が変更されているかどうかを認識できる必要があります。私が想像できることは、機能が比較されるたびに、新しいテアロフが作成され、同じ機能からの2つのテアロフが同じとみなされないということです。おそらく、クラスレベルのフィールドに関数を割り当ててこのインスタンスを返すだけで、問題が解決する可能性があります。 –

答えて

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; 

スタンドアロンプ​​ロジェクトのある時点で問題を再現し、そのバグを記録できるかどうかを確認します。

3

このような場合は、detachコンポーネントを変更検知器tre e(ngOnInitフック内で行うか、コンポーネントメタデータでChangeDetectionStrategy.Detachを使用してください)、すべてのCDに対して追加のngDoCheckライフサイクルフックを追加します。あなたが条件を満たしますいつでも、特にあなたのconditionSoをチェックされることをフックで

MyTable(this.cd); 

ngOnInit() { 
    cd.detach(); 
} 

は、あなたの変化検出器を取り付けて、もう一度それを切り離します。したがって、次の変更検出サイクルは、コンポーネントのバインディングを更新し、 ngOnChangesメソッドを呼び出すことになります。

ngDoCheck() { 
    if(model.value == 'specific value') { 
     cd.reattach(); 
     cd.detectChanges(); //run cd once again for enabled component 
     cd.detach(); //detached component 
     //or 
     //cd.markForCheck(); 
    } 
} 
+0

あなたの提案に基づいて回答を更新しました。「ngOnChanges(customRenderer)」は、変化検出器。 –

+1

@JanVladimirMostert weired、もう一度確認してください。コンポーネントメタデータオプションを使用してコンポーネントを取り外してみてください。 –

+0

私自身の変更検出を必要としない、よりクリーンなソリューションが見つかりました。手動での変更の検出が必要な約30のフィールドがありますが、それは少しです。マップ内の関数をラップして、魔法のように変化検出を固定します。 –

関連する問題