Naman Jain
Naman Jain

Reputation: 411

Angular: Function returning value before the HTTP call is finished

I have to calculate the total number of business days between selected dates and I am using the following logic

this.businessDays = this.calcBusinessDays(this.startDate, this.endDate);

calcBusinessDays(d1: Date, d2: Date) {
        let date1 = new Date(d1);
        let date2 = new Date(d2);
        let oneDay = 1000 * 60 * 60 * 24;
        let difference = Math.floor((date2.getTime() - date1.getTime()) / oneDay);
        let businessDays = 0;
        let i: number;
        this.httpService
            .getHolidays(moment(date1).format('YYYY-MM-DD'), moment(date2).format('YYYY-MM-DD')) //start-date and end date are a part of query params in YYYY-MM-DD format.
            .subscribe((res: HttpResponse<HolidaysListInterface>) => {
                this.holidaysList = res.body.holidayDates;
                for (i = 0; i < difference; ++i) {
                    let day = date1.getDay();
                    let isHoliday = this.holidaysList.indexOf(moment(date1).format('YYYY-MM-DD')) != -1;
                    if (day != 0 && day != 6 && !isHoliday) {
                        ++businessDays;
                    }
                    date1.setDate(date1.getDate() + 1);
                }
            });
        return businessDays;
    }

Now the problem here is I am getting 0 every time as a return value. The function is returning the value even before the Http call is finished. What's the workaround for this?

Upvotes: 1

Views: 667

Answers (1)

Barremian
Barremian

Reputation: 31125

Because that is how asynchronous requests work. They are executed asynchronously disregarding the actual order of execution you specify. You could learn more about it here.

One line solution to your problem is

anything that directly depend on the response from the HTTP call should be inside the subscription

or in other words

subscribe where it's response is required

One more thing to remember is you cannot return an async variable (businessDays here) synchronously.

Also you could use RxJS map operator to transform the response to your required format

Try the following

businessDays: any;

someFunc() {
    this.calcBusinessDays(this.startDate, this.endDate).subscribe(
        businessDays => this.businessDays = businessDays,
        error => {
            // always good practice to handle HTTP errors
        }
    );
}

calcBusinessDays(d1: Date, d2: Date): Observable<any> { // <-- return observable here
    let date1 = new Date(d1);
    let date2 = new Date(d2);
    let oneDay = 1000 * 60 * 60 * 24;
    let difference = Math.floor((date2.getTime() - date1.getTime()) / oneDay);
    let businessDays = 0;
    let i: number;
    return this.httpService
        .getHolidays(moment(date1).format('YYYY-MM-DD'), moment(date2).format('YYYY-MM-DD')) //start-date and end date are a part of query params in YYYY-MM-DD format.
        .pipe(
            map((res: HttpResponse<HolidaysListInterface>) => {
                this.holidaysList = res.body.holidayDates;
                for (i = 0; i < difference; ++i) {
                    let day = date1.getDay();
                    let isHoliday = this.holidaysList.indexOf(moment(date1).format('YYYY-MM-DD')) != -1;
                    if (day != 0 && day != 6 && !isHoliday) {
                        ++businessDays;
                    }
                    date1.setDate(date1.getDate() + 1);
                }
                return businessDays; // <-- return modified value here
            })
        );
}

Upvotes: 3

Related Questions