【问题标题】:Bind click event from one component to another one将一个组件的点击事件绑定到另一个组件
【发布时间】:2020-07-11 07:52:20
【问题描述】:

是否可以在 Angular 中将组件的点击事件动态绑定到页面上的现有组件。 为了说明,我包括了这个screenshot

该应用现在由 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();
    });
  }

现在我的问题是,当我单击导航组件上呈现的按钮时,是否可以调用此方法。并且还可以从当前激活的组件中动态设置它,就像我已经为标题和导航项所做的那样

【问题讨论】:

    标签: angular typescript angular8 angular-services angular-components


    【解决方案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>
    
    

    然后在导航的TS中:

      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 的情况下一次性完成的,但希望它对您有所帮助。

    【讨论】:

    • 这是有道理的,但我更多的是寻找一种动态的方法。我只需从我的CurrentComponent 调用NavigationService 并传递点击事件。喜欢navigation.setActions([{ action: 'currentComponent.createEmployee()', title: 'Add Employee' } ]);。因为使用您的方法,我将不得不有一堆 if 语句来隐藏/显示基于当前路由/组件的按钮。这有可能吗?
    • 我不确定。也许更好的方法是将createEmployee 移动到服务中,然后将该服务注入到需要此功能的任何组件。
    • 当然可以,但我仍然要如何动态更新导航组件以调用此服务?
    • 完美,我正在寻找这样的东西,谢谢
    猜你喜欢
    • 2020-02-29
    • 2020-02-20
    • 1970-01-01
    • 2017-10-07
    • 2017-03-30
    • 1970-01-01
    • 2021-02-06
    • 2011-01-15
    • 1970-01-01
    相关资源
    最近更新 更多