Angular 如何在没有子标签的情况下从子组件传递数据到父组件

3

我尝试通过emit从子组件传递数据到父组件,但我没有任何子标签,只是通过路由跳转到子组件,那么如何监听emit的数据?

parent.html

<ul class="list-unstyled multi-steps">
    <li [ngClass]="{ ' is-active': status == 'first' }">
        <span routerLink="/room/specification"></span>
              step1
    </li>
    <li [ngClass]="{ ' is-active ': status == 'second' }">
         <span routerLink="/room/attributes" (click)="onClick()"></span>
              step2
    </li>
</ul>
<div class="content">
    <router-outlet></router-outlet>
</div>

specification-child.ts

 @Output("specificationData") specificationData = new EventEmitter();

     onSubmit() {
      const data = { this.specificationForm.value };
      this.specificationData.emit(data);
     }

如你所见,我无法使用任何子标签。
<child (specificationData)="getData($event)"></child>

所以我该怎么办?

Angular 是哪个版本? - Satish Hawalppagol
@ Satish Hawalppagol 9.1.7 - heliya rb
4个回答

1
在这种情况下,您可以使用单例服务来代替EventEmitter,该服务在父级和子级之间共享变量。

shared.service.ts

@Injectable({ providedIn: 'root' })
export class SharedService {
  private specDataSource = new ReplaySubject<any>(1);
  public specData$ = this.specDataSource.asObservable();

  public setSpecData(data: any) {
    this.specDataSource.next(data);
  }
}

我使用了ReplaySubject(1),它可以缓存/保存最新的值并在订阅时立即发出。您也可以根据需要使用RxJS SubjectBehaviorSubject

specification-child.ts

constructor(private shared: SharedService) { }

onSubmit() {
  this.shared.setSpecData({ this.specificationForm.value });
}

parent.ts

specData: any;
complete$ = new Subject<any>();

constructor(private shared: SharedService) { }

ngOnInit() {
  this.shared.specData$.pipe(
    takeUntil(this.complete$)   // <-- use to close the subscription
  ).subscribe(data => this.specData = data);
}

ngOnDestroy() {
  this.complete$.next();        // <-- close impending subscriptions
}

0

解决这个问题的一个方法是使用Angular服务。请查看文档以了解更多信息。

在服务中,您可以使用EventEmitter,但惯例是使用RxJS Subjects。您可以在服务中创建一个主题实例,并使用它将数据从一个组件传递到任何其他组件。

示例服务如下:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  dataSubject = new Subject<TypeOfData>();

  constructor() { }

}

然后,在子组件中,您可以使用依赖注入来访问服务的实例并从内部发出数据。

  constructor(private dataService: DataService) {}

  onSubmit() {
    const data = { this.specificationForm.value };
    this.dataService.dataSubject.next(data);
  }

然后,在父组件中订阅该主题即可:

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.dataService.dataSubject.subscribe(data => {
      // Do something with the data
    });
  }

你肯定可以将数据的发射作为一个单独的方法提取出来,但上面是如何使用该服务的基本示例。


谢谢你的回答。对于这部分代码中的 new Subject<TypeOfData>(),需要添加一个参数,请问应该添加什么? - heliya rb

0
在 Angular 7.2.0+ 中

parent.component.ts

    <ul class="list-unstyled multi-steps">
    <li [ngClass]="{ ' is-active': status == 'first' }">
        <span [routerLink]="/room/specification" [state]="{data: {...}}"></span>
              step1
    </li>
    <li [ngClass]="{ ' is-active ': status == 'second' }">
         <span [routerLink]="/room/attributes"  [state]="{data: {...}}"(click)="onClick()"></span>
              step2
    </li>
</ul>
<div class="content">
    <router-outlet></router-outlet>
</div>

specificatioon.child.ts

乍一看,获取数据并不那么明显。有人可能期望ActivatedRoute会包含它,但是没有状态属性。状态属性添加到了Navigation中,可以通过Router.getCurrentNavigation().extras.state访问。问题在于getCurrentNavigation仅在导航期间返回Navigation,在导航结束后返回null。因此,在组件B的onInit生命周期钩子中,Navigation不再可用。我们需要从浏览器的历史对象中读取数据:

history.state.data

0

你可以使用 EventEmitter 或 Subject。在这种情况下,建议使用 Subject。

你可以使用服务来共享发出的值:

import {Injectable, EventEmitter} from '@angular/core';
import { Subject } from 'rxjs';

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

  }

  public emitter: Subject<string> = new Subject<string>(); // Subject
 // public emitter : EventEmitter<string> = new EventEmitter(); // Event Emitter
 
  getEmittedValue() {
    return this.emitter;
  }

你的样例子模板:

<button (click)="go('From Child')">Emit</button>

你的示例子组件(别忘了注入我上面创建的服务):

go(message: string) {
    console.log('Button Clicked ', message);
    this.appService.emitter.next(message); // Subject
   // this.appService.emitter.emit();  // Event Emitter
  }

现在可以在任何地方使用子组件发出的输出。只需在想要使用发出值的任何位置注入上面创建的服务,并订阅主题或事件发射器:

constructor(private appsService: AppService) {
    this.appsService.getEmittedValue().subscribe(res => this.ekMethod(res));
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接