Search code examples
angularngrxngrx-effectsngrx-store

Best way to load data in model, Angular 2


Here is some information about my project:

  1. I'm getting posts data user @ngrx store and effects.
  2. Post model has userId.
  3. When I render posts, I wan't to show post.data and post.user.name

Is there any way to eager load user data with posts?

What would be best solution for this problem?


This is how post.model looks:

import { User } from './user.model';

export class Post {
    userId: number;
    id: number;
    title: string;
    body: string;
    user?: User;
}

I'm not getting whole user object with post items. I'm only getting userIds.


EDIT: This is how I fetch and render posts:

post.effects.ts

@Injectable()
export class PostEffects {

    @Effect()
    posts$: Observable<Action> = this.actions$
        .ofType(postActions.LOAD_LIST)
        .debounceTime(300)
        .startWith(new postActions.LoadListAction())
        .switchMap(() => {
            return this.postsService.all()
                .map((posts: Post[]) => new postActions.LoadListSuccessAction(posts))
                .catch(error => of(new postActions.LoadListFailAction(error)));
        });

    constructor(
        private actions$: Actions,
        private postsService: PostsService
    ) { }

}

posts.component.ts

export class PostsComponent {

  posts$: Observable<Post[]>;
  loaded$: Observable<boolean>;

  constructor(private store: Store<State>) {
    this.posts$ = store.select(rootReducers.getPostItems);
    this.loaded$ = store.select(rootReducers.getPostLoaded);
  }

}

posts.component.html

<div class="content">
    <app-post-list [posts]="posts$ | async"></app-post-list>
</div>
<!-- /.content -->

EDIT 2: Post reducer file content

post.reducer.ts

export function reducer(state = initialState, {type, payload}: postActions.Actions): State {
    switch (type) {
        case postActions.LOAD_LIST: {
            return Object.assign({}, state, {
                loading: true
            });
        }

        case postActions.LOAD_LIST_SUCCESS: {
            return {
                loaded: true,
                loading: false,
                items: payload,
                selectedItem: state.selectedItem
            };
        }

        default: {
            return state;
        }
    }
}

Solution

  • I've found solution but I don't think it's perfect.

    1. I'm getting all users from posts.component.ts and inputing them into post-list component.
    2. The inside post-item component I'm filtering all users with post.userId and taking one user.

    I thought that would be slow, but it's not. And that way I'm making two http requests only. Posts and Users request.

    For now I couldn't found better solution. If you have one, I will be happy integrating it.


    EDIT:

    Huh, I think I've found solution:

    Handle Multiple Angular 2 Models in ngrx with Computed Observables,

    In this article I've found code snippet, and it worked for me:

    export class UsersItemsService {
      constructor(private store: Store<AppStore>) { }
    
      getUsersItems(): Observable<UserItems[]> {
        const users$: Observable<User[]> = this.store.select('users');
        const items$: Observable<Item[]> = this.store.select('items');
    
        return Observable.combineLatest(users$, items$, (users, items) => {
          return users.map(user => Object.assign({}, user, {
            items: items.filter(item => item.userId === user.id)
          }));
        });
      }
    }