Angular BehaviorSubject 和输出

问题描述

在我的应用程序中,我使用行为主题来加载数据:

我的服务:

  data$ = new BehaviorSubject({
      users: [],user: {}
  });

  constructor(​​);

  }​​
  
  dispatch(action: Action): Observable<true | { error: string; }> {
      switch (action.type) {
          case ActionTypes.USER_LIST:
              this.getUsers();
              return of(true);
          default:
              return of(true);
      }
  }

  private getUsers(){
      this.http.get("url")
      .subscribe((users: any) => {
          this.data$.next({...this.data$.value,users: users});
      });
  }

当我的子组件请求它时,我会在我的父组件中调用它。

我的父组件:

export class MyParentComponent implements OnInit {
  isLoading = false;
  user$ = new BehaviorSubject(null);

  constructor(private userService: UserService) { }

  ngOnInit(): void {
    
  }
  
  getUsers(event) {
    this.isLoading = true;
    this.userService.dispatch({type: Action Types.USERR_LIST});
    this.user$.next(this.userService.data$);
    this.isLoading = false;
  }
}

MyChildComponent:调用加载数据:

  private getData() {
    this.onDataChange.emit(this.criteria);
    this.dataSource.data = this.items;
    console.log(this.dataSource);
    this.isLoading = false;
  }

调用我的子组件:

<app-child-comp
                          [entity]="(user$| async)?.value?.userList"
                          (onDataChange)="getUsers($event)" 
                          class="row col-md-12"
>
</app-child-comp>

我不明白为什么我的数据源或我的 items 属性在 onEmit 之后没有更新,而当我在我的子组件中将 items 属性显示到 json 训练时它是最新的

解决方法

根据您的代码,以下是我将如何实现它,为清晰起见重命名一些内容并键入一些对象:

服务:

export interface DataUsers {
    users: User[],user: User
}

data$ = new BehaviorSubject({
    users: [],user: {}
});

constructor(​​);
  // TODO
}​​
  
public dispatch(action: Action): Observable<true | { error: string; }> {
    switch (action.type) {
        case ActionTypes.USER_LIST:
            this.callUsersApi();
            return of(true);
        default:
            return of(true);
    }
}

public getDataUsers$(): Observable<DataUsers> {
  return this.data$.asObservable();
}

private callUsersApi(): void {
  this.http
      .get('url')
      .subscribe((users: User[]) => {
        this.data$.next({...this.data$.value,users: users});
      });
}

父组件:

// {...}
export class MyParentComponent implements OnInit {
  isLoading = false;
  user$: Observable<DataUsers> = null;

  constructor(private userService: UserService) {
    this.user$ = this.userService.getDataUsers$();
  }

  ngOnInit(): void {
    
  }
  
  getUsers(event) {
    this.isLoading = true;
    this.userService.dispatch({type: ActionTypes.USERR_LIST});
    // this.user$ will automatically receive the new data
    this.isLoading = false;
  }
}

父 HTML(更新管道异步):

<app-child-comp
                class="row col-md-12"
                [entity]="(user$| async)?.userList"
                (onDataChange)="getUsers($event)">
</app-child-comp>

子组件:

public ngOnChanges(changes: SimpleChanges) {
  if (changes.entity) {
    // this.entity has changed
    this.isLoading = false;
    if (changes.entity.currentValue) {
      // the new value is not empty
      if (!this.dataSource) {
        // init
        this.dataSource = new MatTableDataSource(changes.entity.currentValue);
      } else {
        // update
        this.dataSource.data = changes.entity.currentValue;
      }
    } else {
      // the new value is null
      if (!this.dataSource) {
        // data were displayed,reset them
        this.dataSource.data = [];
      }
    }
  }
}

private getData() {
  this.isLoading = true;
  this.onDataChange.emit(this.criteria);
  // you cannot set dataSource here,the HTTP call is not ended yet
  // when HTTP call will be ended,the ngOnChanges will be triggered because the parent will inject a new value to this.entity
  // so this.isLoading will be falsed in ngOnChanges,not here.
}