Postpone observable when other one fired in RxJs - rxjs5

I have a table on a page and two subscriptions:
First one reloads table data. It has a delay because it calls an api.
Second highlights data. Does not affect table data.
When subscriptions fire one by one everything is OK, but when they fire at the same time data is highlighted and soon after is reloaded so highlighting is gone.
You can see it here.
Is there are way to postpone highlighting if reloading is in action?
Probably I can accomplish this by introducing loading variable but I am looking for reactiveX solution.
Thanks in advance.

Keep in mind that in rxjs everything is a stream, which you can use to your advantage, I've modified you fiddle a bit so that everything is a stream now:
var pageClicks = Rx.Observable.fromEvent(document.getElementById('page'), 'click');
var highlightClicks = Rx.Observable.fromEvent(document.getElementById('highlight'), 'click');
var bothClicks = Rx.Observable.fromEvent(document.getElementById('both'), 'click');
var page = 0;
var nextPage$ = Rx.Observable.of(page)
.map(function() {
page = (page + 1) % 2;
return page
})
.switchMap(loadData)
.do(renderData);
var doBoth$ = nextPage$
.do(highlight);
// initial rendering of data
doBoth$.subscribe();
pageClicks
.switchMapTo(nextPage$)
.subscribe();
highlightClicks
.do(highlight)
.subscribe();
bothClicks
.switchMapTo(doBoth$)
.subscribe();
Here is the link to the updated fiddle: https://fiddle.jshell.net/r2L7k0mc/3/
Based on your comments I have updated your fiddle with the following code:
var page$ = events.page$.share();
var loadData$ = page$
.startWith(0)
.switchMap(page => loadData(page).takeUntil(page$))
.do(renderData);
loadData$.subscribe();
var loading$ = Rx.Observable.merge(
page$.mapTo(true),
loadData$.mapTo(false)
)
.startWith(false)
.publishReplay(1);
loading$.connect();
events.highlight$
.switchMap(function() {
return loading$
.filter(function(isLoading) { return !isLoading; })
.take(1);
})
.do(highlight)
.subscribe();
See: https://fiddle.jshell.net/mc8h52r7/5/
However I would strongly suggest to rethink the architecture, since this is a very ugly set of streams, that could surely be optimized with a different architecture.

Related

NativeScript: best persistent cache / storage with view data-binding

I'm developing an app that receives data from API and should store it in some kind of cache to bind it to UI views. This data is also shared among several views and any change to it should be reflected in views. What is the best and fastest option for NativeScript so far? Would be awesome to have something similar to SenchaTouch stores / models with proxy. Thanks.
Just create a singleton and request/import that, just as you would in any other Javascript app. As long as you keep your data in an Observable and any changes to it will instantly be reflected in the views.
E.g.
file: myData.js
var observableArray = require("data/observable-array");
var observable = require("data/observable");
var DATA = new observable.Observable({
something: 'a value here',
somethingElse: 1
somethingMany: new observableArray.ObservableArray(['a', 'b', 'c'])
});
exports.getData = function() { return DATA; };
exports.fetchFromAPI = function() { /* something that fetches and updates DATA */ }
In any file where you want to read that data:
var data = require("./myData.js");
console.log(data.getData());
Read more about Observables in NativeScript

protractor click action relies on ptor.sleep(). How can I resolve correctly?

I'm a newbie trying to not rely so much or at all on using ptor.sleep() calls, especially after the click below. The line below never gets the value (they all return Nan)unless I include the ptor.sleep(1000); call after the click() below.
I've made various attempts to make the array elem to resolve before the results of the list after clicking, wrapping the click in the function, etc, but nothing I've tried works without the sleep calls. Already read up on protractor control flow.
devCountString = parseInt(arr[i]);
Thanks for any insights, maybe something obvious I've missed so that I can remove the ptor.sleep() calls.
my spec:
describe('\n == patch List suite results == \n', function() {
// login already was done in config files, onPrepare function.
var ptor, noFilterCount;
// needed here if we turn ptor.ignoreSynchronization = false;
beforeEach(function() {
ptor = protractor.getInstance();
ptor.ignoreSynchronization = true;
browser.get('https://my.abc.com:3000/fixes');
ptor.sleep(1200);
}); //end beforeEach()
it('11 - verify filter fewer', function() {
var sevStringElm, sevString;
var applicableCount;
ptor.ignoreSynchronization = false;
ptor.sleep(500);
sevStringElm = element(by.css("input.form-control.bf-spinner"));
sevStringElm.clear();
ptor.sleep(500);
sevStringElm.sendKeys( '8' );
ptor.sleep(500);
// click on the "fewer" spinner, wrap the click to wrap the .
var fewerPromise = element(by.css("span.bf-spinner-toggle:nth-child(2)")).click();
ptor.sleep(1000);
// now get the list of clickable elements in each device card. by title
var applicableDevicesElm = element.all(by.css("[title$='Applicable\ Devices']"));
applicableDevicesElm.getText().then(function(arr) {
console.log("arr.length= "+arr.length);
for (var i = 0; i < arr.length; i++) {
devCountString = parseInt(arr[i]);
expect(devCountString).toBeLessThan( 9 );
};
});
});
Everytime an action goes to the webdriver, Protractor will put that into the flow queue as shown in the documentation. As a result, when you get to inspect your elements after the click, the queue should have resolved the dependencies and have your state ready for the finder. In any case, even if you don't want to have the implicit wrapping that Protractor does on its actions (which are always asyc), you can put a .then(function(){}) after the click and put the post click logic in that anonymous calback function.
On a side note, you should have to use ptor anymore. Use browser instead that mixes in the protractor instance capabilities. Example: browser.sleep(1000)

Ember.js template binding performance

We have a page containing a table with 26 rows. Each row will contain either an <input> or <select> element, depending on the data we're binding to. When binding to elements that contain between 5-30 options, it takes a page about 5 seconds to render. If I remove the binding, the page renders in under a second.
Is there a known performance issue when binding to Ember.Select views? Or, could I be doing it incorrectly? I'm using Firefox 22. IE9 is about twice as slow. The CPU is not pegged during this time. I'm using ember 1.0rc6.
Template snippet:
{{#if pa.isPickList}}
{{view Ember.Select viewName="select" contentBinding="pa.options" selectionBinding="pa.selected"}}
{{else}}
{{input valueBinding="pa.selected"}}
{{/if}}
I worry that the async nature of how I'm fetching the model could be causing inefficiencies. Perhaps the binding and async events are interacting inefficiently.
Salesforce.com is the backend. From what little I know about promises, I'm wondering if I need to fetch the server data in a promise. I'm not sure how to do this.
Here's how I'm currently fetching the data in my Route:
App.IndexRoute = Ember.Route.extend({
model: function(params){
var otherController = this.controllerFor('selectedProducts');
var ar = Ember.A(); //create an array
var arg = '0067000000PNWrV';
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.ProductPricingLookupController.loadOpportunityProducts}',
arg,
function myHandler(result, event) {
console.info('got results!!! ' + result.length);
for(var i = 0; i < result.length; i++)
{
var p = result[i];
var sfProd = App.ProductResult.create({content: p});
ar.pushObject(sfProd);
}
},
{escape: false} //some of the names have ampersands!!
);
return ar;
}
}
Thanks in advance for helping a newbie learn the ways of javascript and Ember.
Update
Here is working example of this issue. I have 5 picklists each with 60 options. This take 2-3 seconds to render on my machine. I realize these are decently large numbers but hopefully not unreasonable. Increase the number of picklist elements or options and you can easily hit 5 seconds.
Also, moving my server-model-fetching to a promise did not affect performance.
Andrew
It's a little hard to guess at performance problems like this without looking at it in a profiler. You can try creating a profile in Chrome dev tools to see what method is taking the most amount of time. Or create a jsbin which has the same issue.
One potential issue is that the array that you bind to is being built at the same time when the bindings are connected. This shouldn't be an issue with rc.6. What version of Ember are you on?
Regards to promises, your model hook should return a promise that wraps your async call, like so.
model: function(params) {
var promise = Ember.Deferred.create();
var myHandler = function(result, event) {
var model = Ember.A();
// populate the model
promise.resolve(model)
}
var arg = '0067000000PNWrV';
Visualforce.remoting.Manager.invokeAction(..., myHandler);
return promise;
}
If the bindings were firing too early/often, loading the model in a promise like this would help.
Finally try setting Ember.STRUCTURED_PROFILE to true. This will show you exactly how long the templates are taking to render.
Edit: After the the jsfiddle
I dug into this a little more. This is a known issue with Ember.Select. The default implementation creates SelectOption views for each option inside the select to allow databinding of the option items itself. Creating those many views is what takes the time.
However the typical usage will rarely need binding to the option items only to the whole list itself. And this appears to be the common way to bridge the performance gap.
I found a gist that uses option tags instead of SelectOption views.
Here's your updated jsfiddle. I upped the lists to 10 with 100 items each. The list renders in about 150ms for me now.

jQuery stops working after ajax request that adds fields to a form in Drupal 7

I don't think this is a Drupal-specific question, but more of a general jquery/ajax issue:
Basically, I'm trying to use javascript to add up form fields and display the result in a "subtotal" field within the same form. Everything is working fine until i click the option to add another field (via ajax), which then changes my "subtotal" field to zero, and won't work again until I remove the field.
Here is the function that adds up the fields:
function calculateInvoiceFields(){
var total = 0;
var rate = 0;
var quantity = 0;
var i = 0;
var $ = jQuery;
$("#field-aminvoice-data-values tr").each(function(){
// quantity field number
quantity = $("#edit-field-aminvoice-data-und-"+i+"-field-aminvoice-quantity-und-0-value").val();
// rate field as number
rate = $("#edit-field-aminvoice-data-und-"+i+"-field-aminvoice-rate-und-0-value").val();
if(!isNaN(quantity) && !isNaN(rate)){
total += quantity*rate;
}
i++;
});
return total;
}
And here are the functions that get fired for .ready and .live:
jQuery(document).ready(function(){
var $ = jQuery;
$(".field-type-commerce-price input").val(calculateInvoiceFields());
});
jQuery(function(){
var $ = jQuery;
$(".form-text").live('change', function(){
$(".field-type-commerce-price input").val(calculateInvoiceFields());
});
});
Any ideas would be a big help. Thanks in advance!
I recommend using 'on' for any binding statement. and 'off' for unbinding.
The reason it doesn't work after an AJAX call, is because you need to be watching for that element to be added to the DOM, and an event attached to it after it gets loaded. If you load a new element in, and there is nothing watching for it, it won't add the event watch to that new DOM element.
As below:
function calculateInvoiceFields(){
/*..*/
return total;
}
$(document).ready(function(){
$(".field-type-commerce-price input").val(calculateInvoiceFields());
$("body").on('change', ".form-text", function(){
$(".field-type-commerce-price input").val(calculateInvoiceFields());
});
});
usually it stops working when an error has been thrown. did you check out your javascript console (firefox firebug, or built in for chrome) for any indication of an error?

Titanium Mobile: reference UI elements with an ID?

How do you keep track of your UI elements in Titanium? Say you have a window with a TableView that has some Switches (on/off) in it and you'd like to reference the changed switch onchange with a generic event listener. There's the property event.source, but you still don't really know what field of a form was just toggled, you just have a reference to the element. Is there a way to give the element an ID, as you would with a radiobutton in JavaScript?
Up to now, registered each form UI element in a dictionary, and saved all the values at once, looping through the dictionary and getting each object value. But now I'd like to do this onchange, and I can't find any other way to do it than create a specific callback function for each element (which I'd really rather not).
just assign and id to the element... all of these other solution CAN work, but they seem to be over kill for what you are asking for.
// create switch with id
var switcher0 = Ti.Ui.createSwitch({id:"switch1"});
then inside your event listener
myform.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "switch1" ) {
// do some magic!!
}
});
A simple solution is to use a framework that helps you keep track of all your elements, which speeds up development quite a bit, as the project and app grows. I've built a framework of my own called Adamantium.js, which lets you use a syntax like jQuery to deal with your elements, based on ID and type selectors. In a coming release, it will also support for something like classes, that can be arbitrarily added or removed from an element, tracking of master/slave relationships and basic filter methods, to help you narrow your query. Most methods are chainable, so building apps with rich interaction is quick and simple.
A quick demo:
// Type selector, selects all switches
$(':Switch')
// Bind a callback to the change event on all switches
// This callback is also inherited by all new switch elements
$(':Switch').bind('change', function (e) {
alert(e.type + ' fired on ' + e.source.id + ', value = ' + e.value);
});
// Select by ID and trigger an event
$('#MyCustomSwitch').trigger('change', {
foo: 'bar'
});
Then there's a lot of other cool methods in the framework, that are all designed to speed up development and modeled after the familiar ways of jQuery, more about that in the original blog post.
I completely understand not wanting to write a listener to each one because that is very time consuming. I had the same problem that you did and solved it like so.
var switches = [];
function createSwitch(i) {
switches[i] = Ti.UI.createSwitch();
switches[i].addEventListener('change', function(e) {
Ti.API.info('switch '+i+' = '+e.value);
});
return switches[i];
}
for(i=0;i<rows.length;i++) {
row = Ti.UI.createTableViewRow();
row.add(createSwitch(i));
}
However keep in mind that this solution may not fit your needs as it did mine. For me it was good because each time I created a switch it added a listener to it dynamically then I could simply get the e.source.parent of the switch to interact with whatever I needed.
module Id just for the hold it's ID. When we have use id the call any another space just use . and use easily.
Try This
var but1 = Ti.Ui.createButton({title : 'Button', id:"1"});
window.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "1" ) {
// do some magic!!
}
});
window.add(but1);
I, think this is supported for you.
how do you create your tableview and your switcher? usually i would define a eventListener function while creating the switcher.
// first switch
var switcher0 = Ti.Ui.createSwitch();
switch0.addEventListener('change',function(e){});
myTableViewRow.add(switch0);
myTableView.add(myTableViewRow);
// second switch
var switch1 = ..
so no generic event listener is needed.

Resources