Vaibhav
Vaibhav

Reputation: 57

Values are shown only when button is clicked two times

I've completed a month trying my hand at Angular. I'm very new to Web Development and at the risk of sounding like a novice, I'm posting this question.

I've made a simple angular application that sends some form-data to a MVC Web API on the click of a button called roomSearch(). The resultant data is sent back from the Web API to the angular component which showcases it in the html page. The problem is that I always need to click the button twice if I have to see the result. It doesn't work on a single click and I'm having a hard time figuring out why.

Here is my code:

My 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> 

Component File:

 show: boolean;

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

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

Service FIle

 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;   
    }  

The above line of code console.log(this.roomList) shows undefined at first click but on the second click showcases the correct value on the console. What am I doing wrong?

Upvotes: 3

Views: 2057

Answers (1)

user4676340
user4676340

Reputation:

First, kudos for the formatting of your code. It was a pleasure to read it !

Second, what you are facing is an asynchronous issue.

When you make HTTP calls, Angular uses Observables (in your case, you transform it to Promises, but the principle is the same). Observables/Promises are asynchronous, menaning that the result will come later on, not when you make the request.

What happens, in your case, is there :

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

console.log(this.roomList);

You don't wait for the promise to be resolved (a.k.a. having the result). This is why you have a log of undefined.

You should try this :

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;
  }
}

And in your code, remove everything after that :

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

Finally, in your component, you must do this :

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

To explain it to you with words :

Make an HTTP request to get the rooms, and subscribe then wait for the result. Once the result is there, process the request with processRequest and return the result of this process. Once the processing is done, since I subscribed to get the result, bind the result to the variable show of my component.

If this wasn't cler enough, feel free to ask !

Upvotes: 2

Related Questions