0

In Angular 8 in a component I am running the following line:

  console.log(this.array);

In the browser, in developer mode I see the following result on the console:

enter image description here

So it clearly has some content. The following line writes '0' on the console:

console.log(this.array.length);

Here is the stackblitz code: https://stackblitz.com/edit/angular-ivy-g57vnv

In app component the array and array.length is logged on the console.

The content of the array is created as the following: in the service.service.ts, a GET request for authentication is fetched to a sample-backend hosted by Crowdvalley. As the cv-auth header is not the right one (on purpose), the response is an error. If the response does not contain the outcome 'success', to the array a string of 'false' is pushed (see ServiceService). If you look at the web app (https://angular-ivy-g57vnv.stackblitz.io) in developer mode, you see that the array has its fetched content, but it is still written that its length is 0.

Why is that? How can I investigate the true length? How can I access its content from the component?

ArminB
  • 35
  • 1
  • 8

3 Answers3

0

Change your isLoggedIn Method to :-

async isLoggedIn() {
    const array = [];
    const proxyurl = 'https://cors-anywhere.herokuapp.com/';
    const url = 'https://api.sandbox.crowdvalley.com/v1/nzz/authenticate'; // site that doesn’t send Access-Control-*
    const myHeaders = new Headers();
    myHeaders.append('cv-auth', this.adminHeader);
    myHeaders.append('Cookie', this.cookie);

    // tslint:disable-next-line:prefer-const
    let requestOptions = {
      method: 'GET',
      headers: myHeaders
    };
    await new Promise((resolve,reject) => fetch(proxyurl + url, requestOptions)
      .then(response => response.json())
      .then(result => {
        if (result.outcome === 'success') {
          array.push('true');
          resolve();
        } else {
          array.push('false');
          resolve();
        }
      })
      .catch(error => {
        console.log('error', error);
        resolve();
      }));
    return array;
  }

and component ngOnInit Code To :-

ngOnInit(){
      this.service.isLoggedIn().then((array) => {
        this.array = array;
        console.log(this.array);
        console.log(this.array.length);
      })
    }
Aakash Garg
  • 10,649
  • 2
  • 7
  • 25
  • this is kind of an odd solution - it makes the internals of the isLoggedIn method pseudo-synchronous by using async/await, but ultimately returns a promise anyway, when you could do this without the async/await and just return a promise. So it's more complicated than it needs to be. – GreyBeardedGeek Jun 05 '20 at 13:22
  • @GreyBeardedGeek, i didn't knew actual scenario the OP wanted to achieve, what he is doing with that array. question might be having an example. that's why went for this approach. – Aakash Garg Jun 05 '20 at 13:25
  • because he could have directly returned that fetch. that too returns a promise. just a true false array might not be the real case of OP. – Aakash Garg Jun 05 '20 at 13:27
  • 1
    I think the real issue it Single Responsibility: Why is "isLoggedIn()` returning a promise of an array in the first place? (OP design issue, not here). The service ideally would have a private "logon()" and "isLoggedOn()" would return a straight bool... – Austin T French Jun 05 '20 at 13:32
0

It's because ServiceService.isLoggedIn() returns an array, makes an asynchronous call and then mutates said array. This is the wrong pattern - isLoggedIn() should return something asynchronous, either a Promise or, better yet (we're in an Angular project after all) an Observable.

As usual, you can find all kinds of recipes in this thread: How do I return the response from an asynchronous call?

(If in console.log you get an array with some content, then it's only because of the lazy evaluation of objects in the console: it's actual value is evaluated only and you click on that arrow).

mbojko
  • 13,503
  • 1
  • 16
  • 26
0

You are calling isLoggedIn() method as if it is synchronous, which it is not - it does a fetch(), which returns a promise.

So the way that method is written, it returns an empty array immediately and then later, when the promise is resolved, pushes the result into the array.

You should return a promise instead, and work with the promise in your component.

Also, I suppose that there's no real problem with using fetch and promises, but Angular provides higher-level functionality with it's HttpClient and rxjs Observables, which is the "usual" way api calls are done in Angular.

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67