Angular 6 ngIf не работает с моделями магазинов-редукторов ngrx - PullRequest
0 голосов
/ 28 декабря 2018

Я новичок в редуксе, и я читаю и работаю над этим в течение последних нескольких дней, но я продолжаю приходить к точке, где есть ноль ошибок и ноль предупреждений, хотя ожидаемое поведение не достигается.

По сути, у меня есть логин, который связывается с локальным MySQL и возвращает объект json, оттуда я бы хотел, чтобы появилось выпадающее меню.Если они администратор, то они должны увидеть больше опций в выпадающем меню.

Еще раз, ноль ошибок и ноль предупреждений.Я не знаю, что мне не хватает.

Ниже приведен мой файл user.state.ts:

import { User } from "./models/user.models";

export interface UserState {
  readonly user: User[];
}

Ниже приведен мой файл user.models.ts:

  export interface User {
  uName: string;
  isAdmin: number;
  ts: string;
  loggedIn: boolean;
}

Ниже приведен мой файл user.actions.ts:

import { Injectable } from "@angular/core";
import { Action } from "@ngrx/store";
import { User } from "../models/user.models";

export const LOGGEDIN_USER = "[USER] LoggedIn";
export const LOGGEDOUT_USER = "[USER] LoggedOut";

export class LoggedInUser implements Action {
  readonly type = LOGGEDIN_USER;

  constructor(public payload: User) {}
}

export class LoggedOutUser implements Action {
  readonly type = LOGGEDOUT_USER;

  constructor(public payload: User) {}
}

export type Actions = LoggedInUser | LoggedOutUser;

Ниже приведен мой файл редуктора:

import { Action } from "@ngrx/store";
import { User } from "../models/user.models";
import * as UserActions from "../actions/user.actions";

const initialState: User = {
  uName: "Guest",
  isAdmin: 0,
  ts: "2018-12-27 00:00:00",
  loggedIn: false
};

export function reducer(
  state: User[] = [initialState],
  action: UserActions.Actions
) {

  switch (action.type) {
    case UserActions.LOGGEDIN_USER:
      return [...state, action.payload];
    case UserActions.LOGGEDOUT_USER:
      return [...state, action.payload];
    default:
      return state;
  }
}

Теперь, когда мои службы получают JSON от APIЯ вызываю метонд, который отправляет на хранение:

addUser(uName, isAdmin, ts, loggedIn) {
this.store.dispatch(
  new UserActions.LoggedInUser({
    uName: uName,
    isAdmin: isAdmin,
    ts: ts,
    loggedIn: true
  })
);
}

В моем компоненте navbar у меня есть следующее:

import { Store } from "@ngrx/store";
import { User } from "../models/user.models";
import { UserState } from "../user.state";

Внутри класса:

  users: Observable<User[]>;
constructor(private store: Store<UserState>) {
  this.users = store.select("user");
}

В моей панели навигации у меня есть раскрывающееся меню, которое я хотел бы отобразить, как только эта модель войдет в систему со значением true:

<li *ngIf="users.loggedIn" ngbDropdown class="nav-item dropdown">

Я также попробовал user.loggedIn, UserActions.LoggedInUser.loggedIn,и т.д ...

И ничего не происходит.Выпадающее меню не видно в начале, и я подумал, что это здорово, но после входа в систему ничего не меняется.После того, как эта часть будет работать, я применю ту же логику к кнопкам входа и регистрации в панели навигации, за исключением того, что буду использовать! Users.loggedIn.

Заранее спасибо - извините за опечатки или грамматические ошибкино я усталаЯ занимался этим пару дней.

1 Ответ

0 голосов
/ 29 декабря 2018

В случае, если кто-то еще проходит через это, моё решение следующее, и у меня есть вопрос в конце моего решения.

Следующее - мой файл 'redurs / index.ts':

import { ActionReducerMap } from "@ngrx/store";
import { reducer, User } from "./user.reducer";

interface AppState {
  appReducer: User;
}

export const reducers: ActionReducerMap<AppState> = {
  appReducer: reducer
};

Который также импортирует мой файл 'redurs / user.reducer.ts':

import * as UserActions from "../actions/user.actions";
/* use mTstamp function to calculate timestamp within typescript */
function mTstamp() {
  let d = new Date();
  let mMonth;
  if (d.getMonth() < 10) {
    mMonth = "0" + d.getMonth();
  } else {
    mMonth = d.getMonth();
  }
  let mDate;
  if (d.getDate() < 10) {
    mDate = "0" + d.getDate();
  } else {
    mDate = d.getDate();
  }
  let mHours;
  if (d.getHours() < 10) {
    mHours = "0" + d.getHours();
  } else {
    mHours = d.getHours();
  }
  let mMins;
  if (d.getMinutes() < 10) {
    mMins = "0" + d.getMinutes();
  } else {
    mMins = d.getMinutes();
  }
  let mSecs;
  if (d.getSeconds() < 10) {
    mSecs = "0" + d.getSeconds();
  } else {
    mSecs = d.getSeconds();
  }
  let mTimeStamp =
    d.getFullYear() +
    "-" +
    mMonth +
    "-" +
    mDate +
    " " +
    mHours +
    ":" +
    mMins +
    ":" +
    mSecs;
  console.log("mTimeStamp: ", mTimeStamp);
  return mTimeStamp;
}

export interface User {
  uName: string;
  isAdmin: boolean;
  ts: string;
  loggedIn: boolean;
}

const initialState: User = {
  uName: "Guest",
  isAdmin: false,
  ts: mTstamp(),
  loggedIn: false
};

