UPDATED: I created Google Slides using chart to help you understand how ngrx works in an Angular2-Meteor app, check Desugar Meteor, Angular 2, RxJS 5, and ngrx . So check this slides to have a better understanding.
This “gist” will give you a guide using RxJS 5 (Observable), ngrx/store (Redux Store) and ngrx/effects (Redux Saga) in an Angular2-Meteor project.
The tutorial of Reactive Programming and Redux in Angular2-Meteor with explanation needs a while… Don’t wait, start to learn them and use today!
The most important part of codes that needs to connect Angular 2 and Meteor to use these, I already posted below. This helps you start. Have fun!
If you follow this “gist”, you can have some dev tools to help you development, check Tools for Reactive Programming and ngrx (Redux) in Angular2-Meteor .
1. Meteor Subscribe
1) Service
// chat.service.ts
loadMessages(chatId: string): Observable<Message[]> {
return Observable.create(observer => {
this.subscribe('messages.private', chatId, () => {
this.autorun(() => {
const messages = Messages.find({ chatId }).fetch(); // If you want to return Mongo.Cursor, it is also good
observer.next(messages);
}, true);
});
});
}
2) Actions
export class Actions {
static CHAT_SUBSCRIBE_MESSAGES = '[Chat] Subscribe Messages';
static CHAT_LOAD_MESSAGES = '[Chat] Load Messages';
}
3) Dispatch
this.store.dispatch({ type: Actions.CHAT_SUBSCRIBE_MESSAGES, payload: chatId });
4) Effects
// chat.effects.ts
@Effect() loadMessages$ = this.updates$
.whenAction(Actions.CHAT_SUBSCRIBE_MESSAGES)
.map<string>(toPayload)
.switchMap(chatId => this.chatService.loadMessages(chatId))
.map(messages => ({ type: Actions.CHAT_LOAD_MESSAGES, payload: messages }));
5) Reducer
// chat.reducer.ts
export const chatReducer: ActionReducer<ChatState> = (state = initialState, action: Action) => {
switch (action.type) {
case Actions.CHAT_LOAD_MESSAGES: {
return Object.assign({}, state, { messages: action.payload });
}
// ... other chat reducers
default: {
return state;
}
}
};
2. Meteor Call
1) Service
// settings.service.ts
updateEmail(email: string): Observable<string> {
return Observable.create(observer => {
this.call('users.updateEmail', email, error => {
if (error) {
observer.error(error);
return;
}
observer.next(email);
});
});
}
2) Actions
export class Actions {
static SETTINGS_UPDATE_EMAIL = '[Settings] Update Email';
static SETTINGS_UPDATE_EMAIL_SUCCESS = '[Settings] Update Email Success';
static SETTINGS_UPDATE_EMAIL_FAIL = '[Settings] Update Email Fail';
}
3) Dispatch
this.store.dispatch({ type: Actions.SETTINGS_UPDATE_EMAIL, payload: this.email.value });
4) Effects
// settings.effects.ts
@Effect() udpateEmail$ = this.updates$
.whenAction(Actions.SETTINGS_UPDATE_EMAIL)
.map<string>(toPayload)
.switchMap(email => this.settingsService.updateEmail(email)
.map(() => ({ type: Actions.SETTINGS_UPDATE_EMAIL_SUCCESS }))
.catch(error => Observable.of({ type: Actions.SETTINGS_UPDATE_EMAIL_FAIL, payload: error }))
);
5) Reducer
// settings.reducer.ts
export const settingsReducer: ActionReducer<SettingsState> = (state: SettingsState = {}, action: Action) => {
switch (action.type) {
case Actions.SETTINGS_UPDATE_EMAIL_SUCCESS: {
return state;
}
case Actions.SETTINGS_UPDATE_EMAIL_FAIL: {
return Object.assign({}, state, { error: action.payload });
}
default: {
return state;
}
}
};