通过NGRX显示成功,错误消息的正确方法

时间:2018-02-18 18:05:37

标签: javascript angular ngrx ngrx-store

我知道这个问题的两个解决方案,第一个是将消息保持在你看不好的状态,第二个是订阅我当前用来显示消息的ActionSubject。 / p>

还有其他解决方案吗?另外如何在模板中设置CSS类,而不是在组件中?

以下是我的例子:



 this.actionSubject.subscribe(action => {
      if (action.type === fromActions.LOGIN_SUCCESS) {
        this.message$ = action.payload.message;
        this.messageClass = 'alert alert-success';
      }
      if (action.type === fromActions.LOGIN_FAILURE) {
        this.message$ = action.payload.error.message;
        this.messageClass = 'alert alert-danger';
        this.LoginForm.reset();
      }
    })




看起来太长了,而不是DRY,我应该在我期望收到消息的每个组件中执行此操作。

3 个答案:

答案 0 :(得分:3)

来自原始停靠栏https://github.com/ngrx/effects/blob/master/docs/intro.md

的示例

创建描述登录操作源的AuthEffects服务:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthEffects {
  constructor(
    private http: Http,
    private actions$: Actions
  ) { }

  @Effect() login$ = this.actions$
      // Listen for the 'LOGIN' action
      .ofType('LOGIN')
      // Map the payload into JSON to use as the request body
      .map(action => JSON.stringify(action.payload))
      .switchMap(payload => this.http.post('/auth', payload)
        // If successful, dispatch success action with result
        .map(res => ({ type: 'LOGIN_SUCCESS', payload: res.json() }))
        // If request fails, dispatch failed action
        .catch(() => Observable.of({ type: 'LOGIN_FAILED' }))
      );
}

通过EffectsModule.run提供服务以自动启动效果:

import { EffectsModule } from '@ngrx/effects';
import { AuthEffects } from './effects/auth';

@NgModule({
  imports: [
    EffectsModule.run(AuthEffects)
  ]
})
export class AppModule { }

注意:对于依赖于要引导的应用程序的效果(即依赖于路由器的效果),请使用EffectsModule.runAfterBootstrap。请注意,runAfterBootstrap只能在根模块中使用。

另外,您可以在此处查看有效使用后卫:https://toddmotto.com/preloading-ngrx-store-route-guards

答案 1 :(得分:1)

您可以采用许多方法将逻辑移至模板。

这是一种方法:

// component
public isSuccess = merge(
    this.actions.pipe(filter(x => x.type === 'SUCCESS'),mapTo(true)),
    this.actions.pipe(filter(x => x.type === 'FAILURE'),mapTo(false))
);
public message = merge(
    this.actions.pipe(filter(x => x.type === 'SUCCESS'),map(x => x.payload.message)),
    this.actions.pipe(filter(x => x.type === 'FAILURE'),map(x => x.payload.error.message))
);

// template
<div class="alert"
    [class.alert-success]="isSuccess | async"
    [class.alert-danger]="!(isSuccess | async)">
{{ message | async}}
</div>

这是另一个:

<div class="alert alert-success"
    *ngIf="(action | async).type === 'SUCCESS'">
    {{ (action | async).payload.message }}
</div>
<div class="alert alert-danger"
    *ngIf="(action | async).type === 'FAILURE'">
    {{ (action | async).payload.error.message }}
</div>

就表单重置而言,我猜你仍然需要订阅。如果您正在使用效果,那么您可以actions.ofType(...)而不是过滤器运算符。我不知道你使用的是什么版本的rxjs所以我使用的是可管理的语法。

如果你要在多个地方做同样的事情,那么我建议你设置一个封装了这个逻辑的组件。

答案 2 :(得分:0)

我将合并@Kliment Ru和@bygrace的答案,并举例说明我构建的用于将全局消息传递逻辑与小吃栏(材料)封装为可调度操作的内容。

  

message.action.ts

import { Action } from '@ngrx/store';

export const MESSAGE = '[Messages] Show Message';

export class Message implements Action {
    readonly type = MESSAGE;
    constructor(
        public payload: {
            message: string;
            action?: string;
            duration?: number;
            callback?: Function;
        }
    ) { }
}

非常简单,将快餐栏属性封装到ngrx动作中。

  

message.effect.ts

import { Injectable } from '@angular/core';

import { Effect, Actions } from '@ngrx/effects';
import * as MessageActions from '../actions/message.action';

import { tap, map } from 'rxjs/operators';
import { MatSnackBar } from '@angular/material';
import { first } from 'rxjs/operators/first';

@Injectable()
export class MessageEffects {

    constructor(
        private actions$: Actions,
        private snackBar: MatSnackBar
    ) { }

    @Effect({ dispatch: false })
    navigate$ = this.actions$
        .ofType(MessageActions.MESSAGE)
        .pipe(
            map((action: MessageActions.Message) => action.payload),
            tap(({ message, action, duration, callback }) => {
                duration = duration ? duration : 3000;

                // incase of an action assigned, subscribe to the snackbar, else just show the message
                if (callback) {
                    this.snackBar.open(message, action, { duration: duration })
                        .onAction()
                        .pipe(
                            first()
                        )
                        .subscribe(() => {
                            callback();
                        });
                } else {
                    this.snackBar.open(message, action, { duration: duration });
                }

            }));

}

听取动作并显示小吃栏的效果。

然后当你想使用它时,只需执行以下操作,

this.store.dispatch(new fromRoot.Message({ message: 'Something went wrong, please try again later' }));

一个简单的单行程序,它封装了应用程序中消息的整个逻辑和UI,其背后的好处是我可以使用任何库将我的快餐栏更改为我想要的任何内容,并且不得不仅仅更改代码一个地方。