简体   繁体   中英

Angular 8 bind ngrx state to component

I am new to Angular and I want to bind some Classnames in my HTML to some values in my states. At first I had only one state, which was only some boolean value and everything worked fine. Now I changed the state to an object, so that I can save more information in it. Although I am using more or less the same approach as before but the classname doesn't change. The state does change. Can someone please tell me what my mistake is and if there is another more appropriate way to do the things I am trying to do please tell me that also.

The angular version is 8.2.14.

This is my code:

reducer.ts:


export type ShoppinCartState = {
  CartIsOpen: boolean;
};

export type HamburgerState = {
  MenuIsOpen: boolean;
};

export function hamburgerReducer(
  state: HamburgerState = { MenuIsOpen: false },
  action: Action
) {
  switch (action.type) {
    case "HAMBURGER.TOGGLE":
      console.log("HAMBURGER.Toggle called " + state.MenuIsOpen);
      return {
        ...state,
        MenuIsOpen: !state.MenuIsOpen
      };
    case "HAMBURGER.CLOSE":
      return {
        ...state,
        MenuIsOpen: false
      };
    case "HAMBURGER.OPEN":
      return {
        ...state,
        MenuIsOpen: true
      };
    default:
      return state;
  }
}

export function shoppingCartReducer(
  state: ShoppinCartState = { CartIsOpen: false },
  action: Action
) {
  switch (action.type) {
    case "CART.TOGGLE":
      console.log("Tooggle cart called " + state.CartIsOpen);
      return {
        ...state,
        CartIsOpen: !state.CartIsOpen
      };
    default:
      return state;
  }
}

This is my Component. When the user clicks on the Hamburger Icon one action is dispatched which changes the state. There is also another part which is binded to the state. When the value is true, the classname should be "visible".

<app-hamburger-icon (click)="onHamburgerIconClick()"></app-hamburger-icon>
  <div id="Logo"><a (click)="onLinkClick()" routerLink="/">E99-EsAns</a></div>
  <ul [ngClass]="{ visible: hamburgerClicked$ | async }">

And that's the component.ts file

import { Store } from "@ngrx/store";
import { Observable } from "rxjs";
import { HamburgerState } from "src/app/reducer";

@Component({
  selector: "app-navigationbar",
  templateUrl: "./navigationbar.component.html",
  styleUrls: ["./navigationbar.component.css"]
})
export class NavigationbarComponent implements OnInit {
  hamburgerClicked$: Observable<boolean>;

  constructor(private store: Store<HamburgerState>) {
    this.hamburgerClicked$ = this.store.select("MenuIsOpen");
  }

  ngOnInit() {}

  onHamburgerIconClick() {
    console.log(this.hamburgerClicked$);
    this.store.dispatch({ type: "HAMBURGER.TOGGLE" });
  }

  onLinkClick() {
    this.store.dispatch({ type: "HAMBURGER.CLOSE" });
  }

  onShoppingCartIconClicked() {
    this.store.dispatch({ type: "CART.TOGGLE" });
  }
}

Some snippet of my app.module.ts

import { hamburgerReducer, shoppingCartReducer } from "./reducer";
...
...
...
imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    HttpClientModule,
    StoreModule.forRoot({
      hamburgerReducer: hamburgerReducer,
      shoppingCartReducer: shoppingCartReducer
    })
  ],

When you inject the Store into a component you operate on the structure of the global state. So the select has to 'select' into this structure to access the correct object.

Only the reducer functions get handed a slice of this global state. We can see that most likely in app.module.ts where you define your store:

    StoreModule.forRoot({
      hamburgerReducer: hamburgerReducer,
      shoppingCartReducer: shoppingCartReducer
    })

Best practice is to create a interface State that describes your store structure:

export interface State {
   hamburgerReducer: HamburgerState;
   shoppingCartReducer: ShoppingCartState;
}

and then use this interface when injecting the store:

constructor(private store: Store<State>)

then you can select the hamburger menu-state via:

this.store.select(state => state.hamburgerReducer.MenuIsOpen)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM