I have a page that has elements that become visible as you scroll down. I am trying to execute a test to make sure the elements are not there until the scroll is to the bottom of the elements, but I can't seem to figure out how to pass the size from one call (elementIdSize()) to the scroll offset of the next call (scroll()). Admittedly my brain does not yet get the concept of "promises" past simple call chaining.
I tried something like this:
this.browser
.setViewportSize({width: 1000, height: 600})
.element(selector)
.then(function(e) {
console.log('then element: ', e);
element = e;
})
.elementIdSize(element.id)
.then(function(size) {
console.log('Size: ', size);
})
.call(callback);
Which I was hoping would use the passed-in selector to get the element, set the element in the then(), then call elementIdSize() on the element's ID, but the var element is never set from the element() call, and the objects I am getting back don't seem to be what I am trying to get anyway. I feel this is some simple piece of knowledge I am missing here that will make all this "click".
I am using the APIs here for looking up the Webdriver calls, but the documentation doesn't give much details.
It's important to understand that all parameters will get resolved once you execute the chain. That means you can't change them anymore once you've executed the first command basically. In your example you set the value of the element variable in a promise callback. At the time you do that, elementIdSize already read the element variable (and probably threw an error).
The proper way to this is to execute commands that have arguments which get resolved at a later time in then or finish routines. You can also save commands in WebdriverIO by using action commands instead of raw protocol commands. So just use getSize instead of call element first and then call elementIdSize. That is the job of getSize ;-)
I am not sure what exactly you try to do but here is the code that should do the trick:
this.browser
.setViewportSize({width: 1000, height: 600})
.getElementSize(selector).then(function(size) {
console.log('size of element "' + selector + " is', size);
// now as we have the size execute the scroll in a then callback
return this.scroll(0, 600 + size.height);
})
// this get executed once we we did the scrolling since
// the getSize promise is only then fulfilled once the promise
// within the then function is resolved
.isVisible(otherElem).should.be.eventually.be(true, 'element was visible after scrolling')
.call(callback);
(As a side note: we already working on WebdriverIO v4 that will allow to execute commands synchronously, so no more promise headaches ;-))
Related
I am trying to execute a SequentialTransition, but between the animations, I need to execute some commands.
My problem is that it is always executing the last commands passed on the node. Is there any way to fix this?
Where is "is ignored" is the code that I need to be executed in the first animation, then where this "is executed" is the code that I need to be executed in the second animation.
Thanks
private void startAnimation(){
vb_adv.setPrefWidth(197);
ap_services.toBack();// Is ignored
vb_adv.toFront();// Is ignored
ScaleTransition expandAdvertising = new ScaleTransition(Duration.millis(2000), vb_adv);
expandAdvertising.setToX(2);
expandAdvertising.setCycleCount(2);
expandAdvertising.setAutoReverse(true);
ap_services.setPrefWidth(124);
ap_services.toFront();//is executed
ScaleTransition expandService = new ScaleTransition(Duration.millis(2000), ap_services);
expandService.setDelay(Duration.seconds(3));
expandService.setToX(3.7);
expandService.setCycleCount(2);
expandService.setAutoReverse(true);
SequentialTransition sequence = new SequentialTransition(expandAdvertising, expandService);
sequence.play();
}
In the code as you currently have it, you move ap_services to the back of the z-order, and vb_adv to the front:
ap_services.toBack();
vb_adv.toFront();
Then you create and set up you ScaleTransition. Note that doing this part takes essentially no time; all you are doing is configuring the animation which will run later.
The next thing you do is to move ap_services to the front:
ap_services.toFront();
Note that this will happen essentially immediately after the previous calls to toFront() and toBack(), and of course this negates the effect of those calls. So your initial calls are actually executed (not "ignored"), but you immediately do something which undoes their effect.
What you really want is to execute ap_services.toFront() after the ScaleTransition finishes. You can do this by putting that call in an onFinished() handler:
// ap_services.toFront();
expandAdvertising.setOnFinished(e -> ap_services.toFront());
The ractive.set method returns a promise. When performing a simple set operation (single value or map) and then immediately referencing the new value via ractive.get, is it recommended to use the promise? Or is that completely unnecessary?
I've been avoiding the promise and found that I don't need it, but maybe I've just been lucky so far. Here's an example of what I mean:
ractive.set("foo", "bar");
console.log(ractive.get("foo")); // always outputs the correct value "bar"
I'm worried that the set operation is asynchronous and this will become evident on slower machines or if I start using the more advanced features of Ractive.
According to the Ractive docs:
[ractive.set] Returns a Promise that will be called after the set
operation and any transitions are complete.
Based on that, I wonder if the promise is really meant for post-transition work.
Based on that, I wonder if the promise is really meant for
post-transition work.
Exactly. The value update (and the resulting DOM changes per the template) happen synchronously, the promise is meant for asynchronous response to end of transitions.
This is also why the set operation also has a hash map option for the input parameters so multiple sets will be batched in one go:
ractive.set({
foo: 'foo',
bar: 'bar'
}).then( () => {
// this happens asynchronously ***after*** code execution has
// continued below on next event cycle or after transitions complete
});
// data and DOM have been updated as the code continues synchronously here:
console.log( ractive.get() );
I want to wait for all data to be downloaded from the subscription and then create map markers for them all at once at the beginning. To do this, I have a session variable set to false. Then when onReady calls, I initialize all the markers. Then I set the session variable true indicating that the first delivery is in and initialized. In my observe callback, I check the session variable and so long as its false, I dont add any markers. Then, if its true, I will add markers -- assuming non of these markers are already initialized. Sometimes, however, I get a double-count and create twice as many markers.
I guess a good first question to ask is what the relationship is between onReady and observe added? Its not terribly clear in the docs. Is this even the correct way of doing things -- creating a session variable to suppress the observe added function until onReady is done? I dont think so. Also note that the double count doesnt happen every time so its a timing thing... kind of annoying.
Thanks
Yes this is the behavior with observe(). When you run observe initially it will have an initial query that will match everything and run into added.
It is also present when onReady hasn't yet fired but the collections are empty at that point so the initial ones aren't visible. This is mentioned in the docs
Before observe returns, added (or addedAt) will be called zero or more times to deliver the initial results of the query.
I'm not sure entirely how to avoid the initial items. I have done something like this in the past:
var QueryHandle = Collection.find().observe({
added: function() {
if(!QueryHandle) return false;
});
I know this works on the server but I'm not certain if it does on the client.
Another solution would be to run the handle before onReady is called and only stop returning if the subscription is complete: i.e
Meteor.subscribe("collection", function() {
subscribed = true;
});
var QueryHandle = Collection.find().observe({
added: function() {
if(!subscribed) return false;
}
);
Be careful not to run this in a Deps.autorun because then it would be run again if the .find() query params are reactive.
This might happen sometimes depending on how fast the server response. If you use Session it becomes a reactive hash so if it happens fast enough that subscribed returns true. Try using an ordinary variable instead.
If its not helpful there might be an alternative way to avoid the initial ones and a deeper level but it might take a dig into the livedata package.
I am working with a pretty complicated .aspx page that is full of controls (Telerik, Ajax, etc.) that all expand, collapse, show, hide, etc. when the page is loaded. Since this rendering happens on the client-side and can take different lengths of time based on the users machine specs, is there a way to detect when all (or some) rendering has taken place (jQuery?) so I can then act on specific elements, knowing they are fully rendered?
JavaScript is single threaded. The time passed to setTimeout is a minimum, but not a maximum, so if you pass something like 10(ms), you essentially are saying "execute this code after all the currently running code is finished."
So, if all the controls use $(document).ready() to do their thing, all you need is:
$(document).ready(function() {
setTimeout(function() {
doStuff();
},10);
});
doStuff will be called after all the functions passed to $(document).ready have run. However, this isn't foolproof. If the controls have their own way of detecting whether the document has loaded, or do their own setTimeout(), you're in trouble. The problem is that JavaScript does not guarantee the execution order of setTimeouts. Sometimes your code may run last, other times it may run before the setTimeouts used for the animation.
One last idea: if all the animation is done using jQuery, then the effects run in a single queue. In doStuff you could add an animation of some sort with a callback and be reasonably certain that the callback would run last.
Whenever I had to wait for multiple things to be ready before proceeding, I would create an array with true/false values. Every mandatory part of the page got an event which, when it is called, updates the specific entry in the array to true. Also, it called a general function which returned true if all values in an array was true, otherwise false.
If that function finally returned true, I would proceed with the execution. It is especially useful if you have to wait for an AJAX call to end but don't want to use async = true. It also is useful if you want to start loading multiple things at once instead of one after another, since they all report ready-state to the same array.
It does however use global variables so you might need to do some optimizations. You might not want to do this approach either if you have a grudge against global variables.
You should place your code inside the jQuery $(document).ready() function. This will ensure that all elements are loaded before the code runs.
http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
I think the doc you need is:
http://docs.jquery.com/Events/load
"I can then act on specific elements, knowing they are fully rendered?"
You can use the load method (linked above) to attach to any element. So if you had a div with an id of "lastElement", you could write
$('div#lastElement).load(runThisFunction);
OK I have an HTTPService that executes the dataLoaded(e:ResultEvent):void function whenever it gets a result from a send() call.
OK so If I call HTTPService.send() and then call HTTPService.send() again before the previous one receives a result, I end up repeatedly running dataLoaded() which is undesirable
What I want is if HTTPService.send() gets called before a previous call to it returns a result. I want to cancel the first call, and only process the result from the last call to HTTPService.send()
I hope this makes sense.
How can I do that??
Thanks!!
HTTPService has a cancel method. If you call it without its parameter, it should cancel the last invocation of the service. Give that a try and see if you're still getting undesired ResultEvents.
Use the existence of the ASyncToken to determine whether cancellation is appropriate.
private var _serviceCall:ASyncToken;
function callMyService(stuff:Object):void {
if (_serviceCall !== null) {
myService.cancel();
_serviceCall = null;
}
_serviceCall = myService.send(stuff)
}
Actually HTTPService can manage this for you. It has a concurrency property, which you should probably set to "last".
More info here: HTTPService#concurrency
In addition to Robert's answer: Flex: Cancel HTTPService.send()?
HTTPService#concurrency seems to be introduced until Flex 4, I don't find this in Flex 3.. In Flex 3., you have to cancel the previous call manually in contrast to concurrency="last" in Flex 4.
Note that this won't interrupt server process that previous call invokes, it means server may still come out a response however flex abandon that already.