#angular #typescript #ngonchanges
#angular #typescript #ngonchanges
Вопрос:
У меня есть родительская страница, которая передает user
данные дочернему компоненту следующим образом:
<ng-container *ngIf="leaderboard">
<app-leaderboard-preview [user]="user" (click)="goToLeaderboard()"></app-leaderboard-preview>
</ng-container>
Родительская страница ngOnInit()
подписывается на observable, который возвращает пользовательский объект и устанавливает user
переменную (я удалил другие нерелевантные запросы из combineLatest
):
combineLatest([this.userQuery$]).subscribe((results) => {
Promise.all([this.parseUser(results[4])])
})
Насколько я понимаю, он ngOnChanges()
не сработает, если не будет создан новый объект, поэтому я назначаю новый пользовательский объект в качестве нового объекта для передачи app-leaderboard-preview
компоненту с помощью Object.assign()
parseUser(user) {
return new Promise((resolve) => {
if(user) {
this.user = Object.assign({}, user);
resolve(user);
} else {
resolve(user);
}
})
}
Это отлично загружает компонент, но рейтинг пользователя может измениться, поэтому, когда пользователь проводит пальцем вниз, чтобы обновить страницу, значение должно быть обновлено, но компонент не обновляется. Я использую следующий код (почти точную копию приведенного выше) для обновления страницы (без жесткой перезагрузки).
doRefresh(event) {
if (this.user) {
//user
this.userQuery$ = this.db.query$(`user/find?id=${this.user.id}`);
combineLatest([this.userQuery$]).subscribe((results) => {
Promise.all([this.parseUser(results[4])])
})
}
Который затем запускает parseUser
метод для обновления user
объекта, который app-leaderboard-preview
использует.
Таким образом, это должно вызвать ngOnChanges, потому что я передаю «новый» объект компоненту. Что я упускаю?
Комментарии:
1. Где находится код, который вы переназначаете
this.user
2. @RezaRahmati
this.user
переназначается при каждом запускеparseUser()
метода, который размещен в третьем блоке кода3. Можете ли вы поделиться этим кодом, поскольку он здесь не представлен
4. @RezaRahmati Это 3-й блок кода в его вопросе.
5. Я консольно вошел в свой ngOnChanges (), чтобы определить, когда он запущен, и он запускается только при инициализации компонента и никогда при пролистывании для перезагрузки (просто к вашему сведению)
Ответ №1:
Редактировать
После некоторого перехода туда и обратно Джордан выяснил, что у него был асинхронный канал, назначенный переменной user, которая переопределяла его изменения для this.user.
*ngIf = user$ | async as user
Оригинальный ответ
Object.assign({}, объект) должен работать. Протестировано на Angular 7.
this.user = Object.assign({}, user);
.. или, если вы используете Lodash, вы можете сделать.
this.user = _.clone(user);
this.user = _.cloneDeep(user);
https://lodash.com/docs/4.17.11#clone
https://lodash.com/docs/4.17.11#cloneDeep
Демонстрация Stackblitz:https://stackblitz.com/edit/ngonchangeswithobject
Комментарии:
1. спасибо, что помогли мне отладить это. Что-то определенно не так для меня, потому что я только что создал совершенно отдельный метод для анализа пользователя при пролистывании вниз для обновления, называемый `parseUser1(). Я установил user равным null в этом методе, я пробовал как getters, так и setters и ngOnChanges(), и компонент ничего не перехватил после инициализации. Если у вас закончились идеи, не беспокойтесь, я продолжу тестировать новые вещи
2. Извините, я забыл упомянуть. Этот метод запускает ngOnChanges().
3. Хм .. какую версию angular вы используете?
4. У меня есть два входа в моем компоненте, user и rank. Я попытался использовать Object.create() для ввода ранга, и он правильно запустил ngonchanges. Вопрос, который я опубликовал здесь, касается пользовательского ввода, и я попытался использовать Object.create(user) для запуска ngonchanges пользовательского ввода, но по какой-то причине он не запускается, хотя я передаю новый объект на вход. Имеет ли это больше смысла? Извините за путаницу :/
5. Серьезно, большое спасибо, что обратили на это внимание. В итоге я разобрался с этим, и это было действительно глупо. У меня есть
ng-container
с асинхронностью*ngIf = user$ | async as user
, внутри которой находится компонент. Это асинхронноеuser
присвоение переменной в контейнере html имело приоритет над тем,user
которое я назначал в своем родительском компоненте. Я очень сожалею, что отнял у вас время, но благодаря вашей помощи я смог найти проблему.
Ответ №2:
Я сталкивался с этой же проблемой раньше, и мне любопытно, знает ли кто-нибудь, как ее решить.
Способ, которым я обошел это, заключался в использовании методов get() set() для моей входной переменной, подобных этому. Это не самое лучшее решение, особенно если у вас более одной входной переменной.
private _user: any;
@Input()
set user(value: any) {
this._user = value;
// run ngOnChanges stuff here
this.ngOnChanges();
}
get user(): any {
return this._user;
}
Комментарии:
1. Я как бы искал альтернативу получения / установки, но подумал, что это возможно только для отдельных реквизитов, даст этому шанс. Я думаю, что в вашем текущем коде есть некоторые опечатки в скобках у пользователя
getter
, просто предупреждаю!2. @JordanLewallen раздражает, что в их документации onChanges не приводится пример с объектом, а приводится только один для примитива. Возможно, эта проблема была исправлена в более поздних версиях, но мой проект Angular 6.0.1 по-прежнему не работает, когда я проверял последний раз.
3. поэтому я попытался «очистить»
user
переменную непосредственно перед ее назначением в моемparseUser()
методе, выполнив:this.user = null
чуть вышеthis.user = user
, но даже это, похоже, не помогает при использовании get / set .4. Я вернулся и снова посмотрел на свой код, где я делал это, и, похоже, я решил это по-другому, чем я думал. Поскольку у меня была служба, организующая изменения, я добавил наблюдаемый, на который я мог подписаться, который срабатывает в любое время, когда у меня были изменения. Извините, что потратил ваше время на это. Надеюсь, мой другой ответ сработает для вас. Приветствия.