#angular #angular5 #angular-directive #angular-dynamic-components #angular-event-emitter
#angular #angular5 #angular-директива #angular-dynamic-components #angular-событие-эмиттер
Вопрос:
У меня есть слайдер, в котором динамически создаются элементы — это дочерние компоненты.
Родительский шаблон, где находится ng-контейнер для слайдера:
<div id="slider-wrapper">
<ng-container appSliderForm *ngFor="let question of questionsInSlider"
[questionTest]="question" (onRemove)="removeQuestion($event)">
</ng-container>
</div>
Эти дочерние компоненты создаются директивой appSliderForm:
@Directive({
selector: '[appSliderForm]'
})
export class FormSliderDirective implements OnInit {
@Input()
questionTest: QuestionInSlider;
constructor(private resolver: ComponentFactoryResolver, private container: ViewContainerRef) {}
ngOnInit(): void {
const factory = this.resolver.resolveComponentFactory<TestQuestionInSliderComponent>(TestQuestionInSliderComponent);
const component = this.container.createComponent(factory);
component.instance.questionTest = this.questionTest;
component.instance.ref = component;
}
}
В моем дочернем компоненте у меня есть функция remove для удаления самого себя из слайдера.
@Component({
selector: 'app-test-question-in-slider',
templateUrl: './test-question-in-slider.component.html',
styleUrls: ['./test-question-in-slider.component.less']
})
export class TestQuestionInSliderComponent {
questionTest: QuestionInSlider;
ref: any;
@Output() public onRemove = new EventEmitter<QuestionInSlider>();
constructor(private builderService: FormBuilderService) {}
/**
* Chosen question from slider will be displayed.
*/
choose(): void {
this.questionTest.chosen = true;
this.builderService.handlerQuestionFromSlider(this.questionTest);
}
remove(): void {
this.onRemove.emit(this.questionTest);
this.ref.destroy();
}
isChosen() {
return {'chosen': this.questionTest.chosen};
}
getBorderTopStyle() {
return {'border-top': `4px solid ${this.questionTest.color}`};
}
}
Когда эта функция удаления вызывается нажатием на значок удаления в шаблоне дочернего компонента, я хотел бы передать событие, чтобы сообщить родительскому компоненту о выполнении других операций в соответствии с, но функция removeQuestion в родительском компоненте не вызывается.
Не могли бы вы посоветовать мне, пожалуйста, почему не вызывается эта функция removeQuestion?
removeQuestion(question: QuestionInSlider) {
console.log(question);
}
Обновить
Я отладил его в браузере Chrome и увидел, что у моего объекта EventEmitter onRemove не было никаких значений в его свойстве массива наблюдателей, когда для объекта onRemove была вызвана функция emit.
this.onRemove.emit(this.questionTest);
Ответ №1:
Проблема в том, что у FormSliderDirective
нет onRemove
события. Для того, чтобы ваш код работал, вам необходимо добавить событие в директиву и подписаться на него на событие внутреннего компонента. Таким образом, всякий раз, когда срабатывает внутреннее событие, оно будет распространяться наружу.
Вот пример того, как вы можете добавить это в свою директиву:
@Directive({
selector: '[appSliderForm]'
})
export class FormSliderDirective implements OnInit {
@Input() questionTest: QuestionInSlider;
@Output() public onRemove = new EventEmitter<QuestionInSlider>();
constructor(private resolver: ComponentFactoryResolver, private container: ViewContainerRef) {}
ngOnInit(): void {
const factory = this.resolver.resolveComponentFactory<TestQuestionInSliderComponent>(TestQuestionInSliderComponent);
const component = this.container.createComponent(factory);
component.instance.questionTest = this.questionTest;
component.instance.onRemove.subscribe(this.onRemove); // this connects the component event to the directive event
component.instance.ref = component;
}
}
Комментарии:
1. Прошу прощения за поздний ответ. Что касается вашего решения, у меня это не работает. Я отладил его и обнаружил, что мой инициализированный объект EventEmitter onRemove в моем TestQuestionInSliderComponent имел свойство observers для пустого массива. Оно не должно содержать никаких значений?
2. Хорошо, спасибо, что подтолкнули меня. Благодаря вам я нашел решение. Это было просто необходимо для изменения вашего решения.
3. Извините за мой поздний ответ. Рад, что вы это поняли. Я допустил ошибку, и, как вы обнаружили, вам нужно переключить подписки. Я обновил свой ответ. Вы можете выполнить прямую подписку, поскольку отправители событий являются субъектами.
Ответ №2:
Возможно, это поможет вам, когда такая же ошибка возникает после применения решения от @AlesD:
ERROR TypeError: Cannot read property 'subscribe' of undefined
Обходной путь работает для меня:
component.instance.onRemove = this.onRemove;