仅在角度4中服务中的第二个函数调用之后,组件中的变量才会更新

时间:2018-12-29 06:28:08

标签: angular typescript http

我是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在第二次调用函数后更新

2 个答案:

答案 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
    }
}

由于要处理异步结果,因此应使用PromiseObservable返回结果。考虑到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模块中的方法(例如getpost等)会在请求完成后自动完成,因此在这种情况下,我们实际上不必执行任何操作,具体取决于您希望将多少服务细节泄漏到组件中。

答案 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();

}