У меня есть родительский компонент ( CategoryComponent ), дочерний компонент ( videoListComponent ) и ApiService.
У меня большая часть этой работы работает нормально, т. Е. Каждый компонент может получить доступ к json api и получить соответствующие данные через наблюдаемые объекты.
В настоящее время компонент списка видео только получает все видео, я хотел бы отфильтровать это только для видео в определенной категории, я достиг этого путем передачи categoryId ребенку через @Input()
.
CategoryComponent.html
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
Это работает, и когда родительская категория CategoryComponent изменяется, тогда значение categoryId передается через, @Input()
но затем мне нужно обнаружить это в VideoListComponent и повторно запросить массив видео через APIService (с новым categoryId).
В AngularJS я бы сделал для $watch
переменной. Каков наилучший способ справиться с этим?
источник
Ответы:
На самом деле, существует два способа обнаружения и обработки при изменении входа дочернего компонента в angular2 +:
Ссылки на документацию: ngOnChanges, SimpleChanges, SimpleChange
Demo Пример: посмотрите на этот плункер
Ссылка на документацию: смотрите здесь .
Пример демо: Посмотрите на этот плункер .
Какой подход вы должны использовать?
Если ваш компонент имеет несколько входов, то, если вы используете ngOnChanges (), вы получите все изменения сразу для всех входов в ngOnChanges (). Используя этот подход, вы также можете сравнить текущие и предыдущие значения входных данных, которые изменились, и принять соответствующие меры.
Однако, если вы хотите что-то сделать, когда изменяется только один отдельный вход (и вас не волнуют другие входные данные), тогда может быть проще использовать установщик свойства ввода. Однако этот подход не предоставляет встроенного способа сравнения предыдущих и текущих значений измененного ввода (что можно легко сделать с помощью метода жизненного цикла ngOnChanges).
РЕДАКТИРОВАТЬ 2017-07-25: ОБНАРУЖЕНИЕ ИЗМЕНЕНИЯ УГЛОВОГО ИЗМЕНЕНИЯ МОЖЕТ ЕЩЕ НЕ ПОЖАРИТЬСЯ ОТ НЕКОТОРЫХ ОБСТОЯТЕЛЬСТВ
Обычно обнаружение изменений для setter и ngOnChanges срабатывает всякий раз, когда родительский компонент изменяет данные, которые он передает дочернему, при условии, что данные являются примитивным типом данных JS (строка, число, логическое значение) . Однако в следующих сценариях он не сработает, и вам придется предпринять дополнительные действия, чтобы заставить его работать.
Если вы используете вложенный объект или массив (вместо примитивного типа данных JS) для передачи данных от Parent к Child, обнаружение изменений (с использованием либо setter, либо ngchanges) может не сработать, что также упоминается в ответе пользователя: muetzerich. Решения смотрите здесь .
Если вы изменяете данные вне углового контекста (то есть извне), то angular не будет знать об изменениях. Возможно, вам придется использовать ChangeDetectorRef или NgZone в вашем компоненте, чтобы постоянно информировать о внешних изменениях и тем самым запускать обнаружение изменений. Обратитесь к этому .
источник
doSomething
метод и взять 2 аргумента новых и старых значений перед установкой нового значения другим способом. будет сохранять старое значение перед установкой и вызывать метод после этого.Используйте
ngOnChanges()
метод жизненного цикла в вашем компоненте.Вот документы .
источник
MyComponent.myArray = []
, но если входное значение изменено, напримерMyComponent.myArray.push(newValue)
,ngOnChanges()
не запускается. Есть идеи о том, как запечатлеть это изменение?ngOnChanges()
не вызывается, когда вложенный объект изменился. Может быть, вы найдете решение здесьЯ получал ошибки в консоли, а также в компиляторе и IDE при использовании
SimpleChanges
типа в сигнатуре функции. Чтобы избежать ошибок, используйтеany
ключевое слово в подписи.РЕДАКТИРОВАТЬ:
Как указал Джон ниже, вы можете использовать
SimpleChanges
сигнатуру при использовании скобочных обозначений, а не точечных.источник
SimpleChanges
интерфейс вверху файла?<my-user-details [user]="selectedUser"></my-user-details>
). Это свойство доступно из класса SimpleChanges путем вызоваchanges.user.currentValue
. Уведомлениеuser
привязано во время выполнения и не является частью объекта SimpleChangesngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log('onChanges - myProp = ' + changes['myProp'].currentValue); }
Самый безопасный выбор должен пойти с общей службой вместо части с
@Input
параметром. Кроме того,@Input
параметр не обнаруживает изменения в сложном типе вложенных объектов.Простой пример службы выглядит следующим образом:
Вы можете использовать аналогичную реализацию в других компонентах, и все ваши комментарии будут иметь одинаковые общие значения.
источник
@Input
Параметр @JoshuaKemmerer не обнаруживает изменений в сложном типе вложенных объектов, но в простых нативных объектах.Я просто хочу добавить, что есть еще один хук Lifecycle,
DoCheck
который будет полезен, если@Input
значение не является примитивным значением.У меня есть Array как,
Input
так что это не вызываетOnChanges
событие при изменении содержимого (потому что проверка, которую выполняет Angular, является «простой» и не глубокой, поэтому Array по-прежнему является Array, даже если содержимое в Array изменилось).Затем я реализую некоторый пользовательский код проверки, чтобы решить, хочу ли я обновить свое представление с измененным массивом.
источник
пожалуйста, попробуйте использовать этот метод. Надеюсь это поможет
источник
Вы также можете иметь заметку, которая запускает изменения в родительском компоненте (CategoryComponent) и делать то, что вы хотите сделать в подписке в дочернем компоненте. (videoListComponent)
источник
Здесь ngOnChanges будет срабатывать всегда, когда изменяется ваше входное свойство:
источник
Это решение использует прокси- класс и предлагает следующие преимущества:
ngOnChanges()
Пример использования:
Вспомогательная функция:
источник
Если вы не хотите использовать ngOnChange, реализуйте метод og onChange (), вы также можете подписаться на изменения определенного элемента с помощью события valueChanges , ETC.
});
markForCheck (), написанный из-за использования в этом объявлении:
источник
Вы также можете просто передать EventEmitter как Input. Не совсем уверен, что это лучшая практика, хотя ...
CategoryComponent.ts:
CategoryComponent.html:
И в VideoListComponent.ts:
источник