i have table , button , want emit event itemsselected selected items of table when button clicked.
the button should not know table , should remain stream of clicks. solution discarded:
final etable table = ... publishsubject<itemselected> selected = publishsubject.create(); button.addselectionlistener(new selectionlistener(){ @override public void widgetselected(selectionevent e) { (tableitem item : table.getselection()) { selected.onnext(new itemselected(item)); } } });
i prefer way compose click stream of button item selection stream of table in order keep loose coupling between 2 elements.
because table allows multiple selection must first scan items selected in order emit event items. like:
public static class itemsselected<t> { final list<t> items = new arraylist<t>(); } public abstract static class itemselection<t> { public abstract void apply(itemsselected<t> selection); } public static class itemunselected<t> extends itemselection<t> { final t item; public itemunselected(t item) { this.item = item; } public void apply(itemsselected<t> selection) { selection.items.remove(item); } } public static class itemselected<t> extends itemselection<t> { final t item; public itemselected(t item) { this.item = item; } public void apply(itemsselected<t> selection) { selection.items.add(item); } } public static class observabletable<t> extends table { private publishsubject<itemselection<t>> clicks = publishsubject.create(); public observable<itemsselected<t>> selection = clicks.scan(new itemsselected<t>(), new func2<itemsselected<t>, itemselection<t>, itemsselected<t>>() { @override public itemsselected<t> call(itemsselected<t> t1, itemselection<t> t2) { // breaking events immutability t2.apply(t1); return t1; } }); public observabletable(composite parent, int style) { super(parent, style); this.addselectionlistener(new selectionlistener() { @suppresswarnings("unchecked") @override public void widgetselected(selectionevent e) { if (((tableitem) e.item).getchecked()) clicks.onnext(new itemselected<t>((t) e.item.getdata())); else clicks.onnext(new itemunselected<t>((t) e.item.getdata())); } @override public void widgetdefaultselected(selectionevent e) { } }); } }
then, must combine table.selection stream button.clicks stream in selectionforaction stream. idea when buttonclick emitted, selectionforaction emitted if , if itemselected emitted.
-------s1--u1-----s2---s3--------- table.clicks (scan) -------(1)--()---(2)---(2,3)------ table.selection ----o----------o-------------o---- button.clicks (?) -----------------------------(2,3) selectionforaction
so, wich operation should use?
- zip: doesn't work because if click button , later select item, should not nothing, zip emit event.
- join: end "solution" using join doesn't seem one. somethinkg like:
table.selection.join(button.clicks, new func1<itemsselected,observable<long>>() { @override public observable<long> call(itemsselected t) { // doesn't seem idea return observable.timer(1, timeunit.days); } }, new func1<clickevent, observable<long>>() { @override public observable<long> call(clickevent t) { // makes clickevent dropped if there no previous itemsselected event emitted return observable.timer(1, timeunit.milliseconds); } }, new func2<itemsselected, clickevent, selectionforaction>() { @override public selectionforactioncall(itemsselected t1, clickevent t2) { return new selectionforaction(t1.items); } });
any idea?
i've found operator needed achieve join behaviour large time unit (days in example) , small 1 (milliseconds).
with variant of sample takes observable sampler emit event after event of b emitted.
in example click acts sampler , stream selection emits events i'm interested in. (this requires ignore last event being emitted when stream completes).
another possible solution use buffer(boundary):
the clicks stream act boundary , avoid scan operator because list of items selected created buffer operator. solution not considering unselection.
so, sample i've achieved original goal, however, i'm not happy way handle items unselection , final list of items selected. in case need maintain state of items selected in order perform operation on of them when clickevent occurs.
i subscribe items selection/unselection , maintain list of items selected i'll have lost possibility of compose clicks observable selection observable.
with scan maintain state , keep composability of observables, representing list of current selection event seems little forced, in fact represents new issue: if select x items , click button, event selection being emitted expected, if neither items unselected nor new 1 selected , click again button, nothing happens. so, seems selection doesn't fit event.
Comments
Post a Comment