#arrays #angular #typescript #ngfor #ngonchanges
Вопрос:
У меня есть свой app.component
со списком объектов
class Hero {
alias: string;
constructor(public firstName: string,
public lastName: string) {
}
}
class AppComponent {
...
heroes: Hero[] = [
new Hero("foo", "bar")
];
...
onHeroChange($event: Hero, index: number): void {
this.heroes[index] = $event;
}
<div *ngFor="let hero of heroes; let index=index">
<hero [hero]="hero" (heroChange)="onHeroChange($event, index)"></hero>
</div>
ГероКомпонент-это
export class HeroComponent {
@Input()
set hero(newValue: Hero) {
this._hero = newValue;
this.showAlias = !!newValue.alias;
}
get hero(): Hero {
return this._hero;
}
@Output() heroChange: EventEmitter<Hero> = new EventEmitter<Hero>();
showAlias: boolean = !1;
private _hero: Hero;
//
@HostListener('click')
onHeroClick(): void {
this.hero.alias = `alias_${ new Date()}`;
console.info('HERO TO EMIT', this.hero);
this.heroChange.emit(this.hero);
}
}
Моя проблема в том , что даже при назначении измененного героя внутри app.component
, set hero
внутренняя hero.component
часть не вызывается, поэтому showAlias
в примере не обновляется, и я не вижу псевдонима в hero.component
.
Нужно ли мне форсировать ngFor, назначив весь массив?
Может быть, обходным путем можно было бы удалить объект из массива, а затем вставить его снова? Хотя это звучит как бесполезное вычисление.
Примечание: это всего лишь пример, это не то, над чем я действительно работаю, так что что-то вроде
Обновите реквизит showAlias в методе onHeroClick
или
Назначьте героя в компоненте hero.
к сожалению, это не решает проблему. Мне нужно, чтобы изменения происходили снаружи, потому что происходят другие вещи.
Может быть еще один вариант изменения обнаружения onPush
и маркировки для проверки вручную?
Ответ №1:
Вы не устанавливаете новое hero
, вы просто изменяете свойство существующего:
this.hero.alias = `alias_${ new Date()}`;
Это не увольняет сеттера. Измените строку вот так:
this.hero = {...this.hero, alias: `alias_${ new Date()}`};
Комментарии:
1. Спасибо, но я уже упоминал, что это ничего не решит. Изменение должно быть отражено в массиве, это приведет к слишком раннему запуску сеттера внутри компонента hero.component.
2. Возможно, я ошибаюсь, но мне кажется, что вы ничего не задаете. С чего бы это увольнять сеттера? Вы изменяете
hero
объектHeroComponent
, испускаете тот же объектAppComponent
, которому снова передаете тот же объектHeroComponent
. Ссылка не изменилась, сеттер не вызывался. Почему вы ожидаете чего-то другого?3. Если вы посмотрите на
app.component
него, то увидите, что там назначен новый герой. И я не ожидаю, что сеттер выстрелит. Я прошу чистого решения, чтобы снова запустить ngFor для печати.4. Это не новый герой. Это ссылка на того же самого старого (только что измененного) героя, исходящего от
HeroComponent
. Снова начинаетсяngFor
печать, но герой, которыйHeroComponent
появляется в этом новомngFor
цикле, тот же, что и раньше. Для обнаружения угловых изменений по умолчанию используется ссылка. Чтобы изменить ссылку в AppComponent, вы можете сделать это:this.heroes[index] = {...$event};
5. В зависимости от сложности вашего реального варианта использования другим решением было бы определить отдельный компонент для псевдонима. Поскольку это будет связано со
alias
свойством (а не со всем объектом), обнаружение изменений будет работать без необходимости рассматриватьhero
как неизменяемое: https://stackblitz.com/edit/angular-ivy-yhpv3j