使用服务跨组件通信
介绍
在任何 Angular 应用中,组件都是基本构建块。Angular 组件为我们提供应用的视图/模板。它们还管理绑定到这些视图的数据。以下是任何应用中最常见的一些数据共享场景,其中两个或多个组件在它们之间共享信息:
- 父组件到子组件:使用@Input装饰器(属性绑定)
- 子组件到父组件:使用@Output 装饰器和 EventEmitter(事件绑定)
- 兄弟或不相关的组件之间:使用 Angular 共享服务
让我们通过示例来看一下每个场景。
我们的示例设置
在我们的示例中,我们将向用户显示课程列表,并且在选择任何课程后,用户将看到该课程的详细信息。
下面是我们的 app.module.ts 的样子:
//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { CourseListComponent } from './courses/course-list/course-list.component';
import { CourseItemComponent } from './courses/course-list/course-item/course-item.component';
@NgModule({
declarations: [
AppComponent,
CourseListComponent,
CourseItemComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
我们的课程模型如下:
//course.model.ts
export class Course {
public name: string;
public description: string;
public courseImagePath: string;
constructor(name: string, desc: string, courseImagePath: string) {
this.name = name;
this.description = desc;
this.courseImagePath = imagePath;
}
}
我们的根组件或应用程序组件包含课程列表组件,如下所示:
import { Component, OnInit } from '@angular/core';
import { Course } from './course.model';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
selectedCourse: Course;
constructor() { }
ngOnInit() {
}
}
以下是应用程序组件的 HTML 代码:
<div class="row">
<div class="col-md-5">
<app-course-list
(courseWasSelected)="selectedCourse = $event"></app-course-list>
</div>
<div class="col-md-7">
<app-course-detail
*ngIf="selectedCourse; else infoText"
[course]="selectedCourse"></app-course-detail>
<ng-template #infoText>
<p>Please select any course to view details!</p>
</ng-template>
</div>
</div>
此外,我们的课程列表组件如下所示:
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { Course } from '../course.model';
@Component({
selector: 'app-course-list',
templateUrl: './course-list.component.html',
styleUrls: ['./course-list.component.css']
})
export class CourseListComponent implements OnInit {
courses: Course[] = [
new Course('Angular Course 1', 'This is simply a practice Angular course 1', 'http://via.digital.com/350x150.jpeg'),
new Course('Angular Course 2', 'This is simply a practice Angular course 2', 'http://via.digital.com/350x150'),
new Course('Angular Course 3', 'This is simply a practice Angular course 3', 'http://via.digital.com/350x150')
];
constructor() { }
ngOnInit() {
}
}
以下是模板:
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success">New Course</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<app-course-item></app-course-item>
</div>
</div>
以下是我们的课程项目组成部分:
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { Course } from '../../course.model';
@Component({
selector: 'app-course-item',
templateUrl: './course-item.component.html',
styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
课程项目模板:
<a
href="#"
class="list-group-item clearfix">
<div class="pull-left"><!--Display Course Name/Desc here --></div>
<span class="pull-right"><!--Display Course Image here--></span>
</a>
通过上述设置,让我们看看这些组件之间通信的不同方式。
使用 @Input 装饰器(属性绑定)
这是最常见的数据共享方式。它使用 @Input() 装饰器通过模板传递数据。@Input 装饰器允许父组件将其属性绑定到子组件,从而使子组件可以访问其数据。这些绑定实际上是对父组件属性的引用。
假设我们想将“课程”信息从 CourseListComponent 传递到 CourseItemComponent。
以下是我们如何更新课程列表模板:
<div class="row">
<div class="col-xs-12">
<app-course-item
*ngFor="let courseEl of courses"
[course]="courseEl"></app-course-item>
</div>
</div>
您可以看到,当我们遍历课程列表时,我们将该遍历的单个课程元素传递给 CourseItemComponent。因此,我们将父 CourseListComponent 中的子 CourseItemComponent 的“course”属性绑定起来。
现在,为了做到这一点,我们必须在子 CourseItemComponent 上使用 @Input 装饰器。因此,我们更新后的 CourseItemComponent 将如下所示:
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { Course } from '../../course.model';
@Component({
selector: 'app-course-item',
templateUrl: './course-item.component.html',
styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {
@Input() course: Course;
constructor() { }
ngOnInit() { }
}
我们现在可以在 CourseItemComponent 模板中呈现课程名称/描述/图像,如下所示:
<a
href="#"
class="list-group-item clearfix">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ course.name }}</h4>
<p class="list-group-item-text">{{ course.description }}</p>
</div>
<span class="pull-right">
<img
[src]="course.courseImagePath"
alt="{{ course.name }}"
class="img-responsive"
style="max-height: 50px;">
</span>
</a>
使用 @Output 装饰器和 EventEmitter (事件绑定)
在某些情况下,我们希望能够将数据从子组件发射回父组件。子组件公开了一个 EventEmitter 属性,每当子组件上发生任何操作/事件时,该属性都会发射数据。
在我们上面看到的相同例子中,假设每当点击任何单个课程的链接时,我们都希望通知父组件。
因此,我们将在 CourseItemComponent 上添加一个“点击”事件。该模板的更新方式如下:
<a
href="#"
class="list-group-item clearfix"
(click)="onSelected()">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ course.name }}</h4>
<p class="list-group-item-text">{{ course.description }}</p>
</div>
<span class="pull-right">
<img
[src]="course.courseImagePath"
alt="{{ course.name }}"
class="img-responsive"
style="max-height: 50px;">
</span>
</a>
现在,从 CourseItemComponent 类型脚本代码中,我们希望能够发出此事件并将该事件通知父组件。如果我们希望“courseSelected”可从外部监听,则必须使用 @Output 装饰器。这将允许访问此属性上的 emit() 方法。此外,在创建 EventEmitter 实例时,我们可以选择定义可能发出的任何事件数据。
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { Course } from '../../course.model';
@Component({
selector: 'app-course-item',
templateUrl: './course-item.component.html',
styleUrls: ['./course-item.component.css']
})
export class CourseItemComponent implements OnInit {
@Input() course: Course;
@Output() courseSelected = new EventEmitter<Course>();
constructor() { }
ngOnInit() { }
onSelected() {
this.courseSelected.emit(this.course);
}
}
通过上述更改,我们现在可以监听父 CourseListComponent 上的“courseSelected”事件,如下所示。
<div class="row">
<div class="col-xs-12">
<button class="btn btn-success">New Course</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<app-course-item
*ngFor="let courseEl of courses"
[course]="courseEl"
(courseSelected)="onCourseSelected(courseEl)"></app-course-item>
</div>
</div>
此外,我们现在可以访问 CourseListComponent 打字稿代码中的“课程”。
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { Course } from '../course.model';
@Component({
selector: 'app-course-list',
templateUrl: './course-list.component.html',
styleUrls: ['./course-list.component.css']
})
export class CourseListComponent implements OnInit {
courses: Course[] = [
new Course('Angular Course 1', 'This is simply a practice Angular course 1', 'http://via.digital.com/350x150.jpeg'),
new Course('Angular Course 2', 'This is simply a practice Angular course 2', 'http://via.digital.com/350x150')
];
constructor() { }
ngOnInit(<span cl
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~