【问题标题】:Angular 4 - invoking child component method from app componentAngular 4 - 从应用组件调用子组件方法
【发布时间】:2017-12-26 02:05:56
【问题描述】:

简而言之,我有一个 Angular 4 应用程序,它的标题包含一个受 android 启发的浮动操作按钮,当单击此按钮时,应在当前活动组件(基本上是页面内容)上执行一个方法。如果这有什么不同,我正在使用 angular 4 路由器,它引起了对 View Child 方法的一些担忧,因为我并不总是确定哪个组件当前处于活动状态,如果可能的话,我想避免添加 #binding 属性到每一个模板。

我已经通过 ViewChild 装饰器、ContentChild 装饰器、事件、服务尝试过这个,到目前为止,绝对没有任何效果,我完全被卡住了。在这一点上,我不确定这是否真的很复杂,或者只是 PEBCAK。

有问题的按钮包含在app.component -

app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  currentUrl: string = null;

  constructor(private router: Router, private currentRoute: ActivatedRoute) {}

  ngOnInit() {
    this.router.events.subscribe((val) => {
      this.currentUrl = this.router.url;
    });
  }
}

app.component.html(为了简洁起见,只是按钮)

<div class="fab-container">
  <button class="btn btn-warning btn-fab" (click)="fabAction()">
    +
  </button>

这里的大致思路是,当这个按钮被点击时,会在子组件上执行fabAction()方法;

@Component({
  selector: 'app-course-list',
  templateUrl: './course-list.component.html',
  styleUrls: ['./course-list.component.scss']
})
export class CourseListComponent implements OnInit {

  courses: Course[];
  showFilter: boolean = false;

  constructor(
    private courseService: CourseService
  ) { }

  ngOnInit(): void {
    this.getCourses();
  }

  getCourses(): void {
    this.courseService.getCourses().then(courses => this.courses = courses);
  }

  // Should execute this method when button is clicked on app component
  fabAction(): void {
    console.log('responding to click on parent component');
    this.showFilter = !this.showFilter;
  }
}

</div>

一文不值的是,当在应用程序组件上单击 fab 按钮时,每个组件都会有自己的动作来执行,有些会打开模式,有些会显示/隐藏东西,有些会重定向,所以真的很高兴能够在组件本身上指定此行为。

阅读有关这方面的官方 angular 文档给我留下的问题多于答案,因此我将其全部重新整理,希望有人能提出更理想的解决方法。

编辑 - 根据要求对app.component.html 进行完整标记

<header *ngIf="currentUrl != '/landing'">
  <div class="brand">
    <img src="/assets/circle-logo.png" />
  </div>
  <nav>
    <div class="page-title">
      <h2>{{ page?.title }}</h2>
      <h4>{{ page?.strapline }}</h4>
    </div>
    <ul class="header-nav">
      <li [routerLink]="['/courses']">Courses</li>
      <li>Dashboard</li>
      <li>Community</li>
      <li>Blog</li>
      <li>About</li>
    </ul>
    <div class="fab-container">
      <button class="btn btn-warning btn-fab" (click)="fabAction()">
        +
      </button>
    </div>
  </nav>
</header>
  <router-outlet></router-outlet>
<app-footer></app-footer>

这是我的应用程序路由模块,我在其中定义了我的路线以及为哪条路线显示哪个组件(如英雄之旅 Angular 4 演示中所做的那样)

const routes: Routes = [
    { path: '', redirectTo: 'landing', pathMatch: 'full' },
    { path: 'landing', component: LandingComponent },
    { path: 'courses', component: CourseListComponent },
    { path: 'course/:id', component: CourseComponent }
];

@NgModule({
    imports: [ RouterModule.forRoot(routes) ],
    exports: [ RouterModule ]
})

export class AppRoutingModule {}

【问题讨论】:

  • 你在哪里创建组件?你能发布更多代码来显示你如何包含子组件
  • 组件正在由 Angular 路由器通过路由器插座显示,我将在原始帖子中添加 app.component.html 的完整标记

标签: angular angular4-router


【解决方案1】:

创建一个具有 RxJS 主题的服务,当按下 FAB 时,您调用 next。然后在任何关心的组件中,您可以subscribe 到主题。

import { Subject } from 'rxjs/Subject'

@Injectable()
export class FabService {
  clickSubject = new Subject();
}

app.component

@Component(...)
export class AppComponent {

  constructor(private fabService: FabService) {}

  fabAction() {
    this.fabService.clickSubject.next();
  }
}

子组件

@Component(...)
export class ChildComponent implements OnInit, OnDestroy {

  private clickSub: Subscription;

  constructor(private fabService: FabService) {}

  ngOnInit() {
    this.clickSub = this.fabService.clickSubject.subscribe(() => {
      // FAB was clicked
    });
  }

  ngOnDestroy() {
    this.clickSub.unsubscribe();
  }
}

我能想到这可能不起作用的唯一情况是,如果您延迟加载功能模块,因为这些将获得 FabService 的单独实例(或您最终调用的任何实例)。我认为有办法解决这个问题,但我想不出来。

【讨论】:

  • 这正是我所需要的,非常感谢!终于可以停止把我的头撞到墙上并取得一些进展:)
【解决方案2】:

要访问与当前路由关联的组件实例,您可以在路由激活时利用 OnActivate 挂钩接口将此实例设置为共享服务:

@Component({
  selector: 'some-cmp',
  template: `
    <div>routerOnActivate: {{log}}</div>
  `})
  export class AppComponent implements OnActivate {
    constructor(private service:RouteStateService) {
    }

    routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
      this.service.setCurrentRouteComponent(this);
    }
 }

那么你就可以通过这种方式访问​​组件实例并访问函数了:

var component = this.service.getCurrentRouteComponent();
component.somefunction()

尚未测试代码,请查看this 了解更多信息。希望这会有所帮助。

【讨论】:

  • RouteStateService 的导入是什么?它似乎不在 Angular 4 或 5 中。
猜你喜欢
  • 2017-12-15
  • 2023-01-08
  • 2017-09-05
  • 2018-04-14
  • 1970-01-01
  • 2016-12-22
  • 2020-10-20
  • 2017-01-29
相关资源
最近更新 更多