angularhttprequestangular-httpangular-http-interceptorsangular4-httpclient

response of a request not being same when being accessed in subsrcibe


I have an angular function which makes an HTTP call to a certain end point and i am subscribing the response. But there is a very strange behavior i am getting noticing that when i inspect response of the request in network tab it is correct but when i see the same response of very same request in console by console.log it is different. Here is my angular function which is making request and subscribing response.

getTemplate(){
    this.documentService.getDocumentTemplates({}, this.template_uuid)
      .subscribe((response) => {
        console.log('response');
        console.log(response);
        this.questionsarray = response['questions'];
        let i = 0;
        for (const section  of this.questionsarray) {
          for (const question of section.questions) {
            this.questionsarray[i] = question;
            i++;
          }
        }
        if(this.action === 'edit'){
          this.getContract(this.contractUUID);
        }
    });
  }

and following is the screenshot of network tab enter image description here

and following is the screenshot of console.log enter image description here

i am unable to find out my mistake, any help is appreciated. Thanks.

Edit: this is my service function.

getDocumentTemplates(data: Object = null, uuid) {
    return this.httpService.httpRequestConsumerWithUUID({
        method: 'GET',
        url: '/agbuilder/template/' + uuid + '/',
        data: data
    });
  }

and this is my http warpper service which eventually makes requests and returns response.

@Injectable()
export class HttpService {

  baseUrl: string = environment.serverUri;
  onError: EventEmitter<string> = new EventEmitter<string>();

  constructor(
    private http: Http,
    public router: Router,
    private cookieService: CookieService
    ) {
  }

  // for auth(login, signup and profile) where it will use accounts api+server token
  httpRequest(requestObject: any) {
    const request = this.requestBuilder(requestObject, 'server');
    return this.MakeRequest(request);
  }

  // this will use consumer token with uuid in url
  httpRequestConsumerWithUUID(requestObject: any) {
    const request = this.requestBuilder(requestObject, 'consumer-uuid');
    return this.MakeRequest(request);
  }

  // this will use consumer token WITHOUT uuid in url
  httpRequestConsumer(requestObject: any) {
    const request = this.requestBuilder(requestObject, 'consumer');
    return this.MakeRequest(request);
  }

  MakeRequest(request: any) {
    return this.http.request(request)
      .map(response => {

        if (response.status === 204) {

          return Object.assign({'status': 'success'}, {
            serverUri: environment.serverUri
          });
        }

        return Object.assign(response.json(), {
          serverUri: environment.serverUri
        });
      })
      .catch((err) => this.handleError(err));
  }


  // httpRequest(requestObject: any) {

  //   const request = this.requestBuilder(requestObject);
  //   return this.http.request(request)
  //     .map(response => {

  //       if(response.status==204)//when server will perform DELETE operation i.e logout
  //       {
  //         return Object.assign({name: 'server did not send anything'},{serverUri: environment.serverUri});//sending dummy data
  //       }
  //       return Object.assign(response.json(), {
  //         serverUri: environment.serverUri
  //       });
  //     })
  //     .catch((err) => this.handleError(err));
  // }

  handleError(error: Response) {
    if (error.status === 401) {
      window.localStorage.clear();
      window.location.href = environment.login_url;
    }
    return Observable.throw(error || { '_body': 'Server error' });
  }

  private requestBuilder(requestObject: any, reqType: string): Request {
    let method: RequestMethod;
    switch (requestObject.method) {
      case 'GET':
        method = RequestMethod.Get;
        break;
      case 'POST':
        method = RequestMethod.Post;
        break;
      case 'PUT':
        method = RequestMethod.Put;
        break;
      case 'PATCH':
        method = RequestMethod.Patch;
        break;
      case 'DELETE':
        method = RequestMethod.Delete;
        break;
      default:
        throw new Error('Property `method` is required for `http request`');
    }
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    const access_token = window.localStorage.getItem('token') || null;

    switch (requestObject.wukla) {
      case 'false': // if using wukla APIs
        this.baseUrl = environment.serverUri;
        break;
      default: // for calls with server token
        this.baseUrl = environment.wuklaServerUri;
        // const access_token = window.localStorage.getItem('consumer_token') || null;

    }

    const data = Object.assign({}, requestObject.data);
    if (reqType === 'server') {

      // const access_token = window.localStorage.getItem('token') || null;
      // if (access_token) {
        // headers.append('Authorization', 'JWT ' + access_token);
      // }

      headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

        const request: Object = {
          method: method,
          url: (this.baseUrl + requestObject.url),
          headers: headers,
          body: JSON.stringify(data),
          withCredentials: true,
        };
        return new Request(new RequestOptions(request));
    } else if (reqType === 'consumer-uuid') {

    // const access_token = window.localStorage.getItem('consumer_token') || null;
    // if (access_token) {
      // headers.append('Authorization', 'JWT ' + access_token);
    // }

      headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

      const request: Object = {
        method: method,
        url: (this.baseUrl + '/profile/' + this.getUUID() + requestObject.url),
        headers: headers,
        body: JSON.stringify(data),
        withCredentials: true,
      };
      return new Request(new RequestOptions(request));
    } else if (reqType === 'consumer') {

      // const access_token = window.localStorage.getItem('consumer_token') || null;
      // if (access_token) {
      //   headers.append('Authorization', 'JWT ' + access_token);
      // }

      headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

        const request: Object = {
          method: method,
          url: (this.baseUrl + requestObject.url),
          headers: headers,
          body: JSON.stringify(data),
          withCredentials: true,
        };
        return new Request(new RequestOptions(request));
    }

  }

