首页 > 解决方案 > 在嵌套组件中使用时服务为空

问题描述

在嵌套组件中注入的服务为空。如何在嵌套组件中使用服务

export class ActivityComponent implements OnInit {
    constructor(
    .
    .
    public accountService: AccountService //it is null when use in view!!!!

  ) { }
  ....
  }
   <app-some-component>
       ...
       <div *ngFor="let task of tasksService.bindingSource.dataSource"> 
          <app-activity [task]="task"></app-activity>
       </div>
       ...
  </app-some-compnent>
   <div>{{accountService.getUser(task.userId).name}}</div> <!-- <= error line --> 

错误:_co.accountService.getUser(...) 未定义

标签: angular

解决方案


Önay,如果你有一个典型的服务,你会有一些像

getUser(user)
{
     return this.HttpClient.get('....'+user)
}

返回一个 Observable

如果你有一些喜欢

**example of WRONG service
user:any
getUser(user)
{
     this.HttpClient.get('....'+user).subscribe(res=>{
          this.user=res
     }   
     return this.user //<---here user is null because we are making 
                      //async call
}

好吧,你明白为什么 getUser 在最后一种情况下返回 null 而在第一种情况下你不能使用 accountService.getUser().value。accontService不为 null,但 accountService.getUser()返回 null

让我解释一下如何解决有关您需要获取accountService数据的问题。

您可以采用两种方法,获取用户列表,然后获取任务列表并使用用户的值映射 las 列表。我们需要使用 switchMap 和 map 'rxjs' 操作符

想象一下,你有

  getUserList(): Observable<User[]> {
    return this.httpClient.get<User[]>("..."); //get an array of Users
  }
  getTaskList(): Observable<Task[]> {
    return this.httpClient.get<Task[]>("..."); //get an array of Tasks
  }

您可以创建一个新方法,该方法返回带有用户名的任务列表

  getTaskExtenderList(): Observable<any[]> {
    return this.getUserList().pipe(
      switchMap((users: any[]) => {
        //in users we has the list of users, but we want
        //return the task
        return this.getTaskList().pipe(
          map((task: any[]) => {
            //here we has the list of task
            task.forEach(x => {
              const user = users.find(u => u.userId == x.userId);
              x.userName = user ? user.userName : null;
            });
            return task;
          })
        );
      })
    );
  }

另一种方法是,对于每个任务,创建对用户的调用并将名称加入任务(这种方法是当用户列表非常大并且每个用户有一个或两个任务时)

 //we has a function
  getUser(userId): Observable<User> {
    return this.httpClient.get<User>("....."+userId)
  }

  getTaskExtenderList2(): Observable<any[]> {
    return this.getTaskList().pipe(
      map((tasks: Task[]) => {
        const users = tasks.map((t: Task) => t.userId);
        const obs = users
          .filter((x, index) => users.indexOf(x) == index)
          .map(u => this.getUser(u));
        return { uniqueUsers: obs, tasks: tasks };
      }),
      switchMap((data: { uniqueUsers: Observable<User>[]; tasks: any[] }) => {
        return forkJoin(data.uniqueUsers).pipe(
          map((users: any[]) => {
            data.tasks.forEach(t => {
              const user = users.find(u => u.userId == t.userId);
              t.userName = user ? user.userName : null;
            });
            return data.tasks;
          })
        );
      })
    );
  }

好吧,你在stackblitz中有两种方法

注意:在stackblitz中我使用“of”来模拟httpClient.get

NOTE2:记住一个好的做法:“服务返回 Observables,组件订阅服务”


推荐阅读