我是Angular框架的新手。我正在开发通过服务从组件进行基本数据检索。我已经开发了Web服务,该服务会为id(wwid
)吐出某些数据。通过组件(app.service
)通过服务(queueSearch.component
)调用的函数会发起一个GET
请求。数据已在服务内成功检索,但是不会立即更新与组件(waittime
)关联的变量。变量仅在第二次调用后才被更新(基本上单击两次搜索按钮以在html上对其进行更新)。如何单击一次更新?
app.service.ts
searchWWID(wwid: number)
{
console.log("from app service wwid: " + wwid.toString());
this.http.get("http://localhost:3000/api/list/" + wwid).subscribe(Data =>{
if(Data != null)
{
this.waitingTime = JSON.stringify(Data)
}
else
{
this.waitingTime = "";
}
//this gets updated instantaneously and prints
console.log(this.waitingTime);
});
return this.waitingTime;
}
}
queueSearch.component.ts
searchWWID()
{
if(isNaN(Number(this.wwid)))
{
console.log("not a number");
}
else
{
if(this.wwid.toString().length !== 8)
{
console.log("should be eight digits")
}
else
{
//this(waittime) only gets updated after every second call to this function
this.waitTime = this.AppService.searchWWID(Number(this.wwid))
}
}
}
queueSearch.component.html
<h1>{{title}}</h1>
<div style ="text-align:center">
<form>
<input type="text" class="form-control" placeholder="enter wwid"
[(ngModel)]="wwid" name="wwid" id="searchWWID">
<button class="btn btn-primary" id="submitButton"
(click)=searchWWID()>Submit</button>
</form>
</div>
<h2>waiting time: {{waitTime}}</h2>
预期结果:waittime
调用后立即更新html中的searchWWID()
。
实际结果:waittime
在第二次调用函数后更新
答案 0 :(得分:1)
首先,服务调用无法按预期运行的原因:
class Service {
constructor(private http: HttpClient) {}
waitingTime: string;
searchWWID(wwid: number): string
{
// 1. first, you create the request
this.http
.get('http://localhost:3000/api/list/' + wwid)
.subscribe(Data => {
if (Data != null) {
this.waitingTime = JSON.stringify(Data);
} else {
this.waitingTime = '';
}
console.log(this.waitingTime);
});
// 2. then you return the waiting time
return this.waitingTime;
// 3. 500ms later...
// 4. you actually get the response and `this.waitingTime` is set
// but unfortunately you have already returned
// 5. not to worry: the next time you call this function,
// it will return the result we have just received at "step 2" above
}
}
由于要处理异步结果,因此应使用Promise
或Observable
返回结果。考虑到http.get
函数返回一个可观察值,我们将使用Observable
:
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
import {map, tap} from 'rxjs/operators';
class Service {
constructor(private http: HttpClient) {}
searchWWID(wwid: number): Observable<string>
{
return this.http
.get('http://localhost:3000/api/list/' + wwid)
.pipe(
// use a `map` for transformation
map(data => data !== null ? JSON.stringify(data) : ''),
// use a `tap` for a side-effect
tap(idString => console.log(idString)),
);
}
}
现在服务调用返回Observable<string>
,我们要做的就是在组件代码中使用它:
class Component {
constructor(private appService: Service) {}
wwid: string;
searchWWID(): void
{
// let's use "early return" to remove extra nesting
if (isNaN(Number(this.wwid))) {
console.log('not a number');
return;
}
if (this.wwid.toString().length !== 8) {
console.log('should be eight digits');
return;
}
this.appService
.searchWWID(Number(this.wwid))
.subscribe((result: string) => this.wwid = result);
}
}
但是,上面的代码有一个小问题。如果您在组件代码中使用subscribe
,则应记住要在某个时候退订(最有可能是在组件被销毁时)。
一种实现方法是将订阅存储在属性中,然后使用onDestroy
钩子手动取消订阅:
import {OnDestroy} from '@angular/core';
import {Subscription} from 'rxjs';
class Component implements OnDestroy {
constructor(private appService: Service) {}
wwid: string;
wwidSubscription: Subscription;
searchWWID(): void
{
// let's use "early return" to remove extra nesting
if (isNaN(Number(this.wwid))) {
console.log('not a number');
return;
}
if (this.wwid.toString().length !== 8) {
console.log('should be eight digits');
return;
}
this.wwidSubscription = this.appService.searchWWID(Number(this.wwid))
.subscribe((result: string) => this.wwid = result);
}
ngOnDestroy() {
this.wwidSubscription.unsubscribe();
}
}
更新
正如评论中所建议的那样,由于我们的操作是“一次性的”,即我们仅获得一次响应,因此我们可以使用take(1)
来摆脱困境,这将为我们完成可观察的工作,并取消订阅订阅者。
此外,Http模块中的方法(例如get
,post
等)会在请求完成后自动完成,因此在这种情况下,我们实际上不必执行任何操作,具体取决于您希望将多少服务细节泄漏到组件中。
答案 1 :(得分:0)
在您的queueSearch.component.ts
中进行
else {
//this(waittime) only gets updated after every second call to this function
this.waitTime = this.AppService.searchWWID(Number(this.wwid));
console.log(this.waitTime); // check whether the value is getting update here .
// If yes, then its a matter of dirtyChecking
//Inject changedetectorref in your constructor an use that ref below.
this.cdr.markForCheck();
}