2016-04-23 7 views
3

このエラーがなぜスローされるのか分かりますが、コードを整理する方法を理解できません。ここで問題Angular2パイプが原因で「...チェックされた後に変更されました」devエラー

@Component({ 
    selector: 'article', 
    templateUrl: 'article.html', 
    moduleId: module.id, 
    directives: [Toolbar] 
}) 
export class Article { 
    public toolbar: Array<IToolbarItem>; 

    constructor() { 
     this.toolbar = [ 
      { 
       css: 'ic-save', 
       action: (item) => { }, 
       visible: false 
      }, 
      <IDropdownItem>{ 
       css: 'ic-edit', 
       items: [ 
        { 
         css: 'ic-edit', 
         label: 'Edit Article', 
         action: (item) => { } 
        }, 
        { 
         css: 'ic-edit', 
         label: 'Edit Content', 
         action: (item) => { 
          this.toolbar[0].visible = true; 
         } 
        } 
       ] 
      } 
     ]; 
    } 
} 

とツールバーコンポーネントおよびテンプレート

@Component({ 
    selector: 'toolbar', 
    moduleId: module.id, 
    templateUrl: 'toolbar.html', 
    styleUrls: ['toolbar.css'], 
    pipes: [VisiblePipe], 
    encapsulation: ViewEncapsulation.None 
}) 
export class Toolbar { 
    @Input() items: Array<IToolbarItem>; 
} 

<div class="container"> 
    <div class="toolbar"> 
     <div class="toolbar-item" *ngFor="#i of (items | visible)"> 
     . 
     . 
     . 

し、最終的にVisiblePipeパイプ

@Pipe({ 
    name: 'visible', 
    pure: false 
}) 
export class VisiblePipe implements PipeTransform { 
    transform(value) { 
     return (<Array<any>>value).filter(v => v.visible !== false); 
    } 
} 

があるので、記事の構成要素は、ツールバーの配列が渡されたツールバーのコンポーネントを使用していますこれは可視のパイプを使用してvisibleプロパティがfalseに設定されている項目をフィルタリングします。

VisiblePipeパイプを実行すると、エラーがスローされます。だから何らかの理由でパイプ変換コードが変更検出後に実行されていますか?どうして?

編集

だから私はギュンターによって提案どおりに私のVisiblePipeパイプを更新しました、そしてそれは

export class VisiblePipe implements PipeTransform { 
    private previousValue: Array<IVisibleItem>; 
    private cacheResult: Array<IVisibleItem>; 

    transform(value: Array<IVisibleItem>) { 
     if (!this.previousValue || !compareArrays(this.previousValue, value)) { 
      this.previousValue = value.map(i => { return { visible: i.visible } }); 
      this.cacheResult = value.filter(v => v.visible !== false); 
     } 

     return this.cacheResult; 
    } 
} 

function compareArrays(arrayOne: Array<IVisibleItem>, arrayTwo: Array<IVisibleItem>) { 
    if (arrayOne.length !== arrayTwo.length) { 
     return false; 
    } 

    for (let i = 0, l = arrayOne.length; i < l; i++) { 
     let arrayOneEntry = arrayOne[i]; 
     let arrayTwoEntry = arrayTwo[i]; 

     if (arrayOneEntry.visible !== undefined && 
      arrayTwoEntry.visible !== undefined && 
      arrayOneEntry.visible !== arrayTwoEntry.visible) { 
      return false; 
     } 
    } 

    return true; 
} 

interface IVisibleItem { 
    visible: boolean 
} 

を働いているが、これは本当に最高の/唯一の方法ですか?私は自分自身の変更検出のいくつかの側面を処理しているように感じる!

答えて

3

エラーが発生します。devMode角度ランは各ターンごとに2回の検出を変更し、入力値が変更されていないにもかかわらず2つの後続の呼び出しに対してパイプが異なる配列インスタンスを返します。 pure: falseに設定されている場合、これは「許可」さえありません。

これを修正するには、入力が変更されなかったときにパイプが後続の呼び出しで同じ配列インスタンスを返すようにします。

@Pipe({ 
    name: 'visible', 
    pure: false 
}) 
export class VisiblePipe implements PipeTransform { 
    this cached; 
    transform(value) { 
     if(value == this.cached && this.resultCached) { 
     return this.resultCached; 
     } 
     this.value = value; 
     this.resultCached = (<Array<any>>value).filter(v => v.visible !== false); 
     return this.resultCached; 
    } 
} 

アレイを外部から変更することができます(新しいインスタンスを作成せずに)場合は、これも処理する必要があります。最後の呼び出し以降に配列の内容が変更されているかどうかを確認する必要があります。

IterableDiffersを使用して、配列内の項目が追加または削除されたかどうかを確認できます。 これには、配列に含まれる項目のプロパティの変更は引き続き含まれません。

関連する問題