Привязать событие клика от одного компонента к другому

Возможно ли в Angular динамически привязать событие щелчка от компонента к существующему компоненту на странице. Для иллюстрации я прилагаю этот снимок экрана.

Приложение теперь состоит из 4 простых компонентов; Один компонент оболочки, который определяет глобальный макет, в компоненте оболочки у меня есть компонент заголовка (синий контур) и компонент навигации (красный контур). Зеленый компонент - это компонент, загруженный текущим маршрутом.

Я обновляю компонент навигации с помощью простой службы, например:

@Injectable({ providedIn: 'root' })
export class NavigationService {

  private titleSource = new Subject<string>();
  private actionsSource = new Subject<ActionButton[]>();
  private menuItemsSource = new Subject<MenuItem[]>();

  title = this.titleSource.asObservable();
  actions = this.actionsSource.asObservable();
  menuItems = this.menuItemsSource.asObservable();

  constructor() {
  }

  setTitle(title: string) {
    this.titleSource.next(title);
  }

  setActions(actions: ActionButton[]) {
    this.actionsSource.next(actions);
  }

  setMenuItems(menuItems: MenuItem[]) {
    this.menuItemsSource.next(menuItems);
  }
}

Компонент навигации просто использует эту службу следующим образом:

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html'
})
export class NavigationComponent implements OnInit {
  title: string = "";
  actions: ActionButton[] = [];
  menuItems: MenuItem[] = [];

  constructor(private navigation: NavigationService)  { 
    navigation.title.subscribe((title) => this.title = title);
    navigation.actions.subscribe((actions) => this.actions = actions);
    navigation.menuItems.subscribe((menuItems) => this.menuItems = menuItems);
  }
}

И отображает это так:

<div class="navigation">
    <div *ngIf="title.length" class="navigation__title">
        <h1>{{title}}</h1>
    </div>
    <div class="navigation__menu">
        <ul>
            <li *ngFor="let menuItem of menuItems"  [routerLinkActive]="['active']">
                <a routerLink="{{menuItem.path}}">{{menuItem.title}}</a>
            </li>
        </ul>
    </div>
    <div class="navigation__actions">
      <a *ngFor="let actionButton of actions" class="btn btn--primary">{{actionButton.title}}</a>
    </div>
</div>

Затем в активированном в данный момент компоненте (зеленом) я устанавливаю заголовок и такие элементы, как этот

 ....

  constructor(private employeeService: EmployeeService, private navigation: NavigationService, private drawerService: NzDrawerService) { 
    navigation.setTitle('');
    navigation.setActions([
      {
        path: '',
        title: 'Add Employee'
      }
    ]);
    navigation.setMenuItems([
      {
        path: '/employees',
        title: 'Employees'
      },
      {
        path: '/teams',
        title: 'Teams'
      }
    ]);
  }
  ....

В этом же активном компоненте я также определил этот метод:

  createEmployee() {
    const drawer = this.drawerService.create<CreateEmployeeComponent>({
      nzContent: CreateEmployeeComponent,
      nzClosable: false,
      nzWidth: '33%',
    });

    drawer.afterClose.subscribe(data => {
      this.loadEmployees();
    });
  }

Теперь мой вопрос: можно ли каким-либо образом вызвать этот метод, когда я нажимаю кнопку, отображаемую в моем компоненте навигации. А также установите его динамически из текущего активированного компонента, как я уже делаю для заголовка и элементов навигации.


person yohik36059    schedule 30.03.2020    source источник


Ответы (1)


Вы можете использовать Object orientation для этого

Создать базовый класс

export class EmployeeCreateClass {
 createEmployee() {
    const drawer = this.drawerService.create<CreateEmployeeComponent>({
      nzContent: CreateEmployeeComponent,
      nzClosable: false,
      nzWidth: '33%',
    });

    drawer.afterClose.subscribe(data => {
      this.loadEmployees();
    });
  }
}

Заставьте Navigation расширить его:

export class NavigationComponent extends EmployeeCreateClass implements OnInit {
...

HTML-код для навигации:

<button (click)="createEmployee()"></button>

То же самое и с компонентами:

export class CurrentComponent extends EmployeeCreateClass implements OnInit {
....

HTML:

<button (click)="createEmployee()"></button>

================================================== ====== Извините, я неправильно понял вопрос, вы, вероятно, можете его уточнить, но, возможно, что-то вроде этого:

@Injectable({ providedIn: 'root' })
export class NavigationService {

  private titleSource = new Subject<string>();
  private actionsSource = new Subject<ActionButton[]>();
  private menuItemsSource = new Subject<MenuItem[]>();
  private actionItems = [];

  title = this.titleSource.asObservable();
  actions = this.actionsSource.asObservable();
  menuItems = this.menuItemsSource.asObservable();

  constructor() {
  }

  setTitle(title: string) {
    this.titleSource.next(title);
  }

  setActions(actions: ActionButton[]) {
   this.actionItems = [];
    for(let i = 0; i < actions.length; i++) {
      this.actionItems.push(new Subject<void>());
    }
    this.actionsSource.next(actions);
  }

  setMenuItems(menuItems: MenuItem[]) {
    this.menuItemsSource.next(menuItems);
  }
}

Затем в HTML-коде навигации:

      <a *ngFor="let actionButton of actions; let i = index" class="btn btn--primary" (click)="actionButtonClicked(i)">{{actionButton.title}}</a>

Затем в ТС навигации:

  actionButtonClicked(i: number) {
    this.navigation.actionItems[i].next();
  }

Затем в вашем компоненте:

navigation.setActions([
      {
        path: '',
        title: 'Add Employee'
      }
    ]);
// the bottom should get triggered every time actionButton gets `next`ed.
navigation.actionItems[0].subscribe(_ => { this.createEmployees(); });

Имейте в виду, что я делаю это сразу без IDE, но, надеюсь, это поможет вам.

person AliF50    schedule 30.03.2020
comment
В этом есть смысл, но я больше искал способ сделать это динамически. Я бы просто позвонил NavigationService из своего CurrentComponent и передал событие щелчка. как navigation.setActions([{ action: 'currentComponent.createEmployee()', title: 'Add Employee' } ]);. Потому что с вашим подходом мне понадобится связка if-statement для скрытия / отображения кнопок на основе текущего маршрута / компонента. Это как-то возможно? - person yohik36059; 31.03.2020
comment
Я не уверен. Возможно, лучшим подходом было бы переместить createEmployee в службу, а затем внедрить эту службу в любой компонент, который нуждается в этой функции. - person AliF50; 31.03.2020
comment
Да, конечно, но все же как мне динамически обновить компонент навигации для вызова этой службы? - person yohik36059; 31.03.2020
comment
Отлично, я искал что-то подобное, спасибо - person yohik36059; 31.03.2020