I ran into an interesting issue when defining a global variable (as null in this case), and having a function change that global variable to a callback that was passed to that function---then trying to invoke the global variable (which is now the function) from a click event listener. However if that global variable wasn't defined (var globalCallback; as opposed to var globalCallback = null;) then everything is okay. I was under the assumption that the updated variable reference is always accessible by event listeners regardless of the variable's initial value---this doesn't seem to be the case.
See code below:
TypeError
document.addEventListener("DOMContentLoaded", function(){
//...
theSettingFunction(function(){
//...
});
var globalCallback = null; //creates TypeError when invoked after assigned to function
//var globalCallback = function(){}; //tried this too to test
function theSettingFunction(callback)
{
//...
globalCallback = callback;
//...
}
/* This event listener doesn't need removing it's a core UI element
This event gets triggered only after theSettingFunction() has been invoked first */
document.querySelector('#myButtonDiv').addEventListener('click', function(){
//...
globalCallback(); //invoking sees globalCallback as null still = TypeError
});
//...
});
Everything Okay
document.addEventListener("DOMContentLoaded", function(){
//...
theSettingFunction(function(){
//...
});
var globalCallback;
function theSettingFunction(callback)
{
//...
globalCallback = callback;
//...
}
/* This event listener doesn't need removing it's a core UI element
This event gets triggered only after theSettingFunction() has been invoked first */
document.querySelector('#myButtonDiv').addEventListener('click', function(){
//...
globalCallback(); //invoking... hey I see you---you're a function! Invoked.
});
//...
});
Is this because of the way the JS engine optimizes? Why else are event listeners not getting the updated references to global variables when they're defined?
No, this is not an engine optimization. It's an effect of JavaScript's funny hoisting rules, and the order in which the various things appear in your code.
The JavaScript language specifies that certain declarations are "hoisted" to the beginning of the program. I guess the idea was to make programming easier by not forcing programmers to pay attention to the order of things -- except, as it turns out, automatic reordering only gets you so far...
For example, you can call a function before defining it. Let's look at an example:
func(); // No error, because "func" is defined later.
variable = 1; // No error, because "variable" is declared later.
function func() {}
var variable;
console.log(variable); // Will print "1".
Under the hood, this is implemented by the engine reordering things as follows:
function func() {}
var variable;
func();
variable = 1;
console.log(variable); // Will print "1".
(Again, this is not an optimization, it's a requirement of the JavaScript language.)
An additional detail is that a combined declaration+initialization of a variable is split into two steps, and only the declaration is hoisted. So this:
console.log(variable); // Prints "undefined".
var variable = 1;
after internal re-ordering becomes this:
var variable;
console.log(variable); // Prints "undefined".
variable = 1;
Now, if we simplify your code a bit, we can see that this is exactly what happens. By inlining theSettingFunction, and assuming that the body of the onclick-handler is invoked directly, we get:
// This is what `theSettingFunction` does:
globalCallback = function() { /*...*/ }
var globalCallback = null;
// This is what the click-handler does:
globalCallback();
which the engine is required to reorder to:
var globalCallback; // hoisted declaration
globalCallback = function() { /*...*/ }
globalCallback = null;
globalCallback(); // TypeError, of course!
So you can easily fix the problem by moving the declaration+initialization of globalCallback before its first assignment, i.e. the call site of theSettingFunction:
document.addEventListener("DOMContentLoaded", function(){
var globalCallback = null; // Declare and initialize...
//...
theSettingFunction(function(){ // ...before assigning.
//...
});
function theSettingFunction(callback)
{
//...
globalCallback = callback;
//...
}
document.querySelector('#myButtonDiv').addEventListener('click', function(){
//...
globalCallback();
});
//...
});
Arguably, this will also make your code easier to read, because it's easier for humans to understand in which order things are happening when they don't have to take any invisible reordering into account. For this reason, personally, I would also move the definition of theSettingFunction before its first call.
Page object:
class Product {
get button() { return (".element"); }
}
module.exports = new Product();
Code
var pageObject = require('../pageObjects/product.page.js');
describe("Test", function () {
before( function () {
browser.url();
pageObject.button.click();
});
This returns an error when the test is ran of
pageObject.button.click is not a function
I have other page objects being utilized in the test outside of the before hook that are working fine. When I move the above object outside of the hook and into the main test, it still returns the same error. It appears to be setup the same as my other page objects, so I'm not sure what I am doing wrong.
Based on what i can see from you Product class, the getter button() is not returning the webElement. It is returning just a string .element.
Please try by updating the code as like below:
class Product {
get button() { return $(".element"); }
}
module.exports = new Product();
Thanks, Naveen
How can I call a function, or run some code for when any and every Template.rendered event is called in Meteor? (Not just a specific template)
(Is there a way I can do this without overloading meteor's base functions?)
Thanks!
One way is to call another method:
dothis = function() {
// Something
}
Template.hello.rendered = function() {
dothis();
}
Template.hello2.rendered = function() {
dothis();
}
If you have nothing else to do in your rendered you could:
Template.hello2.rendered = dothis;
Also in bulk (will override any other rendered if it is defined before, when it is run):
for(tmpl in Template) {
Template[tmpl].rendered = dothis;
};
(and also if you have defined stuff before you can make it run both callbacks:)
for(tmpl in Template) {
if(Template[tmpl].rendered) {
Template[tmpl].rendered = function() {
var originalfunction = Template[tmpl].rendered;
var result = originalfunction.apply(this);
dothis.apply(this);
return result;
}
}
else
{
Template[tmpl].rendered = dothis;
}
};
Hi i want to make nested dwr call.
In my java code i have two function
public String getNetworks() {
// return some networks.
}
public String getInternalNetwork(network) {
// return some networks.
}
I want to make a chained dwr call.
myDwr.getNetworks({
callback: function() {
var network
/// parse out answer.
myDwr.getInternalNetwork(network, {
callback:function() {
});
}
});
how do i do this so that dwr calls are made in order, and both functions are executed.
my answer was to store the network in a different call.
DWREngine.beginBatch();
myDwr.getNetworks({
callback: function(networks) {
network = getMainNetwork(networks);
}
});
myDwr.getInternalNetwork(network, {
callback: function() {
}
});
DWREngine.endBatch();
I'm rusty with delegates and closures in JavaScript, and think I came across a situation where I'd like to try to use one or both.
I have a web app that behaves a lot like a forms app, with fields hitting a server to change data on every onBlur or onChange (depending on the form element). I use ASP.NET 3.5's Web Services and jQuery to do most of the work.
What you need to know for the example:
isBlocking() is a simple mechanism to form some functions to be synchronous (like a mutex)
isDirty(el) checks to make sure the value of the element actually changed before wasting a call to the server
Agent() returns a singleton instance of the WebService proxy class
getApplicationState() passes a base-64 encoded string to the web service. This string represents the state of the application -- the value of the element and the state are passed to a service that does some calculations. The onSuccess function of the web service call returns the new state, which the client processes and updates the entire screen.
waitForCallback() sets a flag that isBlocking() checks for the mutex
Here's an example of one of about 50 very similar functions:
function Field1_Changed(el) {
if (isBlocking()) return false;
if (isDirty(el)) {
Agent().Field1_Changed($j(el).val(), getApplicationState());
waitForCallback();
}
}
The big problem is that the Agent().Field_X_Changed methods can accept a different number of parameters, but it's usually just the value and the state. So, writing these functions gets repetitive. I have done this so far to try out using delegates:
function Field_Changed(el, updateFunction, checkForDirty) {
if (isBlocking()) return false;
var isDirty = true; // assume true
if (checkForDirty === true) {
isDirty = IsDirty(el);
}
if (isDirty) {
updateFunction(el);
waitForCallback();
}
}
function Field1_Changed(el) {
Field_Changed(el, function(el) {
Agent().Field1_Changed($j(el).val(), getTransactionState());
}, true);
}
This is ok, but sometimes I could have many parameters:
...
Agent().Field2_Changed($j(el).val(), index, count, getApplicationState());
....
What I'd ultimately like to do is make one-linen calls, something like this (notice no getTransactionState() calls -- I would like that automated somehow):
// Typical case: 1 value parameter
function Field1_Changed(el) {
Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val()), true);
}
// Rare case: multiple value parameters
function Field2_Changed(el, index, count) {
Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val(), index, count), true);
}
function Field_Changed(el, theDelegate, checkIsDirty) {
???
}
function delegate(method) {
/* create the change delegate */
???
}
Ok, my first question is: Is this all worth it? Is this harder to read but easier to maintain or the other way around? This is a pretty good undertaking, so I may end up putting a bounty on this one, but I'd appreciate any help you could offer. Thanks!
UPDATE
So, I've accepted an answer based on the fact that it pointed me in the right direction. I thought I'd come back and post my solution so that others who may just be starting out with delegates have something to model from. I'm also posting it to see if anybody wants to try an optimize it or make suggestions. Here's the common Field_Changed() method I came up with, with checkForDirty and omitState being optional parameters:
function Field_Changed(el, args, delegate, checkForDirty, omitState) {
if (isBlocking()) return false;
if (!$j.isArray(args) || args.length == 0) {
alert('The "args" parameter in Field_Changed() must be an array.');
return false;
}
checkForDirty = checkForDirty || true; // assume true if not passed
var isDirty = true; // assume true for updates that don't require this check
if (checkForDirty === true) {
isDirty = fieldIsDirty(el);
}
if (isDirty) {
omitState = omitState || false; // assume false if not passed
if (!omitState) {
var state = getTransactionState();
args.push(state);
}
delegate.apply(this, args);
waitForCallback();
}
}
It handles everything I need it to (check for dirty, applying the application state when I need it to, and forcing synchronous webservice calls. I use it like this:
function TransactionAmount_Changed(el) {
Field_Changed(el, [cleanDigits($j(el).val())], Agent().TransactionAmount_Changed, true);
}
cleanDigits strips out junk characters the user may have tried to type in. So, thanks to everyone, and happy coding!
OK, few things:
Delegates are extremely simple in javascript since functions are first class members.
Function.apply lets you call a function with an array of arguments.
So you can write it this way
function Field_Changed(delegate, args)
{
if (isBlocking()) return false;
if (isDirty(args[0])) { //args[0] is el
delegate.apply(this, args);
waitForCallback();
}
}
And call it as:
Field_Changed(Agent().Field2_Changed, [el, getApplicationState(), whatever...]);
I have been using the following utility function that I wrote a long time ago:
/**
* #classDescription This class contains different utility functions
*/
function Utils()
{}
/**
* This method returns a delegate function closure that will call
* targetMethod on targetObject with specified arguments and with
* arguments specified by the caller of this delegate
*
* #param {Object} targetObj - the object to call the method on
* #param {Object} targetMethod - the method to call on the object
* #param {Object} [arg1] - optional argument 1
* #param {Object} [arg2] - optional argument 2
* #param {Object} [arg3] - optional argument 3
*/
Utils.createDelegate = function( targetObj, targetMethod, arg1, arg2, arg3 )
{
// Create an array containing the arguments
var initArgs = new Array();
// Skip the first two arguments as they are the target object and method
for( var i = 2; i < arguments.length; ++i )
{
initArgs.push( arguments[i] );
}
// Return the closure
return function()
{
// Add the initial arguments of the delegate
var args = initArgs.slice(0);
// Add the actual arguments specified by the call to this list
for( var i = 0; i < arguments.length; ++i )
{
args.push( arguments[i] );
}
return targetMethod.apply( targetObj, args );
};
}
So, in your example, I would replace
function Field1_Changed(el) {
Field_Changed(el, delegate(Agent().Field1_Changed, $j(el).val()), true);
}
With something along the lines
function Field1_Changed(el) {
Field_Changed(el, Utils.createDelegate(Agent(), Agent().Field1_Changed, $j(el).val()), true);
}
Then, inside of Agent().FieldX_Changed I would manually call getApplicationState() (and encapsulate that logic into a generic method to process field changes that all of the Agent().FieldX_Changed methods would internally call).
Closures and delegates in JavaScript:
http://www.terrainformatica.com/2006/08/delegates-in-javascript/
http://www.terrainformatica.com/2006/08/delegates-in-javascript-now-with-parameters/