Bun*_*ner 11 store rxjs hybrid-mobile-app ngrx angular
我们有一个有角度的项目在工作(待开发,还没有开始).它非常复杂,数据流复杂.此外,我们的应用程序中有两种用户.经理和用户.这些用户将看到类似的视图,但每个用户都有一些不同的自定义视图.经理可以按照您的想象获得更多功能.为了以可扩展的方式管理这个相当大而复杂的应用程序,我们遵循NX模式.即单个回购中的多个应用程序.最后,在单个回购中,我有以下应用程序.
大部分开发将在commonapp中完成,不同的视图和定制将分别在两者mngr-app和user-app.
我们也考虑ngrx在我们的国家管理申请中使用.我已经看过多个如何做到这一点的示例和教程.到目前为止一切都还可以.这部分仅供参考.
我们的问题在此之后开始.我们的业务团队还希望我们使用包含Web应用程序的Web视图开发iOS和Android应用程序(我忘了提到它是一个响应式Web应用程序).因此,我们所做的一切都将通过网络视图发送给移动用户.但是,业务团队也希望我们为移动应用程序开发一些自定义本机视图.
我们来看看下面的例子:(这是来自ngrx的例子)
当用户单击Add Book to Collection按钮时,[Collection] Add Book会将操作类型分派给商店,效果将按如下方式处理:
@Effect()
addBookToCollection$: Observable<Action> = this.actions$
.ofType(collection.ADD_BOOK)
.map((action: collection.AddBookAction) => action.payload)
.switchMap(book =>
this.db.insert('books', [ book ])
.map(() => new collection.AddBookSuccessAction(book))
.catch(() => of(new collection.AddBookFailAction(book)))
);
Run Code Online (Sandbox Code Playgroud)
这是Web应用程序的正常流程.
我们的业务团队希望我们为移动应用程序构建某种自定义逻辑,以便当用户在移动应用程序(iOS或Android)中导航到此页面时,不会将书籍添加到集合中,而是打开本机页面用户将在该本机页面上执行操作.我的意思是他们希望Web应用程序在移动应用程序中出现时表现不同.我可以if(window.nativeFlag === true)在Web应用程序中实现这一点.但是,这只是我们想要避免的肮脏黑客.因为,我们正在使用ngrx,rxjs我们觉得这可以用Observables rxjs和Actions 来完成ngrx.
到目前为止我们尝试的是暴露store和actions反对DOM,以便我们可以在移动应用程序中访问它.
constructor(private store: Store<fromRoot.State>, private actions$: Actions) {
window['store'] = this.store;
window['actions'] = this.actions$;
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,我们可以[Collection] Add Book按如下方式订阅事件
actions().ofType('[Collection] Add Book').subscribe(data => {
console.log(data)
})
Run Code Online (Sandbox Code Playgroud)
并在将书籍添加到集合时收到通知.但是,Web应用程序仍然执行正常操作,我们无法覆盖此行为.
我的问题是如何订阅ngrx移动应用程序中的某些操作并取消Web应用程序行为?
编辑
我自己想出了一个解决方案,但是任何其他解决方案都会受到赞赏,如果你能想出更好的解决方案,我会给予赏金.
到目前为止我能做什么
bridge我在网络应用程序中编写了以下内容。
window['bridge'] = {
dispatch: (event: string, payload = '') => {
// I had to use zone.run,
// otherwise angular won't update the UI on
// an event triggered from mobile.
this.zone.run(() => {
this.store.dispatch({type: event, payload: payload});
});
},
ofEvent: (event: string) => {
// I register this event on some global variable
// so that I know which events mobile application listens to.
window['nativeActions'].push(event);
return this.actions.ofType(event);
}
};
Run Code Online (Sandbox Code Playgroud)
从 Android 应用程序中,我可以收听[Collection] Add Book以下内容:
webView.loadUrl("
javascript:bridge.ofEvent('[Collection] Add Book')
.subscribe(function(book) {
android.addBook(JSON.stringify(book.payload));
});
");
Run Code Online (Sandbox Code Playgroud)
这将触发我的addBook方法,我将把这本书保存在某个类上以供以后使用。
@JavascriptInterface
public void addBook(String book) {
Log.i("addBook", book);
this.book = book;
}
Run Code Online (Sandbox Code Playgroud)
我还向 Android 应用程序添加了一个按钮来删除这本书。
webView.evaluateJavascript("
bridge.dispatch('[Collection] Remove Book', "+this.book+")
", null);
Run Code Online (Sandbox Code Playgroud)
通过这段代码,我能够监听 Web 应用程序触发的事件并将结果保存在某处。我还能够从 Android 应用程序触发一些事件来删除 Web 应用程序中的书籍。
另外,前面我提到我在全局变量上注册了这个事件。
我更改@Effect为以下
@Effect()
addBookToCollection$: Observable<Action> = this.actions$.pipe(
ofType<AddBook>(CollectionActionTypes.AddBook),
map(action => action.payload),
switchMap(book => {
if (window['nativeActions'].indexOf(CollectionActionTypes.AddBook) > -1) {
return of();
} else {
return this.db
.insert('books', [book])
.pipe(
map(() => new AddBookSuccess(book)),
catchError(() => of(new AddBookFail(book)))
);
}
})
);
Run Code Online (Sandbox Code Playgroud)
我if (window['nativeActions']..)可以检查移动应用程序是否注册了此特定事件。但是,我不会对@Effect我拥有的所有设备执行此控制。此时,我正在考虑编写一些自定义RxJs运算符来从我的effects. 我觉得我已经接近答案了,但我会感谢任何意见。
自定义 RxJs 运算符
我编写了以下自定义运算符并解决了我的问题。
export function nativeSwitch(callback) {
return function nativeSwitchOperation(source) {
return Observable.create((subscriber: Observer<any>) => {
let subscription = source.subscribe(value => {
try {
if (window['nativeActions'].indexOf(value.type) > -1) {
subscriber.complete();
} else {
subscriber.next(callback(value));
}
} catch (err) {
subscriber.error(err);
}
},
err => subscriber.error(err),
() => subscriber.complete());
return subscription;
});
};
}
Run Code Online (Sandbox Code Playgroud)
将我的效果更改为以下:
@Effect()
addBookToCollection$: Observable<Action> = this.actions$.pipe(
ofType<AddBook>(CollectionActionTypes.AddBook),
nativeSwitch(action => action.payload),
switchMap((book: Book) =>
this.db
.insert('books', [book])
.pipe(
map(() => new AddBookSuccess(book)),
catchError(() => of(new AddBookFail(book)))
)
)
);
Run Code Online (Sandbox Code Playgroud)
这正是我想要的。因为,subscriber.complete()如果给定事件是由移动应用程序注册的,我会调用,其中的方法switchMap永远不会被调用。
希望这会对某人有所帮助。
| 归档时间: |
|
| 查看次数: |
546 次 |
| 最近记录: |