所以,这是我的用例:我从rest API中获取了一个observable,然后在模板中使用async
来预测数据。点击后,我获得特定用户的ID,然后用该用户的数据填写表单。为了实现后者,我重用现有的observable并过滤数据,然后订阅它。我想知道我的方法是否正确,因为当我点击“编辑”表单填充时,我认为应用程序太慢了,所以我猜这里我创建了太多的订阅或诸如此类的东西?
另外,为了论证,我创建了两个可观察对象(user
和users
),一个(user
)获得另一个(users
的“引用” ),然后它显示在模板中async
,而我也订阅它并将其设置为“常规”变量。这是一个问题吗?要显示带有async
的观察者并订阅它吗?
这是代码,因为我的问题可能有点令人困惑:
//our root app component
import {Component, NgModule, VERSION, OnInit, OnDestroy} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/find';
import 'rxjs/add/operator/takeUntil';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { UserService } from './service';
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<div>
{{user | async | json}}
{{selected | json}}
</div>
<div *ngFor="let u of users | async">
{{u.first_name}} {{u.last_name}}
<br />
<img [src]="u.avatar" />
<br />
<br />
<a (click)="edit(u.id)">Edit</a>
<br />
<br />
</div>
<div>
<form [formGroup]="userForm" (ngSubmit)="onSubmit()" novalidate>
<input type="text" formControlName="first_name" />
<input type="text" formControlName="last_name" />
</form>
<p>userForm value: {{ userForm.value | json}}</p>
<p>validity: {{ userForm.valid }}</p>
</div>
</div>
`,
styles: ['a { cursor: pointer; }']
})
export class App implements OnInit, OnDestroy {
users: Observable<any>;
user: Observable<any>;
destroy$: Subject<boolean> = new Subject<boolean>();
name:string;
userForm: FormGroup;
constructor(private fb: FormBuilder, private service: UserService) {
this.name = `Angular! v${VERSION.full}`;
this.createForm();
}
createForm() {
this.userForm = this.fb.group({
first_name: ['', {updateOn: 'blur', validators: [Validators.required, Validators.minLength(2), Validators.maxLength(10)]}],
last_name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(20)]]
})
}
edit(id) {
this.user = this.users.map(x => x.find(x => x.id === +id));
this.user.takeUntil(this.destroy$).subscribe(u => {
console.log(u);
this.selected = u;
this.userForm.patchValue({
first_name: u.first_name,
last_name: u.last_name
});
});
}
ngOnInit() {
console.clear();
console.log('hello world');
this.users = this.service.all();
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.unsubscribe();
}
}
@NgModule({
imports: [ BrowserModule, HttpClientModule, ReactiveFormsModule ],
providers: [UserService],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
答案 0 :(得分:0)
您可以通过传递整个用户而不仅仅是id来大大简化编辑方法。
ISO
至于多次调用<a (click)="edit(u)">Edit</a>
edit(user) {
this.selected = user;
this.userForm.patchValue({
first_name: user.first_name,
last_name: user.last_name
});
}
会导致多次订阅和多次调用后端。
如果要多次调用它,请使用service.all()
rxjs运算符。
这将在observable周围创建一个包装器主题,每次调用它时都会返回相同的值。
答案 1 :(得分:0)
假设你想使用observable来完成这项任务。虽然Leon的答案中有更直接的方法,但为了学习Observables,我们可以这样做: - )
您正在使用异步管道在模板中订阅用户可观察对象,但也在编辑方法中订阅。编辑方法中的订阅永远不会取消订阅,因此存在内存泄漏。
每次单击用户并让模板中的异步管道重新订阅时,您也会重新定义this.user
observable。这导致另一个内存泄漏,因为异步管道没有关于应该取消订阅的覆盖可观察量的线索。
这不是你应该如何组成你的可观察流。首先,您应该定义可观察的数据转换。
当我查看您的应用程序时,您有两个数据/事件源:
用户只能从服务中观察到。点击次数应该是Subject
。因为在编辑时,您应该发出被单击(可观察)的userId,并通过显示用户详细信息(观察者行为)对此单击做出反应。
editClick: Subject<number> = new Subject<number>;
那么让我们来定义user
observable的样子(ngOnInit
中的所有代码):
this.users = this.service.all().shareReplay();
this.user = this.editClick
.switchMapTo(this.users, (userId, users) => ({ userId, users}))
.map(x => x.users.find(user => user.id === +x.userId))
.do((u) => {
console.log(u);
this.selected = u;
this.userForm.patchValue({
first_name: u.first_name,
last_name: u.last_name
});
});
这里我基于editClick定义用户可观察性 - 这就是我将从后面获取id的地方。使用switchMapTo
我将来自users
的{{1}} observable和id合并到我稍后用来过滤掉点击用户的对象中。
现在如何在editClick
方法中触发editClick
?只需在每次点击时发出onEdit
,如下所示:
userId
注意我如何在edit(id) {
this.editClick.next(id);
}
中定义数据流。刚刚开始一次。没有娱乐或其他什么。我有两个可观察的订阅者:
ngOnInit
显示用户列表users
显示详细信息 - 每次触发user
此外,模板中只有订阅,因此没有内存泄漏,因为editClick
管道将为您管理async
。