【问题标题】:Angular Method not saving value of variable角度方法不保存变量的值
【发布时间】:2020-06-04 22:18:21
【问题描述】:

我正在 Angular 中创建一个 Route Guard;它的运作方式取决于您是否与公司有关联;它会将您发送到特定组件。 Unfourtnetly,当运行 canLoad 方法时,它不会保存 companylist 变量的值。任何帮助将不胜感激!

import { Injectable } from '@angular/core';
import { CanActivate, Router, CanLoad } from '@angular/router';
import { AuthService } from 'src/app/auth.service';
import { User } from 'src/models/user';
import {ListdataService} from 'src/app/listdata.service';

@Injectable({
  providedIn: 'root'
})
export class CompanyonlyService implements CanActivate, CanLoad {
  companieslist=[];

  constructor(private authService: AuthService, private router: Router,private dataService:ListdataService) { }



  run(){
    this.dataService.sendGetRequestcompanies().subscribe((data: any[])=>{
      let tmp = [];

      for (let key in data)
        if (data.hasOwnProperty(key))
          tmp.push(data[key])

          this.companieslist = tmp;
          console.log(this.companieslist)





    }   )}



  canActivate() {
    return this.canLoad()
  }


    //this method won't set the value of the variable why?
    canLoad(){

      this.run()
      console.log('after loop')
      console.log(this.companieslist)
    if (this.companieslist.length==0) {

      this.router.navigate(['/companysignup']);

    }
    else{
      this.router.navigate(['/dashboard']);
    }

    return this.authService.isLoggedIn();
  } 
  }


[在此处输入图像描述]这是我在控制台中返回的内容

【问题讨论】:

  • 我在控制台中返回的是在 run() 之后包含一个项目的数组。然后当我 console.log(this.companieslist) 我返回一个空数组
  • 因为 canLoad 内部的 console.log(this.companieslist) 在可观察到的发射值之前评估并填充数组。 js是异步的

标签: angular angular-router-guards angular-route-guards


【解决方案1】:

由于请求,方法 run 是异步的,您没有检查请求是否已经完成。

因此,如果在检查条件时请求未完成,companyList 的大小将始终等于 0。

查看How to check all HTTP get request is completed (resolved) - Angular 2

【讨论】:

    【解决方案2】:

    问题是基于异步的。 run 方法运行一个影响 campaniesList 数组的订阅。但是当您调用 run 并触发订阅时,它不会停止执行您的代码。因此,当您在运行后立即登录时:

      this.run()
      console.log('after loop')
      console.log(this.companieslist)
    

    它在嵌套在订阅块中的内容之前运行:

     this.dataService.sendGetRequestcompanies().subscribe((data: any[])=>{
      let tmp = [];
    
      for (let key in data)
        if (data.hasOwnProperty(key))
          tmp.push(data[key])
    
          this.companieslist = tmp;
          console.log(this.companieslist)
    }
    

    编辑:

    我有一个守卫的例子

     canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
       return this.userService.getPermissions(this.userService.userId).pipe(map((permissions: string[]) => {
           if(permissions.length === 0) {
                this.router.navigateByUrl('/dashboard');
           }
           return permissions.length > 0; // this is where you could check for some specific permission maybe?
       }),
       retry(3),
       catchError(() => {
        this.router.navigateByUrl('/dashboard');
        return of(false);
       })
    

    【讨论】:

    • 我尝试在 canLoad() 中使用 settimeout 方法,它显示了正确的值,但它不会执行脚本的下一部分。你能告诉我如何使用 async/await,拜托
    • 解决方案可能涉及在警卫类中明确解决它。因此,创建一个实现 canActivate 的自定义保护类,将该保护与您想要限制的路由相关联,然后使用该类执行异步操作。我知道这样做很痛苦,所以我将发布一个我实现类似功能的地方的示例(经过大量试验和可观察的错误......)
    • 希望对你有帮助!
    【解决方案3】:

    CanLoad 守卫的方法类型签名允许您返回Observable&lt;boolean&gt;Promise&lt;boolean&gt; 或只是普通的boolean

    CanActivate 守卫是类似的,除了你可以返回 booleanUrlTree,但仍然允许它是 Observable 或 Promise。这意味着该函数可以等待您的调用完成。

    出于您的目的, CanActivate 就足够了,除非您想阻止客户端完全加载不同的路由模块,但这超出了此答案的范围。

    您的 dataService 请求返回一个 Observable,因此您需要做的就是将请求返回的数据映射到 CanActivate 的正确返回类型。

    这是您可以做到的一种方法:

    import { Injectable } from '@angular/core';
    import { CanActivate, Router, CanLoad } from '@angular/router';
    import { map } from 'rxjs/operators';
    import { AuthService } from 'src/app/auth.service';
    import { User } from 'src/models/user';
    import { ListdataService } from 'src/app/listdata.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class CompanyonlyService implements CanActivate {
    
      constructor(private authService: AuthService, private router: Router,private dataService:ListdataService) { }
    
      canActivate() {
        return this.dataService.sendGetRequestcompanies().pipe(
          map((data: any[]) => {
            if(data && data.length > 0) return this.router.createUrlTree(['/dashboard']);
            else return this.router.createUrlTree(['/companysignup']);
          })
        );
      }
    
    }
    

    使用 Typescript 的主要优点之一是知道您的参数是什么类型或返回类型是什么。如果您没有正确声明它们,它无法拯救您自己,并且您会错过看到可以返回的不同可能选项。

    完全类型化的方法是:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean|UrlTree> | Promise<boolean|UrlTree> | boolean|UrlTree {
        return this.dataService.sendGetRequestcompanies().pipe(
          map((data: any[]) => {
            if(data && data.length > 0) return this.router.createUrlTree(['/dashboard']);
            else return this.router.createUrlTree(['/companysignup']);
          })
        );
      }
    

    【讨论】:

      猜你喜欢
      • 2018-07-19
      • 1970-01-01
      • 2019-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多