只有在点击按钮两次后才会显示数值。

3
我已经尝试了一个月的Angular。我对Web开发非常陌生,为了不显得太菜,我在这里发帖提问。
我做了一个简单的Angular应用程序,它会在点击名为"roomSearch()"的按钮时向MVC Web API发送一些表单数据。结果数据从Web API发送回来,并由Angular组件在html页面中展示出来。 问题是,如果我要查看结果,我总是需要点击两次按钮。它不能在单击时工作,我很难弄清楚原因。
以下是我的代码:
我的HTML:
<form #roomForm="ngForm" class="coupon-form" (ngSubmit)="onSubmit(roomForm)">    
  <div class="row">
    <div class="col-xs-6 form-group">
      <label>Start Date</label>
      <input type="date" class="form-control" name="startDate" #startDate="ngModel" [(ngModel)]="roomService.userSelection.startDate" placeholder="Start Date" required>
    </div>

    <div class="col-xs-6 form-group">
      <label>End Date</label>
      <input type="date" class="form-control" name="endDate" #endDate="ngModel" [(ngModel)]="roomService.userSelection.endDate" placeholder="End Date" required> 
    </div>
  </div>

  <div class="form-group">
    <button type="button" (click)="roomSearch(roomForm)" class="btn btn-lg btn-block btn-info"><i class="fa fa-floppy-o" aria-hidden="true"></i> Submit</button> 
  </div>       
</form>

<br/>

<table *ngIf="show" class="table table-sm table-hover">  
  <p><b>Rooms We Could Find For You</b></p>
    <tr>      
      <td>{{roomService.finalRoom1/(roomService.roomList.length)}}</td>      
      <td>{{roomService.finalRoom2/(roomService.roomList.length)}}</td>      
      <td>{{roomService.finalRoom3/(roomService.roomList.length)}}</td>      
      <td>{{roomService.finalRoom4/(roomService.roomList.length)}}</td>
    </tr>
</table> 

组件文件:

 show: boolean;

 ngOnInit() {
    this.show = this.roomService.show;
  }

  roomSearch(form: NgForm)
  {
    this.show = this.roomService.getRoomList(form.value.startDate, form.value.endDate);
  }

服务文件

 constructor(private http: Http) {
      this.show=false;
    } 

getRoomList(startDate: string, endDate:string){    

    this.finalUrl = this.apiRoot + '?startDate='+ startDate + '&endDate='+ endDate;

    this.show=true;

    this.http.get(this.finalUrl)
    .map((data: Response)=>{
      return data.json() as Room[];
    }).toPromise().then(x =>{
      this.roomList = x;
    });

    console.log(this.roomList);

    if(this.roomList!=null){
      this.finalRoom1 = 0; this.finalRoom2 = 0; this.finalRoom3 = 0; this.finalRoom4 = 0; 
      this.priceRoom1 = 0; this.priceRoom2 = 0; this.priceRoom3 = 0; this.priceRoom4 = 0;

      this.roomList.forEach((e:any) => {
        this.finalRoom1 = this.finalRoom1 + Number(e.UnitPrice1);
        this.finalRoom2 = this.finalRoom2 + Number(e.UnitPrice2);
        this.finalRoom3 = this.finalRoom3 + Number(e.UnitPrice3);
        this.finalRoom4 = this.finalRoom4 + Number(e.UnitPrice4);
      });

    console.log(this.roomList); //This statement shows undefined at first click but on the second click showcases the correct value on the console.

    if(this.finalRoom1>0)
    this.show=true;
    else
    this.show=false;

    return this.show;   
    }  

上面的代码行console.log(this.roomList)在第一次点击时显示为undefined,但在第二次点击时在控制台上展示了正确的值。我做错了什么?
1个回答

2
首先,你的代码格式很棒,阅读起来很愉快!
其次,你面临的是异步问题。
当你进行HTTP调用时,Angular使用Observables(在你的情况下,你将其转换为Promises,但原理是相同的)。Observables/Promises是异步的,意味着结果将在稍后返回,而不是在请求时立即返回。
在你的情况下,发生了以下情况:
this.http.get(this.finalUrl)
.map((data: Response)=>{
  return data.json() as Room[];
}).toPromise().then(x =>{
  this.roomList = x;
});

console.log(this.roomList);

你不必等待承诺(Promise)被解决(即结果出现)。这就是为什么你的日志中有“undefined”的原因。
你可以尝试以下代码:
processRequest(roomList: Room[]) {

  if (roomList != null) {
    this.finalRoom1 = 0; this.finalRoom2 = 0; this.finalRoom3 = 0; this.finalRoom4 = 0;
    this.priceRoom1 = 0; this.priceRoom2 = 0; this.priceRoom3 = 0; this.priceRoom4 = 0;

    roomList.forEach((e: any) => {
      this.finalRoom1 = this.finalRoom1 + Number(e.UnitPrice1);
      this.finalRoom2 = this.finalRoom2 + Number(e.UnitPrice2);
      this.finalRoom3 = this.finalRoom3 + Number(e.UnitPrice3);
      this.finalRoom4 = this.finalRoom4 + Number(e.UnitPrice4);
    });

    console.log(roomList); //This statement shows undefined at first click but on the second click showcases the correct value on the console.

    if (this.finalRoom1 > 0)
      this.show = true;
    else
      this.show = false;

    return this.show;
  }
}

在你的代码中,删除冒号后面的所有内容:
return this.http.get(this.finalUrl)
  .map((data: Response) => {
    return data.json() as Room[];
  }).toPromise().then(x => {
    return Promise.resolve(this.processRequest(x))
  });

最后,在您的组件中,您必须这样做:
roomSearch(form: NgForm)
{
  this.roomService.getRoomList(form.value.startDate, form.value.endDate).then(show => this.show = show);
}

用简单的话来解释:

发送一个HTTP请求以获取房间,然后订阅并等待结果。一旦结果出现,使用processRequest处理请求并返回此处理的结果。一旦处理完成,由于我订阅了获取结果,将结果绑定到组件中的变量show。

如果还不清楚,请随时问!


非常感谢您的鼓励和易于理解的表述。我认为您的代码是一个很大的改进,但是,在服务文件中我遇到了一个错误。“在类型'Promise<Room[]>'上不存在属性'map'。” - Vaibhav
糟糕!请将“map”替换为“then”,并将其中唯一的代码行替换为“return Promise.resolve(this.processRequest(x))”(这与map完全相同,但需要分几步完成)。 - user4676340
没问题 :) 祝你的项目好运!(记得将你的问题标记为已解决!) - user4676340

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接