问题描述
我对 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); //显示空类 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
您的模板可能未定义的原因是因为它们会在您的 observable 完成之前呈现。因此,您需要通过将任何异步代码包装在(例如)*ngIf="!asyncVariable"
中来意识到这一点。
或者您可以使用如下所示的 Angular 异步模板
您的 html 将使用异步管道 https://angular.io/guide/observables-in-angular
*ngFor="let plantilla of plantillas | async"
您的 ts 文件不会订阅 observable。它只会分配它。订阅发生在带有角度异步管道的引擎盖下。
this.plantillas = this.plantillaServicio.listar();
,
我的解决方案是这样的:
正如詹姆斯所说,关键是要理解异步。在执行订阅者的同时,可能需要一点时间或很多时间,但无论如何都需要时间,执行下一条指令。如果该指令取决于订阅者的结果,它将不会按预期工作。
需要注意的是,每个订阅者都有三个参数,事件、错误和完成。在完成块内,可以执行其余的指令,但总是在该块内,而不是在它或订阅者之外。为此,我需要另外一个订阅者,一个链接订阅者。 第一个订阅者检索个人资料,第二个订阅者检索植物,这正是我真正想要的。而视图代码我不必碰它。
@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!');
});
};
}