为 Angular 订阅者的变量赋值

Assign values to a variable from a Angular subscriber

我对 Angular 很陌生。我已经完成了服务和模板,我开始做组件。我正在尝试从休息服务中分配值列表(模板)。如果用户是管理员,他可以看到所有这些,并且可以正常工作。如果用户不是管理员,他只能看到他自己的,但我无法让订阅者存储用户的个人资料。 当我尝试分配它时,它没有这样做。我读到这是因为订阅者是异步方法,但我真的找不到解决方案。如何将服务器的值分配给变量,以便在视图中呈现它?

组件

@Component({
  selector: 'app-plantilla',
  templateUrl: './plantilla.component.html',
  styles: [
  ]
})
export class PlantillaComponent implements OnInit {

  public titulo = 'Colección de plantillas';
  public plantillas: Plantilla[] = [];
  public perfil: Perfil = new Perfil();

  constructor(private plantillaServicio: PlantillaService, private authService: AuthService, private perfilServicio: PerfilService) { }

  ngOnInit(): void {
    if (this.authService.isAuthenticated()) {

      console.log(this.authService.usuario);
      if (this.authService.usuario.rol.id===1 ) {
        console.log("al if");
//this works
        this.plantillaServicio.listar().subscribe(plantillas =>
          this.plantillas = plantillas);
      }else{
        console.log("al else");
//this works
        console.log(this.perfilServicio.ver(this.authService.usuario.id).subscribe(val => console.log(val)));
//this doesn't work
        this.perfilServicio.ver(this.authService.usuario.id).subscribe((val:Perfil)=>this.perfil=val);
//show empty class
        console.log(this.perfil);
      }

    } else {
      console.log("No autenticado");
    }
  }
}

查看

<div
    class="card container"
    *ngFor="let plantilla of plantillas"
>
    <div class="row g-0">
        <div class="col-md-6">
            <h3 class="card-title">
                {{plantilla.id}} - {{plantilla.empresa.nombre}} - {{plantilla.empresa.id}}
            </h3>
        </div>
        <div class="col-md-12">
            <!-- <div class="card-header">{{plantilla.asunto}}</div> -->
            <div class="card-body text-dark bg-light mb-3">
                <h5 class="card-title">{{plantilla.asunto}}</h5>
                <p
                    class="card-text"
                    [innerHTML]=plantilla.texto
                ></p>
            </div>
        </div>
    </div>
</div>

我也在 *ngIf="plantillas?.length>0" 视图中尝试过,但控制台显示模板可以未定义。

这是第一次学习Rxjs的人很常见的问题。

console.log(this.perfilServicio.ver(this.authService.usuario.id).subscribe(val => console.log(val)));

包含整个语句的外部控制台日志只会注销订阅。 不是订阅的结果。内部控制台日志将记录结果的值,因为它在您的 subscribe 块内并完成异步。

this.perfilServicio.ver(this.authService.usuario.id).subscribe((val:Perfil)=>this.perfil=val); //show empty class console.log(this.perfil);

您在此处底部的控制台日志将在您在订阅块中设置变量之前执行。

this.perfilServicio.ver(this.authService.usuario.id)
    .subscribe((val:Perfil)=>{
        this.perfil=val;
        console.log(this.perfil); //This will now work
    });

我强烈建议您学习订阅和可观察对象的基础知识。 https://www.learnrxjs.io/learn-rxjs/concepts/rxjs-primer

您的模板可以未定义的原因是它们会在您的可观察对象完成之前呈现。因此,您需要通过将任何异步代码包装在(例如)*ngIf="!asyncVariable".

中来意识到这一点

或者您可以使用 angular 如下所示的异步模板

您的 html 将使用异步管道 https://angular.io/guide/observables-in-angular

*ngFor="let plantilla of plantillas | async"

您的 ts 文件不会订阅可观察对象。它只会分配它。订阅发生在 angular 异步管道的幕后。

this.plantillas = this.plantillaServicio.listar();

我的解决方案是这样的:

正如 James 所说,关键是要理解异步性。当订阅者正在执行时,它可能需要一点时间或很多时间,但无论如何都需要时间,执行下一条指令。如果该指令取决于订阅者的结果,它将不会按预期工作。

需要注意的是,每个订阅者都有三个参数,事件、错误和完成。在完成块内,可以执行其余的指令,但总是在这个块内,而不是在它或订阅者之外。为此,我还需要一个订阅者,一个链式订阅者。 第一个订阅者检索配置文件,第二个订阅者检索植物,这是我真正想要的。还有我没接触过的视图代码。

@Component({
  selector: 'app-plantilla',
  templateUrl: './plantilla.component.html'
})
export class PlantillaComponent implements OnInit {

  public titulo = 'Colección de plantillas';
  public plantillas: Plantilla[] = [];
  public perfil: Perfil = new Perfil();
  private empresa: Empresa = new Empresa ();

  constructor(private plantillaServicio: PlantillaService,
    private authService: AuthService,
    private perfilServicio: PerfilService,
    private empresaServicio: EmpresaService) { }

  ngOnInit(): void {
    if (this.authService.isAuthenticated()) {

      console.log(this.authService.usuario);
      if (this.authService.usuario.rol.id === 1) {
        console.log("al if");
        this.plantillaServicio.listar().subscribe(plantillas => this.plantillas = plantillas);
      } else {
        console.log("al else");
//call to old suscriptor
        this.setPerfil(this.authService.usuario.id);
      }
    } else {
      console.log("No autenticado");
    }
  }

// old suscriptor but modified
  setPerfil(id: number): void {
    this.perfilServicio.ver(this.authService.usuario.id)
      .subscribe((val: Perfil) => {
        this.perfil = val;
        console.log(val);
      }, (err) => {
        console.log(err)
      }, () => {
        console.log('perfil complete!');
//call to new suscriptor
        this.setPlantillas(this.perfil.id);
      });
  }

//new suscriptor
  setPlantillas(id: number): void {
    this.plantillaServicio.listarPorEmpresa(id)
    .subscribe((val: Plantilla[]) => {
      this.plantillas=val;
      console.log(val);
    }, (err) => {
      console.log(err)
    }, () => {
      console.log('plantillas complete!');
    });
  };
}