1

I have an issue with my Angular10 application using Akita store.

When I start/refresh my application on my component page I see LOADING on my component.

However via the console it looks like the store has the items loaded and my console.logs are being triggered in the onInit.

When I refresh the application on the page where they should load it will not and it will just show 'loading'. But if I click the router link button to this page it will then load.

/models/post post.model.ts

export interface Post {
// fields here
}

/stores/post post.store.ts

export interface PostsState extends EntityState<Post, number> {
    posts: Post[];
    isLoaded: boolean;
}

export const getInitialState = () => {
    return {
        posts: [],
        isLoaded: false,
    };
};

@Injectable({
    providedIn: 'root'
})
@StoreConfig({name: ‘postsStore'})
export class PostsStore extends EntityStore<PostsState> {
    constructor() {
        super(getInitialState());
    }
}

/stores/user user.query.ts

@Injectable({ providedIn: 'root' })
export class PostsQuery extends QueryEntity<PostsState> {

  constructor(protected store: PostsStore) {
    super(store);
  }

  getPosts(): Observable<Post[]> {
    return this.select(state => state.posts);
  }

  getLoaded():Observable<boolean> {
    return this.select(state => state.isLoaded);
  }

  getIsLoading():Observable<boolean> {
    return this.selectLoading();
  }


}
import { ID } from '@datorama/akita';

services/posts posts.service.ts

@Injectable({ providedIn: 'root' })
export class PostsService {

  private API_URL = `${environment.apiUrl}`;


  constructor(private postsStore: PostsStore,
              private http: HttpClient) {}

  get() {
    return this.http.get<Post[]>(`${this.API_URL}/posts`)
     .pipe(
       tap(entities => this.postsStore.set(entities))
      );
  }

  add(post: Post) {
    this.postsStore.add(post);
  }

  update(id, post: Partial<Post>) {
    this.postsStore.update(id, post);
  }

visual/ visual.component.ts

ngOnInit(): void {
    console.log('STARTING'); // on page initial this shows
    this.postsQuery.getIsLoading().subscribe(res => this.loading = res);
    this.postsQuery.getPosts().subscribe(res => this.posts = res);
    this.postsQuery.getLoaded().pipe(
      take(1),
      filter(res => !res),
      switchMap(() => {
        this.postsStore.setLoading(true);
        console.log(‘TEST ‘A); // on page initial this shows
        return this.postsService.get();
      })
      ).subscribe(res => {
        this.postsStore.update(state => {
          console.log(‘TEST ‘B); // on page initial this shows
          return {
            posts: res
          };
        });
        this.postsStore.setLoading(false);
        console.log(‘TEST’ C);  // on page initial this shows
      }, err => {
        console.log(err);
        this.postsStore.setLoading(false); 
        console.log(‘TEST ‘D); // This does not show
      });
  }

visual/ visual.component.html

<div *ngIf="loading">
<p>
  LOADING
</p>
</div>   



<div *ngIf="!loading">
<div *ngFor="let post of posts>
{{post.name}}
<div>
</div>

1 Answers1

1

It would be nice to have this example on stackblitz to try it out (it's hard to get the problem without debugging it).

Also, I would suggest trying to add console.log to this.postsQuery.getIsLoading() subscription to debug it better.

But, for now I see two options:

  1. Try to add changeDetectorRef.detectChange() in the this.postsQuery.getIsLoading() subscription;

  2. The propblem might be relate to this issue https://github.com/datorama/akita/issues/653 (see stackblitz example), The rootcause of it is macking store update in the store subscription synchrounusly.

The way to fix it is delay this.postsStore.setLoading(true); (you could try to put it into setTimeout() or add some rxjs operator)