  // upload on connect
  uploadFile(url, data) {

    const headers = new Headers();
    headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

    const request: Object = {
      method: 'POST',
      url: (environment.serverUri + url),
      headers: headers,
      body: data,
      withCredentials: true,
    };
    return this.http.request(new Request(new RequestOptions(request)))
      .map(response => {
        return Object.assign(response.json(), {
          serverUri: environment.serverUri
        });
      })
      .catch((err) => this.handleError(err));
  }

  uploadFileToWukla(url, data) {

    const headers = new Headers();
    headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

    const request: Object = {
      method: 'POST',
      url: (environment.wuklaServerUri + '/profile/' + this.getUUID() + url),
      headers: headers,
      body: data,
      withCredentials: true,
    };
    return this.http.request(new Request(new RequestOptions(request)))
      .map(response => {
        return Object.assign(response.json(), {
          serverUri: environment.serverUri
        });
      })
      .catch((err) => this.handleError(err));
  }

  downloadFile(url): Observable<Blob> {

    const headers = new Headers();
    headers.append('Content-Type', 'application/pdf');
    headers.append('X-CSRFToken', this.cookieService.get('csrftoken'));

    const request: Object = {
      method: 'GET',
      url: (environment.wuklaServerUri + '/profile/' + this.getUUID() + url),
      headers: headers,
      body: JSON.stringify({}),
      responseType: ResponseContentType.Blob,
      withCredentials: true,
    };

    return this.http.request(new Request(new RequestOptions(request)))
      .map(res => res.blob())
      .catch((err) => this.handleError(err));

  }

  getUUID() {
    return window.localStorage.getItem('uuid') || null;
  }

}

EDIT Here is questions array in reponse object in console.log tab.

questions: Array(4)
0:
help_text: "From which date do you want to start the Non Disclosure Agreement?"
required: true
slug: "agreement_date"
type: "DatePicker"
__proto__: Object
1:
help_text: "For how long should this NDA be for?"
required: true
slug: "agreement_validity"
type: "NumberYears"
__proto__: Object
2:
questions: (3) [{…}, {…}, {…}]
side_text: "Second Party Information"
__proto__: Object
3:
questions: (6) [{…}, {…}, {…}, {…}, {…}, {…}]
side_text: "Non Disclosure Agreement details"
__proto__: Object
length: 4
__proto__: Array(0)

and here is questions array from response in network tab.

questions: [{questions: [{slug: "agreement_date", type: "DatePicker", required: true,…},…],…},…]
0: {questions: [{slug: "agreement_date", type: "DatePicker", required: true,…},…],…}
questions: [{slug: "agreement_date", type: "DatePicker", required: true,…},…]
side_text: "General Information"
1: {questions: [,…], side_text: "First Party Information"}
questions: [,…]
side_text: "First Party Information"
2: {questions: [,…], side_text: "Second Party Information"}
questions: [,…]
side_text: "Second Party Information"
3: {,…}
questions: [{slug: "nda_purpose", type: "RadioButton",…}, {slug: "nda_confidentiality", type: "CheckBoxes",…},…]
side_text: "Non Disclosure Agreement details"

Solution

  • The questions arrays are the same when you get to the console.log(...) bit. However, it updats on real time (check the small i of information on your console just by the object:

    Here

    It will say something like "value below was evaluated right now", meaning it's not the value when you print it, it's the value when you open the object on the console.

    If you want to want it to be the same when you print it, you should print a copy of it:

    console.log(JSON.parse(JSON.stringify(object));
    

    Just in case you don't know where you are modifying it, it's here:

        this.questionsarray = response['questions'];
        let i = 0;
        for (const section  of this.questionsarray) {
          for (const question of section.questions) {
            this.questionsarray[i] = question;
            i++;
          }
        }
    

    this.questionarray and response.questionsis the same array, so since you are modifying one, you modify both.