2016-04-23 2 views
3

Ich weiß, warum dieser Fehler ausgelöst wird, aber ich verstehe nicht, wie ich meinen Code organisieren, um es zu beheben. Hier ist die AusgabeAngular2 pipe verursacht '... hat sich geändert, nachdem es überprüft wurde' dev error

@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; 
         } 
        } 
       ] 
      } 
     ]; 
    } 
} 

und die Symbolleiste Komponente und Vorlage

@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)"> 
     . 
     . 
     . 

und schließlich die VisiblePipe Rohr

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

So Artikelkomponente verwendet die Symbolleiste Komponente, auf die die Symbolleiste Array übergeben wird Dies wiederum verwendet die sichtbare Pipe, um Elemente herauszufiltern, bei denen die visible -Eigenschaft auf "false" gesetzt ist.

Wenn die Pipe VisiblePipe ausgeführt wird, wird der Fehler ausgelöst. Aus irgendeinem Grund wird der Pipe-Transformationscode nach der Änderungserkennung ausgeführt? Warum?

bearbeiten

Also habe ich mein VisiblePipe Rohr gemäß dem Vorschlag von Gunter aktualisiert, und es funktioniert

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 
} 

ist dies wirklich der beste/einzige Weg? Es fühlt sich an, als würde ich selbst einen Aspekt der Veränderungserkennung bearbeiten!

Antwort

3

Der Fehler wird verursacht, weil in devMode Angular Läufe die Erkennung zweimal für jede Umdrehung ändern und Ihre Pipe eine andere Array-Instanz für zwei nachfolgende Aufrufe zurückgibt, obwohl sich der Eingabewert nicht geändert hat. Dies ist nicht einmal "erlaubt" wenn auf pure: false eingestellt ist.

Um es zu beheben, stellen Sie sicher, dass Ihre Pipe dieselbe Array-Instanz für nachfolgende Aufrufe zurückgibt, wenn sich die Eingabe nicht geändert hat.

@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; 
    } 
} 

Wenn das Array von außen verändert werden (ohne eine neue Instanz erstellen), dann müssen Sie kümmern sich um diese auch zu übernehmen. Sie müssen dann überprüfen, ob sich der Inhalt des Arrays seit dem letzten Aufruf geändert hat.

Sie können die IterableDiffers verwenden, um zu überprüfen, ob Elemente im Array hinzugefügt oder entfernt oder ersetzt wurden. Dies bezieht sich immer noch nicht auf Änderungen der Eigenschaften der Elemente im Array.

Verwandte Themen