2016-11-27 2 views
11

У меня есть компонент таблицы данных (angular2-data-table), где мы изменили проект из традиционного определения изменения углов в OnPush для оптимизации скорости рендеринга.Angular2 ngFor Обнаружение изменения с помощью муфт массива

После того, как была реализована новая стратегия обнаружения изменений, ошибка была указана, поскольку таблица не обновляется, когда объект данных мутирован, например, обновления свойств объекта. Ссылка: https://github.com/swimlane/angular2-data-table/issues/255. Сильный вариант использования может быть сделан для такого типа потребностей в таких вещах, как встроенное редактирование или внешние изменения данных, в единое свойство в большом сборе данных, таком как биржевой тикер.

Чтобы устранить эту проблему, мы добавили пользовательскую функцию проверки свойств trackBy, которая называется trackByProp. Ссылка: commit. К сожалению, это решение не решило проблему.

На demo page при активной перезагрузке вы можете увидеть демонстрацию, на которую ссылаются в приведенном выше фиксации, но не обновлять таблицу до тех пор, пока вы не нажмете кнопку, чтобы вызвать обнаружение изменений.

Структура компонента что-то вроде:

Table > Body > Row Group > Row > Cell

все эти компоненты реализации OnPush. Я использую геттеры/сеттеры в наборе строк для запуска перерасчета страниц, как показано на рисунке here.

Мы хотим остаться с обнаружением изменений OnPush для тех, кто реализует этот шаблон, однако в качестве проекта с открытым исходным кодом с несколькими потребителями можно утверждать какую-то функцию пользовательской проверки для видимых значений строк на экране.

Все, что сказал, trackBy не вызывает обнаружение изменений в значениях ячейки строки, что является лучшим способом для этого?

+0

Вопрос должен включать код, который позволяет воспроизвести проблему. –

ответ

15

Угловой детектор изменений не проверяет содержимое массивов или объектов.

Hacky обходного путь, чтобы просто создать копию массива после мутации

this.myArray.push(newItem); 
this.myArray = this.myArray.slice(); 

Таким образом this.myArray ссылается другой экземпляр массива и Угловыми распознают изменения.

Другой подход заключается в использовании IterableDiffer (для массивов) или KeyValueDiffer (для объектов)

// inject a differ implementation 
constructor(differs: KeyValueDiffers) { 
    // store the initial value to compare with 
    this.differ = differs.find({}).create(null); 
} 

@Input() data: any; 

ngDoCheck() { 
    var changes = this.differ.diff(this.data); // check for changes 
    if (changes && this.initialized) { 
    // do something if changes were found 
    } 
} 

Смотрите также https://github.com/angular/angular/blob/14ee75924b6ae770115f7f260d720efa8bfb576a/modules/%40angular/common/src/directives/ng_class.ts#L122

+0

'ngDoCheck' не работает, пока я не вызываю событие, подобное клику. Кроме того, я заметил, что '* ngFor' уже имеет пользовательское отслеживание, почему бы это не обнаружить? https://github.com/angular/angular/blob/master/modules/%40angular/common/src/directives/ng_for.ts#L113 – amcdnl

+0

Я также изучал использование Rx для этого: http://stackoverflow.com/questions/32683488/rxjs-observing-object-updates-and-changes – amcdnl

+0

Как уже упоминалось выше, вопрос должен содержать достаточную информацию, чтобы иметь возможность воспроизводить. Мой ответ был просто выстрелом из бедра. Плункер для воспроизведения будет полезен. Возможно, это проблема зоны. –

2

Вы можете использовать метод markForCheck от ChangeDetectorRef.


У меня есть подобная проблема, где у меня есть компонент, который содержит большое количество данных и повторно проверить их все на каждом цикле обнаружения изменений не вариант. Но поскольку мы наблюдаем некоторые свойства от URL, и мы меняем вещи в представлении соответственно, с onPush наш взгляд не обновляется (автоматически).

Так что в вашем конструкторе, используйте DI получить экземпляр changeDetectorRef: constructor(private changeDetectorRef: ChangeDetectorRef)

И везде, где вам нужно, чтобы вызвать changeDetection: this.changeDetectorRef.markForCheck();

+0

Я пробовал это на родительской странице и не имел никаких результатов. Возможно, это нужно сделать на уровне компонентов, который их рендерит, но в этот момент я ничего не знаю: S – amcdnl

+0

Я полагаю, что какой-то пользовательский api для изменения свойства мог бы сделать это? Но это не очень приятно с точки зрения API. – amcdnl

1

я тоже столкнулся с аналогичной проблемой, где оптимизировать моя производительность приложения, я должен был использовать changeDetection.OnPush стратегии. Так что я ввел ее как в моем родительском компоненте, а также конструктор моего ребенка компонента, экземпляр changeDetectorRef

export class Parentcomponent{ 
     prop1; 

     constructor(private _cd : ChangeDetectorRef){ 
      } 
     makeXHRCall(){ 
     prop1 = ....something new value with new reference; 
     this._cd.markForCheck(); // To force angular to trigger its change detection now 
     } 
    } 

Аналогично в детском компоненте, впрыскивается экземпляр changeDetectorRef

export class ChildComponent{ 
    @Input myData: myData[]; 
    constructor(private _cd : ChangeDetectorRef){ 
      } 
     changeInputVal(){ 
     this.myData = ....something new value with new reference; 
     this._cd.markForCheck(); // To force angular to trigger its change detection now 
     } 
    } 

Угловое изменение Обнаружение срабатывает при каждой асинхронной функции: -

  • любое событие DOM, например, щелчок, отправка, наведение курсора мыши.
  • любой XHR вызов
  • любые Таймеры как SetTimeout() и т.д.

Таким образом, этот вид замедляет приложение, потому что даже когда мы перетаскиванием мыши, угловатые был запускающих changeDetection. Для сложного приложения, охватывающего несколько компонентов, это может быть одним из основных узких мест в производительности, поскольку у углового есть этот тип родительской стратегии обнаружения детей. Чтобы избежать этого, мы лучше используем стратегию OnPush и принудительно запускаем обнаружение изменений углов, где мы видим, что существует эталонное изменение.

Во-вторых, в стратегии OnPush следует быть очень осторожным, чтобы он вызывал изменение только при изменении ссылки на объект, а не только на значение свойства объекта i.e в разделе «Угловое изменение» означает «новая ссылка».

Для например: -

obj = { a:'value1', b:'value2'}' 
    obj.a = value3; 

Характеристическое значение «а» «OBJ» может иметь изменения, но OBJ все еще указывает на то же ссылки, так Угловое обнаружение изменения не вызывают здесь (пока сила это к); Чтобы создать новую ссылку, нужно клонировать объект в другой объект и соответствующим образом назначать его свойства.

для дальнейшего понимания, читать о структурах Immmutable данных, изменение обнаружения here

Смежные вопросы