@tonx92

Angular 2+ Почему родительский компонент не видит EventEmitter .emit()?

Родительский компонент:
import { Component, Input, Output } from '@angular/core';

@Component({
    selector: 'sluhcrm',
    template: `
<h1>{{title}}</h1>
<main-menu (TestEvent)="MenuClick($event)"></main-menu>
`,
    styleUrls: ['app.component.css']
})

export class AppComponent {
    title = 'MyTitle';

    MenuClick(name){
        alert(1);
        console.log(name);
    }
}


Дочерний компонент:
import { Component, Input, Output, EventEmitter } from '@angular/core';

const menu = [
    {'name':'Главная', 'url':'/', 'active':1},
    {'name':'Районы', 'url':'/', 'active':0},
    {'name':'Точки', 'url':'/', 'active':0},
    {'name':'Посещения', 'url':'/', 'active':0},
    {'name':'Пользователи', 'url':'/', 'active':0}
]

@Component({
    selector: 'main-menu',
    template: `
<div class="menu">
    <div class="punkt" *ngFor="let punkt of menu" [class.active]="punkt.active">
        <a (click)="selectMenu(punkt)">
            {{punkt.name}} {{punkt.active ? '<': ''}}
        </a>
    </div>
</div>
`,
    styleUrls: ['menu.component.css']
})

export class MenuComponent {
    
    @Output('TestEvent') asd = new EventEmitter();

    menu = menu;

    selectMenu(punkt){
        menu.forEach(element => {
            element.active = 0;
        });

        punkt.active = 1;
        this.asd.emit(punkt.name);
    }
    
}


Перепробовал уже все что смог найти, по непонятным мне причинам, родительский компонент отказывается отлавливать событие TestEvent, нет ошибок, логи пустые, он тупо его игнорирует. selectMenu отрабатывает себя нормально.
  • Вопрос задан
  • 614 просмотров
Решения вопроса 1
@tonx92 Автор вопроса
Спасибо, помогло разобраться.
Причина была в следующем, в модуле компонент с меню был в bootstrap, как только его от туда убрал output заработал, кто-нибудь может мне объяснить почему так происходит?
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";

import { AppComponent } from './main/app.component';
import { MenuComponent } from './main/menu/menu.component';

@NgModule({
  imports: [BrowserModule, FormsModule],
  declarations: [AppComponent, MenuComponent],
  bootstrap: [AppComponent, >>MenuComponent<<]
})

export class AppModule { }
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@antoart
Web developer
Слушай, классный вопрос.

Заставил пошерстить документацию и применить дедукцию )))
В итоге вот тебе развернутый ответ.

1. Urukhayy дал частично правильный ответ. Ну, то есть он корректно заметил, что запись вида
@Output() TestEvent = new EventEmitter();
предпочтительней, чем запись вида
@Output('eventEmitterAlias') blaBlaBla = new EventEmitter();

Ангулярщики сами уже не рекомендуют использовать алиасы, даже tslint в нормальных проектах ругается на это и говорит, что способ когда указывается alias не очень крут, и лучше таким способом не пользоваться. Сложно будет отследить эти методы в коде, и уже точно невозможно будет в студии "провалиться" в код.
Но ты можешь так делать, чисто технически :):)
Да и вообще в Typescript принято писать в camelCase стиле (testEvent). PascalCase это уже больше на C# похоже.

2. По существу.
Из документации по ангуляр (https://angular.io/guide/bootstrapping#the-bootstr... стало ясно, что те компоненты, которые прописаны в bootstrap создаются при запуске приложения. Каждый с нуля со своей структурой дочерних компонентов.
Что это значит для нас?
Ты создал AppComponent, в котором создался MainComponent со всеми нужными связями (@Output). А дальше система создала отдельно MainComponent и поместила куда следует, оторванного от родителя, сиротинушку такого. Связь потеряна. В этом и было дело.

А чтобы увидеть это - в MainComponent добавь
constructor() {
    console.log('main component create');
}

И проследи, сколько раз компонент создался.

Заключение:
Вопрос огонь! Поработай над стилем. Никто не пишет punkt. Представь, что заказчик иностранец. (menuPoint, link, item, point) - item супер вариант ))). Почитай про style-guide ангуляр. Поможет найти общий язык с другими ангулярщиками :):)
Ответ написан
Комментировать
@Urukhayy
В дочернем компоненте замените на это:
@Output() TestEvent = new EventEmitter();

И в функции selectMenu вызывайте:
this.TestEvent.emit(punkt.name)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы