如何在Angular 6中同步加载组件?

时间:2018-10-12 21:09:08

标签: angular angular6

我有一个标头组件,该组件进行调用以获取用户令牌并存储用户数据。然后,我有一个不同的组件(管理组件),它不是标头的子代,它依赖于用户数据来获取其他数据。我遇到的问题是管理组件在标头组件完成对用户的调用之前初始化,因此破坏了我的管理组件。换句话说,由于标题尚未设置活动公司,因此代码执行中断。有没有办法确保这些内容在Angular 6中同步加载,以便我可以避免此问题?

header.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';


@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
  user: any;
  activeCompany: any;

  constructor(private authService: AuthService) { }

  ngOnInit() {
    this.authService.getToken().then((user) => {
      this.user = user;
      this.user.Companies = JSON.parse(this.user.Companies.split('"').join('"'));
      this.authService.getActiveCompany$().subscribe((company: any) => {
        if(!company) {
          let company = this.user.Companies[0]
          this.authService.setActiveCompany$(JSON.stringify(company));
        }
        this.activeCompany = company;
      });
    });
  }

  setActiveCompany(company) {
    this.authService.setActiveCompany$(company)
  }
}

admin.component.ts

import { Component, OnInit } from '@angular/core';
import { TagService } from '../../services/tag.service';
import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'app-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdminComponent implements OnInit {
  companyId: number;
  tags: any;
  loading: boolean = true;

  constructor(
    private tagService: TagService,
    private authService: AuthService
   ) {}

  ngOnInit() {
    this.authService.getActiveCompany$().subscribe((company: any) => {
      // The line below breaks because the active company has not been set yet by the header 
      this.companyId = company.Id
      this.tagService.getTags(companyId).then((tags) => {
        this.setTags(tags)
        this.loading = false;
      });
    });
  }
}

auth.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, Subject, BehaviorSubject } from 'rxjs';
import { AppConfig } from '../../app-config';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private activeCompany$: Subject<any>;

  constructor(private http: HttpClient, private _config: AppConfig) {
    let initialActiveCompany;
    if (window.localStorage.getItem('activeCompany')) {
      initialActiveCompany = JSON.parse(window.localStorage.getItem('activeCompany'));
}   else {
      this.getToken().then((user: any) => {
        initialActiveCompany = user.Companies = JSON.parse(user.Companies.split('&quot;').join('"'))[0];
  });
}
this.activeCompany$ = new BehaviorSubject<any>(initialActiveCompany);

}

  getToken() {
    return new Promise(resolve => {
      this.http.get(`${this._config.API_URL}/Token`).subscribe(data => {
        resolve(data);},
        err => {
        console.log("Error retrieving token", err);
      });
    });
  }

  // Returns the observable (read-only) part of this subject
  getActiveCompany$(): Observable<any> {
    return this.activeCompany$.asObservable();
  }

  // Stores the new company value in local storage and pushes it to the subject
  setActiveCompany$(company: any) {
    window.localStorage.setItem('activeCompany', JSON.stringify(company));
    this.activeCompany$.next(company);
  }
}

4 个答案:

答案 0 :(得分:5)

我认为您应该多组织一些服务来处理异步性。

您应该在AuthService中将activeCompany设置为BehaviorSubject,然后在admin中订阅更改。

因为更改getTags()时需要调用activeCompany

答案 1 :(得分:3)

我建议您在管理组件中使用解析器服务。首先在cli中使用 ng g s resolver 命令创建一个新的解析器服务,然后使用此代码

import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { AuthService } from '../../services/auth.service';
import {
  Resolve,
  ActivatedRouteSnapshot,
  RouterStateSnapshot
} from "@angular/router";

@Injectable({
  providedIn: "root"
})
export class ResolverService implements Resolve<any> {
  this.companyId: any;
  constructor(private authService: AuthService) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any> {
    return this.authService.getActiveCompany$().subscribe((company: any) => {
    this.companyId = company.Id
    this.tagService.getTags(companyId).then((tags) => {
    this.setTags(tags)
    this.loading = false;
    });
   });
  }
}

,然后将其添加到管理组件下的路由模块中

{
 path: "admin",
 component: AdminComponent,
 resolve: {
 result: ResolverService
 }
}

,然后最后在您的管理组件中导入 ActicatedRoute

import { ActivatedRoute } from "@angular/router";

并添加到您的构造函数中

userData = null // store the data you want from your authService here from your resolver

constructor(private actr: ActivatedRoute) {
 this.actr.data.pipe(map(data => data.resuslt)).subscribe(res => {
 this.userData = res;
 });
}

我没有时间阅读您的authservice.ts,但我希望您能理解

答案 2 :(得分:0)

您是否尝试实施安全导航操作员?进行一些重组,就可以得到等待结果到达以实际呈现值的结果

The current hero's name is {{currentHero?.name}}

您可以看到docs here

答案 3 :(得分:0)

  1. 声明一个标志变量
  2. 标头组件完成对用户的调用后,将标志的值设置为true。
  3. 如果标志的值为*ngIf,则使用true加载管理组件。