Я знаю, что не первый, кто спрашивает об этом, но не могу найти ответа в предыдущих вопросах. У меня это в одном компоненте
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
В контроллере rawLapsdata
время от времени происходит мутация.
В laps
, данные выводятся как HTML в табличном формате. Это меняется всякий раз, когда rawLapsdata
меняется.
Мой map
компонент нужно использовать ngOnChanges
в качестве триггера для перерисовки маркеров на карте Google. Проблема в том, что ngOnChanges не срабатывает при rawLapsData
изменении родительского объекта . Что я могу сделать?
import {Component, Input, OnInit, OnChanges, SimpleChange} from 'angular2/core';
@Component({
selector: 'map',
templateUrl: './components/edMap/edMap.html',
styleUrls: ['./components/edMap/edMap.css']
})
export class MapCmp implements OnInit, OnChanges {
@Input() lapsData: any;
map: google.maps.Map;
ngOnInit() {
...
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
console.log('ngOnChanges = ', changes['lapsData']);
if (this.map) this.drawMarkers();
}
Обновление: ngOnChanges не работает, но похоже, что lapsData обновляется. В ngInit есть прослушиватель событий для изменения масштаба, который также вызывает this.drawmarkers
. Когда я меняю масштаб, я действительно вижу изменение маркеров. Так что единственная проблема в том, что я не получаю уведомления в момент изменения входных данных.
В родителе у меня эта строчка. (Напомним, изменение отражается на кругах, но не на карте).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
Обратите внимание, что this.rawLapsData
это указатель на середину большого json-объекта.
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
должно сделать это тогда.ngOnChanges()
не будет вызываться. Вы можете использоватьngDoCheck()
и реализовать свою собственную логику, чтобы определить, изменилось ли содержимое массива.lapsData
обновляется, потому что он имеет / является ссылкой на тот же массив, что иrawLapsData
.Ответы:
rawLapsData
продолжает указывать на тот же массив, даже если вы изменяете содержимое массива (например, добавляете элементы, удаляете элементы, изменяете элемент).Во время обнаружения изменений, когда Angular проверяет входные свойства компонентов на предмет изменений, он использует (по существу)
===
для грязной проверки. Для массивов это означает, что ссылки на массив (только) проверяются грязно. ПосколькуrawLapsData
ссылка на массив не меняется,ngOnChanges()
не будет вызываться.Я могу придумать два возможных решения:
Реализуйте
ngDoCheck()
и выполните собственную логику обнаружения изменений, чтобы определить, изменилось ли содержимое массива. (В документе Lifecycle Hooks есть пример .)Назначьте новый массив
rawLapsData
всякий раз, когда вы вносите какие-либо изменения в содержимое массива. ЗатемngOnChanges()
будет вызываться, потому что массив (ссылка) появится как изменение.В своем ответе вы пришли к другому решению.
Повторяя некоторые комментарии здесь к OP:
laps
компоненте ваш код / шаблон перебирает каждую запись вlapsData
массиве и отображает содержимое, поэтому для каждого отображаемого фрагмента данных есть привязки Angular.===
проверки), он по-прежнему (по умолчанию) грязно проверяет все привязки шаблона. Когда любое из этих изменений изменится, Angular обновит DOM. Вот что вы видите.maps
Компонент , вероятно , не имеет каких - либо привязок в своем шаблоне егоlapsData
ввода недвижимости, не так ли? Это объяснило бы разницу.Обратите внимание, что
lapsData
в обоих компонентах иrawLapsData
в родительском компоненте все указывают на один и тот же / один массив. Таким образом, даже если Angular не замечает никаких (ссылочных) изменений воlapsData
входных свойствах, компоненты «получают» / видят любые изменения содержимого массива, потому что все они совместно используют / ссылаются на этот один массив. Нам не нужен Angular для распространения этих изменений, как в случае с примитивным типом (строка, число, логическое значение). Но с примитивным типом любое изменение значения всегда будет запускатьсяngOnChanges()
- это то, что вы используете в своем ответе / решении.Как вы, наверное, уже догадались, свойства ввода объекта ведут себя так же, как свойства ввода массива.
источник
Не самый чистый подход, но вы можете просто клонировать объект каждый раз, когда меняете значение?
Думаю, я бы предпочел этот подход реализации вашего собственного,
ngDoCheck()
но, возможно, кто-то вроде @ GünterZöchbauer сможет вмешаться.источник
В случае с массивами это можно сделать так:
В
.ts
файле (родительский компонент), в котором вы обновляете,rawLapsData
сделайте это так:Решение:
и
ngOnChanges
будет вызываться дочерний компонентисточник
Как расширение второго решения Марка Райкока
вы можете клонировать содержимое массива следующим образом:
Я говорю об этом, потому что
у меня не сработало. Надеюсь, это поможет.
источник
Если данные поступают из внешней библиотеки, вам может потребоваться запустить оператор обновления данных внутри
zone.run(...)
. Залитьzone: NgZone
для этого. Если вы уже можете запустить экземпляр внешней библиотеки внутриzone.run()
, то, возможно, вам не понадобитсяzone.run()
позже.источник
$scope.$apply
?zone.run
похоже на$scope.apply
.Используется,
ChangeDetectorRef.detectChanges()
чтобы указать Angular запускать обнаружение изменений при редактировании вложенного объекта (который он пропускает из-за грязной проверки).источник
У меня есть 2 решения вашей проблемы
ngDoCheck
для определенияobject
измененных данных или нетobject
новый адрес памятиobject = Object.create(object)
от родительского компонента.источник
Мое "хакерское" решение
selectedTps изменяется одновременно с rawLapsData, и это дает карте еще один шанс обнаружить изменение с помощью более простого
объектногопримитивного типа. Это НЕ элегантно, но работает.источник
Обнаружение изменений не запускается, когда вы изменяете свойство объекта (включая вложенный объект). Одним из решений было бы переназначить новую ссылку на объект с помощью функции clone () lodash.
источник
Вот хак, который избавил меня от проблем с этим.
Итак, сценарий, аналогичный OP - у меня есть вложенный компонент Angular, которому нужны данные, передаваемые ему, но входные данные указывают на массив, и, как упоминалось выше, Angular не видит изменений, поскольку он не проверяет содержимое массива.
Поэтому, чтобы исправить это, я конвертирую массив в строку для Angular, чтобы обнаружить изменение, а затем во вложенном компоненте я разделяю (',') строку обратно на массив и снова его счастливые дни.
источник
Я наткнулся на ту же потребность. И я много читал об этом, так что вот моя статья по этой теме.
Если вы хотите, чтобы обнаружение изменений происходило при нажатии, тогда оно будет, когда вы измените значение объекта внутри, верно? И у вас также будет это, если вы каким-то образом удалите объекты.
Как уже было сказано, использование changeDetectionStrategy.onPush
Допустим, у вас есть этот компонент, который вы создали с помощью changeDetectionStrategy.onPush:
Затем вы нажимаете элемент и запускаете обнаружение изменений:
или вы удалите элемент и вызовете обнаружение изменений:
или вы бы изменили значение attrbibute для элемента и инициировали обнаружение изменений:
Содержание обновления:
Метод slice возвращает тот же самый массив, а знак [=] создает новую ссылку на него, вызывая обнаружение изменений каждый раз, когда это необходимо. Легко и читабельно :)
С Уважением,
источник
Я пробовал все решения, упомянутые здесь, но по какой-то причине
ngOnChanges()
у меня все еще не сработало. Итак, я вызвал егоthis.ngOnChanges()
после вызова службы, которая повторно заполняет мои массивы, и она сработала .... правильно? возможно нет. Аккуратные? конечно нет. Работает? да!источник
хорошо, поэтому мое решение для этого было:
И это вызывает у меня ngOnChanges
источник
Пришлось создать для него хак -
источник
В моем случае это были изменения значения объекта, которые
ngOnChange
не фиксировались. Некоторые значения объектов изменяются в ответ на вызов API. Повторная инициализация объекта устранила проблему и вызвалаngOnChange
срабатывание в дочернем компоненте.Что-то вроде
источник