从父级中的ajax调用接收数据后,如何更新子级组件 [英] How to update child components after receiving data from an ajax call in parent

查看:94
本文介绍了从父级中的ajax调用接收数据后,如何更新子级组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序结构如下,我的问题是如何在接收初始或将来的数据时更新子组件视图,假设我只有一个具有事件OnDataUpdate的服务,所有子组件都在接收该服务的同一实例另一方面,由于它已在应用程序模块提供程序"部分中声明,因此我尝试了所有这些方法&没用:

my app structure is as below, my question is how to update children components view on receiving initial or future data, imagine I have only one service which has an event OnDataUpdate, all the child components are receiving the same instance of the service since it has declared in App module providers section, on the other hand, I have tried all these ways & did not work:

  1. ApplicationRef.tick()
  2. ChangeDetectionRef.markForCheck()
  3. ChangeDetectionStrategy
  4. 具有这样的OnDataRecieved事件的组件之间的共享服务

@Injectable()
export class ApiService {

  public OnDataRecieved: EventEmitter<Model>  = new EventEmitter<Model>();

  constructor(private http: HttpClient, private ngZone: NgZone) {
  }

  public getDataAsync(): Observable<Model> {
      return this.http
        .get<Model>('url')
        .pipe(catchError(er => throwError(er)));
    }
}

在App根组件中,这类似于下面的代码

and in App root component this is like below code

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default
})
export class AppComponent implements DoCheck {

  model: BehaviorSubject<Model> = new BehaviorSubject<Model>(new Model()); //with default values
  subModel: BehaviorSubject<SubModel>; 


  constructor(private apiService: ApiService,
    private zone: NgZone) {

    this.apiService.getDashboard().subscribe((data) => {
      this.zone.run(() => {
          this.apiService.OnDataReceived.emit(data);
          this.model = new BehaviorSubject<Model>(data);
      });
    });

    this.model.subscribe((mdl) => {
      this.subModel = new BehaviorSubject<SubModel>(mdl.subModel));
    });
  }

  ngDoCheck() {
  }
}

想象当数据被加载或更改时模型被嵌套并通过子组件传播,其结构可以像这样

imagine the model is nested and propagated through the child components as data is loaded or changed, the structure can be like this

 __ AppRootComponent
|_____ Component1
|_________SubCompoent1-1
|_________SubCompoent1-2
|_____ Component2
|_________SubCompoent2-1
|____________SubCompoent2-1-1

我在ngDoCheck中接收到数据更改,无需触发检测更改,但是UI和子组件未更新!

I receive the data changes in ngDoCheck, no need to trigger the detect changes, but the UI and child components does not get updated!

推荐答案

让我们从一些常规建议开始:

Let's start with some general advice:

  1. 通常不需要服务即可使数据从组件流到其(大)子级.为此使用@Input绑定.

使用服务管理数据流时,请使用纯RxJS,即ObservableSubjectBehaviorSubject等的实例.EventEmitter是特定于Angular的组件,用于处理组件的输出事件和指令.如果您想查看类似的解决方案,请查看此答案一个BehaviorSubject.

When using a service to manage data flows, use plain RxJS, i.e. instances of Observable, Subject, BehaviorSubject, etc. EventEmitter is an Angular specific meant to handle output events from components and directives. Check this answer if you want to see a similar solution using a BehaviorSubject.

您不需要告诉Angular在默认区域中运行代码.默认情况下会执行此操作.

You don't need to tell Angular to run code in the default zone. It does this by default.

具体来说,您的服务可以像以下这样简单:

Concretely, your service can be as simple as the following:

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  constructor(private http: HttpClient) { }

  getData(): Observable<Model> {
    return this.http.get<Model>('...');
  }
}

然后,组件可以订阅它并将值存储在纯同步属性中.可以将此属性作为@Input()传递给子组件:

A component may then subscribe to it and store the value in a plain synchronous property. Down the road this property can be passed as @Input() to child components:

@Component({
  selector: 'my-app',
  template: `
    <strong>AppComponent:</strong> {{model | json}}
    <child [model]="model"></child>
  `
})
export class AppComponent implements OnInit {
  model: Model;

  constructor(private apiService: ApiService) { }

  ngOnInit(): void {
    this.apiService.getData()
      .subscribe(model => this.model = model);
  }
}

您还可以随时更新model属性,并且更改将传播到子代和孙代组件. 这是一个带有示例实现的Stackblitz .

You can also update the model property at any point in time and the change will be propagated to the components children and grandchildren. Here's a Stackblitz with a sample implementation.

这篇关于从父级中的ajax调用接收数据后,如何更新子级组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