资讯专栏INFORMATION COLUMN

在Angular中使用类Redux工具—ngrx/store

bitkylin / 2119人阅读

摘要:因为我们正好要使用,此时我们就可以用的服务来监听了当然,我们不能忘了清空订阅最后一步就是在有返回的时候调用表单的现在我们可以在组件里显示提醒了

原文:Connect Angular Forms to @ngrx/store

这篇文章中,我们将要讨论如何用ngrx/effects连接Angular表单和ngrx/store

我们最终的结果是这样的

ew-story0.component.ts

@Component({
  selector: "new-story-form",
  template: `
    
...controls
Success!
{{error}}
}) class NewStoryFormComponent {...}

The Reducer

方便起见,我们会写一个简单的reducer来组织管理我们应用里的所有的表单

状态(the state)将由一个用ID作为key,表格数据作为value的简单对象构成

举个例子

connect-form.reducer.ts

const initialState = {
  newStory: {
    title: "",
    description: ""
  },
  contactUs: {
    email: "",
    message: ""
  }
}

export function forms(state = initialState, action) {
}

我们先构建一个action——UPDATE_FORM。这个action由两个key:path和value组成

connect-form1.reducer.ts

store.dispatch({
  type: UPDATE_FORM,
  payload: {
    path: "newStory",
    value: formValue
  }
});

然后这个reducer将负责更新state

connect-form2.reducer.ts

export function forms(state = initialState, action) {
  if(action.type === UPDATE_FORM) { 
                       // newStory:           formValue
    return { ...state, [action.payload.path]: action.payload.value }
  }
}
连接表单的组件——ConnectForm Directive 获取State

我们想要基于state更新表单,所以我们需要path作为输入,然后取出store中正确的片段

connect-form.directive.ts

@Directive({
  selector: "[connectForm]"
})
export class ConnectFormDirective {
  @Input("connectForm") path: string;

  constructor(private formGroupDirective: FormGroupDirective,
    private store: Store ) {
      
    ngOnInit() {
      // Update the form value based on the state
      this.store.select(state => state.forms[this.path]).take(1).subscribe(formValue => {
        this.formGroupDirective.form.patchValue(formValue);
      });
    }
  }
}

我们抓取表单directive实例然后从store里更新表单数据

更新State

当表单数据改变时我们也需要更新表单状态。我们可以通过订阅(subscribe)这个valueChanges的可观察对象(observable)然后调度(dispatch)这个UPDATE_FORM的action来获取值

connect-form1.directive.ts

this.formChange = this.formGroupDirective.form.valueChanges
  .subscribe(value => {
    this.store.dispatch({
      type: UPDATE_FORM,
      payload: {
        value,
        path: this.path, // newStory
      }
    });
})

这就是表单和State同步所要做的全部工作了

通知和重置

有两件事我们要在这个部分完成

基于HTTP响应返回来显示通知给用户——我们需要保证通知直接传给组件并且不储存信息在store里

有两点原因

通常,没有其他的组件需要这个信息

我们不想每次都重置store

当提交成功时重置表单

我们将让Angular尽其所能,处理好前端表单校验并重置表单

成功的Action

成功的Action包含表单的path属性所以我们可以知道到底哪个表单需要重置,同时什么时候需要去使用(emit)这个成功的事件

connect-form2.directive.ts

const FORM_SUBMIT_SUCCESS = "FORM_SUBMIT_SUCCESS";
const FORM_SUBMIT_ERROR = "FORM_SUBMIT_ERROR";
const UPDATE_FORM = "UPDATE_FORM";

export const formSuccessAction = path => ({
  type: FORM_SUBMIT_SUCCESS,
  payload: {
    path
  }
});
异常的Action

同成功的action一样,因为有path的存在,我们也知道何时去使用(emit)错误异常 的事件

connect-form3.directive.ts

export const formErrorAction = ( path, error ) => ({
  type: FORM_SUBMIT_ERROR,
  payload: {
    path,
    error
  }
});

我们需要创建 成功 和 错误异常 的输出 然后 监听 FORM_SUBMIT_ERRORFORM_SUBMIT_SUCCESS 的 action。

因为我们正好要使用 ngrx/effects ,此时我们就可以用 Action 的服务(service)来监听actions了

connect-form3.directive.ts

@Directive({
  selector: "[connectForm]"
})
export class ConnectFormDirective {
  @Input("connectForm") path : string;
  @Input() debounce : number = 300;
  @Output() error = new EventEmitter();
  @Output() success = new EventEmitter();
  formChange : Subscription;
  formSuccess : Subscription;
  formError : Subscription;

  constructor( private formGroupDirective : FormGroupDirective,
               private actions$ : Actions,
               private store : Store ) {
  }

  ngOnInit() {
    this.store.select(state => state.forms[this.path])
      .debounceTime(this.debounce)
      .take(1).subscribe(val => {
      this.formGroupDirective.form.patchValue(val);
    });

    this.formChange = this.formGroupDirective.form.valueChanges
      .debounceTime(this.debounce).subscribe(value => {
        this.store.dispatch({
          type: UPDATE_FORM,
          payload: {
            value,
            path: this.path,
          }
        });
      });

    this.formSuccess = this.actions$
      .ofType(FORM_SUBMIT_SUCCESS)
      .filter(( { payload } ) => payload.path === this.path)
      .subscribe(() => {
        this.formGroupDirective.form.reset();
        this.success.emit();
      });

    this.formError = this.actions$
      .ofType(FORM_SUBMIT_ERROR)
      .filter(( { payload } ) => payload.path === this.path)
      .subscribe(( { payload } ) => this.error.emit(payload.error))
  }
}

当然,我们不能忘了清空订阅

connect-form4.directive.ts

ngOnDestroy() {
  this.formChange.unsubscribe();
  this.formError.unsubscribe();
  this.formSuccess.unsubscribe();
}

最后一步就是在有返回的时候调用表单的actions

connect-form4.directive.ts

import {
  formErrorAction,
  formSuccessAction
} from "../connect-form.directive";

@Effect() addStory$ = this.actions$
  .ofType(ADD_STORY)
  .switchMap(action =>
    this.storyService.add(action.payload)
    .switchMap(story => (Observable.from([{
      type: "ADD_STORY_SUCCESS"
    }, formSuccessAction("newStory")])))
    .catch(err => (Observable.of(formErrorAction("newStory", err))))
  )

 

现在我们可以在组件里显示提醒了


ew-story.component.ts

 @Component({
  selector: "new-story-form",
  template: `
    
...controls
Success!
{{error}}
` }) class NewStoryFormComponent { constructor(private store: Store ) {} onError(error) { this.error = error; } onSuccess() { this.success = true; } submit() { // You can also take the payload from the form state in your effect // with the withLatestFrom observable this.store.dispatch({ type: ADD_STORY, payload: ... }) } }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84215.html

相关文章

  • Immutable & Redux in Angular Way

    摘要:来源于社区,时至今日已经基本成为的标配了。部分很简单,要根据传入的执行不同的操作。当性能遇到瓶颈时基本不会遇到,可以更改,保证传入数据来提升性能。当不再能满足程序开发的要求时,可以尝试使用进行函数式编程。 Immutable & Redux in Angular Way 写在前面 AngularJS 1.x版本作为上一代MVVM的框架取得了巨大的成功,现在一提到Angular,哪怕是已...

    lunaticf 评论0 收藏0
  • 前端每周清单半年盘点之 Angular

    摘要:延伸阅读学习与实践资料索引与前端工程化实践前端每周清单半年盘点之篇前端每周清单半年盘点之与篇前端每周清单半年盘点之篇 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎关注【前端之巅】微信公众号(ID:frontshow),及时获取前端每周清单;本文则是对于半年来发布的前端每周清单...

    LeviDing 评论0 收藏0
  • #私藏项目实操分享# 介绍一款开源电商网站的购物车添加功能的实现

    摘要:目前电商领域有两款比较出名的开源电商网站解决方案,分别是基于开发框架,代号为的开源项目,以及基于的作为开源项目的开发成员之一,今天我想通过本文,给大家介绍一下我们平时购物时最常使用到的功能之一,添加产品到购物车的技术实现。 目前电商领域有两款比较出名的开源电商网站解决方案,分别是基于 Angular 开发框架,...

    不知名网友 评论0 收藏0
  • Angular 4 简单入门笔记

    摘要:首先,我们需要在入口页面的中配置根路径然后创建一个路由模块路由配置在主模块中导入配置好的路由模块而在页面中需要一个容器去承载上面代码中的定义了用户点击后的路由跳转,定义该路由激活时的样式类。 刚实习的时候用过AngularJS,那时候真的是连原生JavaScript都不会写,依样画葫芦做了几个管理后台。然后突然换项目了,AngularJS就不写了,感觉前前后后接触了一年多的Angula...

    whlong 评论0 收藏0
  • 2017-08-30 前端日报

    摘要:前端日报精选精读个最佳特性翻译轻量级函数式编程第章组合函数之组件类型写的姿势中文周二放送面试题详解知乎专栏译原生值得学习吗答案是肯定的掘金个超赞的视觉效果众成翻译布局时常见总结腾讯前端团队社区归档打地鼠入门学习书籍 2017-08-30 前端日报 精选 精读《Web fonts: when you need them, when you don’t》10个最佳ES6特性翻译 -《Jav...

    weizx 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<