export function reducer(appUserState = initialState, action): User {
  switch (action.type) {
    case UserActions.ACTION_LOGOUT:
      return {
        ...appUserState,
        uName: "Guest",
        isAdmin: false,
        ts: mTstamp(),
        loggedIn: false
      };
    case UserActions.ACTION_LOGIN:
      return {
        ...appUserState,
        uName: action.payload,
        isAdmin: action.payload,
        ts: action.payload,
        loggedIn: action.payload
      };
  }
  return appUserState;
}

Файл index.ts также импортирует файл 'actions / user.actions.ts':

export const ACTION_LOGIN = "LoggedIn";
export const ACTION_LOGOUT = "LoggedOut";

Это все, что мне нужно для создания редукса для входа и выхода.

В компонентах большая часть моей логики проходила через файл служб, который обрабатывает вход черезthe db:

import { Injectable } from "@angular/core";
import { Router } from "@angular/router";
import { HttpClient } from "@angular/common/http";
import { Component } from "@angular/core";
import { Store } from "@ngrx/store";
import { User } from "./reducers/user.reducer";
import { Observable } from "rxjs";
import * as UserActions from "./actions/user.actions";

@Injectable({
  providedIn: "root"
})
export class ShoppingCartValuesService {
  public shoppingCartValues = "n";
  public loginObj: any;
  public uri = "<path to some local php api>";
  user: Observable<User[]>;

  constructor(
    private http: HttpClient,
    private router: Router,
    private store: Store<any>
  ) {}

  getLogin(email, password) {
    return new Observable(observe => {
      this.http
        .get(this.uri + "?name=" + email + "&pass1=" + password)
        .subscribe(res => {
          this.loginObj = res;
          if (this.loginObj.uName != null || this.loginObj.uName !== "Guest") {
            this.loginObj.loggedIn = true;
            this.getState();
            this.updateState({
              action: UserActions.ACTION_LOGIN,
              payload: this.loginObj
            });
          }
          observe.next(res);
          this.router.navigate(["/"]);
        });
    });
  }

  getState() {
    return this.store.select("appReducer");
  }

  updateState(obj) {
    this.store.dispatch({
      type: obj.action,
      payload: obj.payload
    });
    console.log("this.loginObj from updateState: ", this.loginObj);
  }

  logout() {
    const logoutObj = {
      action: UserActions.ACTION_LOGOUT,
      payload: {
        uName: "Guest",
        isAdmin: 0,
        ts: "2018-12-28 00:00:00",
        loggedIn: false
      }
    };
    this.store.dispatch({
      type: logoutObj.action,
      payload: logoutObj.payload
    });
    this.router.navigate(["/login"]);
  }
}

Как видите, когда возвращается результат (res), я проверяю, есть ли имя пользователя в объекте JSON, что означает, что php нашел совпадение.Оттуда getState (), которая выбирает хранилище «appReducer», а updateState () отправляет изменения в хранилище.

Ниже приведена соответствующая часть панели навигации, к которой я пытался выполнить, и этоприводит к вопросу, который у меня есть, но я поставлю его в конце:

  <li *ngIf="!appUserState.loggedIn" class="nav-item">
    <a
      class="nav-link"
      data-toggle="tooltip"
      title="Register"
      id="register"
      routerLink="/register"
      ><span>Register</span></a
    >
  </li>
  <li *ngIf="!appUserState.loggedIn" class="nav-item">
    <a
      class="nav-link"
      data-toggle="tooltip"
      title="Login"
      routerLink="/login"
      id="login-btn"
      ><span>Login</span></a
    >
  </li>
  <li *ngIf="appUserState.loggedIn" ngbDropdown class="nav-item dropdown">
    <a
      ngbDropdownToggle
      class="nav-link dropdown-toggle"
      href="//:javascript"
      id="dropdown01"
      data-toggle="dropdown"
      aria-haspopup="true"
      aria-expanded="false"
      >More</a
    >
    <div ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdown01">
      <a
        class="dropdown-item"
        data-toggle="tooltip"
        title="My orders"
        routerLink="/my-orders"
        id="search-records"
        ><span>Search Records</span></a
      >
      <a
        *ngIf="appUserState.isAdmin.isAdmin != '0'"
        class="dropdown-item"
        data-toggle="tooltip"
        title="Admin search records"
        routerLink="/admin/orders"
        id="admin-search-records"
        ><span>Admin Search Records</span></a
      >
      <a
        *ngIf="appUserState.isAdmin.isAdmin != '0'"
        class="dropdown-item"
        data-toggle="tooltip"
        title="Admin products"
        routerLink="/admin/products"
        id="admin-products"
        ><span>Admin Products</span></a
      >

Ниже приведена соответствующая часть файла app.module.ts:

import { StoreModule } from "@ngrx/store";
import { reducers } from "./reducers/";

Позже в массиве import:

StoreModule.forRoot(reducers, {}),

Теперь это работает на 100% вместе с нулевыми ошибками или предупреждениями.Однако, как вы, наверное, заметили, мне пришлось применить несколько взломать в панели навигации - * ngIf = "appUserState.isAdmin.isAdmin! = '0'"

Почему система увидит appUserState какобъект внутри объекта?Другими словами, почему он не распознал * ngIf = "appUserState.isAdmin! = '0'" - только когда я увидел, что appUserState.isAdmin был тем, чем я думал appUserState, я понял, что это позволит оценитьправда, потому что объект существовал.Когда я использовал консоль, чтобы открыть объект, и обнаружил внутри него объект, который имел свойство isAdmin, тогда я решил проблему, добавив еще один .isAdmin

Если кто-то может мне это объяснить,тогда это будет вишня поверх глазури.В противном случае, он работает, и этого пока достаточно.

Заранее спасибо

...