1

I have an angular component that fetches data from the server, then transforms it before assigning it to a variable:

class Component {
  data = [];

  ngOnInit() {
    this.store.select(data).pipe(
      map(data => { this.data = this.transformData(data); })
    ).subscribe();
  }

  transformData(data) {
    // data is an array of data
    return data.map(item => item);
  }
}

The above is a simplified version of what I'm doing, the transform method does more but it's irrelevant.

then I try to do a for loop using the data but it wont show me anything, and there are no errors being thrown either:

<div *ngFor="let item of data|async">
  {{ item.prop1 }} {{ item.prop2 }}
</div>

I'm not sure why this is happening - I'm used to react where I pass in props or update the state and the component re-renders, what's the workflow in angular?

I tried this solution but it still wont show me any data:

class Component {
  data = [];

  ngOnInit() {
    this.store.select(data).pipe(
      map(data => { this.data = this.transformData(data); })
    ).subscribe();
  }

  transformData(data) {
    // data is an array of data
    // notice 'of()'
    return of(data.map(item => item));
  }
}

To clarify, I do see the value of this.data change when I console.log, but the html is not rendering the data

7
  • Before i attempt to help you with this: Please post all of the relevant code, what is store ?. Also, Why isn't your Component implementing OnInit. The OnInit method will not be called otherwise. Use a constructor(){} to call your function if you do not intend to use ngOnInit's lifecycle event. Commented Feb 5, 2019 at 15:04
  • the code is minimal, I removed everything that is not relevant to the question. The store is a redux store Commented Feb 5, 2019 at 15:05
  • well... The fact that you are not explicitly implementing OnInit in your component may be error enough to cause this behaviour. Commented Feb 5, 2019 at 15:06
  • I'm implementing it, but it's removed from this because that's not where the issue is Commented Feb 5, 2019 at 15:06
  • @Joel Whether or not implementing OnInit, Angular will call the method if it exists. Angular instead inspects directive and component classes and calls the hook methods if they are defined. Angular finds and calls methods like ngOnInit(), with or without the interfaces. Here is the official docs: angular.io/guide/… Commented Feb 5, 2019 at 15:06

4 Answers 4

1

In order to use async, you can pass Observable or Promise to *ngFor. Therefore, you need to assign the return value of this.store.select to data without subscribe:

class Component {
  data: Observable<any>;

  ngOnInit() {
    this.data = this.store.select(data).pipe(
      map(result => { return this.transformData(result); })
    );
  }

  transformData(data) {
    // data is an array of data
    return data.map(item => item);
  }
}

If you won't do any modifications in transformData method, you can remove pipe.

class Component {
      data: Observable<any>;

      ngOnInit() {
        this.data = this.store.select(data);
      }

 }
Sign up to request clarification or add additional context in comments.

Comments

0

Not really sure what you're doing in the transformData method. You're essentially returning the same data as is.

Try this though:

class Component {
  data$: Observable<any[]>;

  ngOnInit() {
    this.data$ = this.store.select(data).pipe(
      map(data => this.transformData(data))
    );
  }

  transformData(data) {
    return data.map(item => item);
  }
}

And then in your template:

<div *ngFor="let item of data$ | async">
  {{ item.prop1 }} {{ item.prop2 }}
</div>

1 Comment

transformData was simplified because it's not the focus of the question
0

If you are sure that the error doesn't lie within your service.

Then maybe you can try something like this:

class Component {
  private data = Observable<Array<any>>;

  public ngOnInit() {
    this.store.select(data).pipe(
      map(data => { this.data = this.transformData(data); })
    );
  }

  private transformData(data): Observable<any> {
    // data is an array of data
    // notice 'of()'
    return of(data.map(item => item));
  }
}

HTML:

<div *ngFor="let item of data | async">
    {{item.prop}}
</div>

Since I cant see how your service looks like, i'm going to have to assume...

I would advice you to use promises here instead as I've found them more easy to work with in cases where async is sought after. Also, instead of passing the pipe here, do it in your service. That way, you only have raw data to spit out to the HTML-view, no conversions in the controller needed, and that way you know that you have data (because you can get it from the service at an earlier stage and not the controller).

Comments

0

you can use like this.

    class Component {
      data = [];

      ngOnInit() {
        this.store.select(data).pipe(
          map(data => this.transformData(data))
        ).subscribe(result=> { this.data =result});
      }

      transformData(data) {
        // data is an array of data
        return data.map(item => item);
      }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.