Hello i created this ngrx selector
Path: src\app\store\navigation\navigation.selectors.ts
export const getNavigationState = createFeatureSelector<NavigationState>('navigation');
const getNavigation = createSelector(
getNavigationState,
(state) => {
return state.entities;
}
)
/**
* Get Arrays Of all Categories and submenu
*/
export const getFullMenu = createSelector(
getNavigation,
(state) => {
return state.menu
}
)
/**
* Get Arrays Of all Categories and submenu
*/
export const fullMenuCat = createSelector(
getFullMenu,
(categories) => {
categories.map((category) => {
return {title: category.title, url: category.url}
})
}
)
I don't know why, but when i call my observable in my component i have this issue:
ERROR TypeError: Cannot read properties of undefined (reading 'map')
This is my data from data.json
Path: src\datas\subnav.json
[
{
"id": "angular",
"title": "Angular stuff",
"url": "/angular",
"links": [
{
"name": "Components",
"url": "#"
},
{
"name": "Directives",
"url": "#"
},
{
"name": "Services",
"url": "#"
},
{
"name": "Pipe",
"url": "#"
},
{
"name": "Other",
"url": "#"
}
]
}
]
Those datas are used by ngrx effects
Path: src\app\store\navigation\navigation.effects.ts
read$ = createEffect(() => this.actions.pipe(
ofType(fromActions.Types.READ),
switchMap(() => {
return this.navigationService.getCategories().pipe(
map(data => {
return new fromActions.ReadSuccess(data);
})
)
})
))
And finally this is the Navigation interface
Path: src\app\store\navigation\navigation.models.ts
import { Category } from "@app/models/backend";
export interface Navigation {
isNavOpen: boolean,
currentCategory: string,
menu: Array<Category>,
lastUrlVisited: string
}
and the Category interface
Path: src\app\models\backend\categorie\index.ts
export interface Category {
id: string,
title: string,
url: string,
links: Array<Link>
}
export interface Link {
name: string,
url: string,
}
this is the ts file of my component
Path: src\app\components\header\header.component.ts
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { select, Store } from '@ngrx/store';
/**State */
import * as fromRoot from '@app/store';
import * as fromNavigation from '@app/store/navigation';
import { Observable } from 'rxjs';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderComponent implements OnInit {
fullMenuCat$: Observable<any>;
constructor(
private store: Store<fromRoot.State>,
) {
}
ngOnInit(): void {
this.store.dispatch(new fromNavigation.Read )
this.fullMenuCat$ = this.store.pipe(select(fromNavigation.fullMenuCat));
}
}
and the fullMenuCat$ observable call in my html
Path: src\app\components\header\header.component.html
<nav *ngIf="fullMenuCat$ | async as fullMenuCat">
<ol class="header__categories__nav">
<li #link *ngFor="let menuCat of fullMenuCat" class="header__categories__navitem" (mouseover)="moveMarker($event)" (mouseout)="resetMarkerPos()" routerLinkActive="header__categories__navitem-active" >
<a class="categories-a" routerLink="{{menuCat.url}}">{{menuCat.title}}</a>
</li>
</ol>
</nav>
I'm on this problem since 3 days and I don't know what I need to do. For more clarity here is a repo with my project: https://github.com/orphen92/angular-demo.git
You can run the projet with "npm run start command"
And a live url https://orphen92.github.io/angular-demo/angular
I try to create the most scallable architecture, so my code is explosed in many parts and i can't link all the code here (always for clarity).
I hope you can help me
You probably just need to give your store an initial state for that
categories. Or use optional chaining combine with nullish coalescing to give your selector a default value ifcategoriesis empty, like this:Since you're performing data fetching,
categoriesis always going to be empty the first time your selector trying to read it, this is why you should always give your state some initial values