Getting Value from Nested Anonymous Function - javascript

I've got a list of items that have different data values that I'm trying to return on a click event. I can't seem to pass the value from the click event to the parent function. I may just be doing this all wrong. I just need the data value from each click event to replace the value of my systemName variable. Can someone help me out here?
function getSystemName(){
var systemName = '';
$('.pulldown li').bind('click', function(){
var systemName = '';
var systemName = $(this).find('a').data('value');
console.log(systemName);
});
return systemName;
}
// Edit: I should probably explain that I'm trying to get that value from the click event to update content on the page via jquery .load so perhaps like mentioned below....I'm not doing this properly because I can log the systemName properly on click but it doesn't seem to update the page content. Here is the entire code block.
$.ajaxSetup ({
cache: false
});
var ajax_load = "<img src='.../images/130.gif' alt='loading...' align='middle' />";
var loadUrl = ".../content.php";
var getSystemName = (function(){
var systemName = '';
$('.pulldown li').bind('click', function(){
systemName = $(this).find('a').data('value');
console.log(systemName);
});
return function() { return systemName };
})();
$("#results")
.html(ajax_load)
.load(loadUrl, "ki_systems=" +getSystemName());

In the code in the question, each time you call getSystemName() it will bind a click handler again (resulting in multiple click handlers) and then just return the local systemName variable that will always be blank.
If you are saying that each time you call getSystemName() you want it to return the system name associated with whichever li element was most recently clicked then you can declare the systemName variable as a global variable and bind the event handler (once) outside getSystemName():
var systemName = '';
$('.pulldown li').bind('click', function(){
systemName = $(this).find('a').data('value');
console.log(systemName);
});
function getSystemName() {
return systemName;
}
But that makes the function rather redundant: you could just refence the global variable directly.
On the other hand you could declare just the function and use a closure to avoid the need for global variables, something like this:
var getSystemName = (function(){
var systemName = '';
$('.pulldown li').bind('click', function(){
systemName = $(this).find('a').data('value');
console.log(systemName);
});
return function() { return systemName };
})();
// if no items have been clicked yet it will return an empty string by default
console.log( getSystemName() ); // ""
// click on an item with name "red"
console.log( getSystemName() ); // "red"
// click on an item with name "green"
console.log( getSystemName() ); // "green"
That last block could be a little confusing to the uninitiated. It is setting getSystemName to whatever is returned from an anonymous function expression that is executed immediately (note the extra empty parentheses at the end). And what is returned is a simple function that when called itself will return systemName, which is declared in the outer scope. The click handler also updates this same systemName. So when you actually call getSystemName() you are calling the little one-liner function from the return statement.

I think the problem here is that you're missing synchronous and asynchronous programming - you probably want a callback on the getSystemName() function. I expect there's something more architecturally wrong with the approach you're taking.
However, this is what it'd look like if I wrote that using your style:
function getSystemName(callback) {
$('.pulldown li').bind('click', function(){
console.log(systemName);
callback( $(this).find('a').data('value') );
});
}
So instead of this sort of code:
console.log("System Name: ", getSystemName())
You would have:
getSystemName( function (name) { console.log("System Name: ", name); } );

Remove the var from the second and third definitions. If you use var before the variable name a new local instance will be created.
systemName = '';
systemName = $(this).find('a').data('value');
console.log(systemName);

Consider this, on the second line you're only binding a callback function to the click event, not executing the code inside that function.

You can't.
Look at the code.
Set systemName to an empty string
When a list item is clicked set systemName to something else
Return systemName
You can't make 3 wait for 2. You need to do something with the data in the click handler and not try to return it.

Well, i suppose you are trying to set a value to see which node has been click, thus you need to change the scope of your systemName variable. Move it out so it will be global, like so:
var systemName = '';
$('.pulldown li').bind('click', function(){
systemName = $(this).find('a').data('value');
console.log(systemName);
});

Related

How do you use Javascript constructor methods in a jQuery statement?

I can't figure out how to use a Javascript constructor method in a jQuery .click method. I'm trying to get a button's function to change dynamically based on a constructor. Here's the set up:
<button onclick="">
</button>
needs to call a method that changes depending on another button. The following is my broken code:
function GloveMode (name , array) {
this.colorArray = array;
this.displaySettings = function(){
//Title
$("#displayTitle").text(this.name);
//Display Color Set
$("#displayColors").empty();
//Totally Broken
$("#upArrow").click( function(){
addColor();
});
};
this.addColor = function(){
console.log(this.colorArray.length);
};
};
I can't figure out how to get $("#upArrow").click() to call this.colorArray properly, or how to call this.addColor() in the .click() method! Please help.
Your Problem is that "this" means something different in each function body. So save the wanted "this" to a variable e.g. "self" and use that.
function GloveMode (name , array)
{
var self = this;
this.colorArray = array;
this.displaySettings = function()
{
//Title
$("#displayTitle").text(this.name);
//Display Color Set
$("#displayColors").empty();
//Totally Broken
$("#upArrow").click( function()
{
self.addColor();
});
};
this.addColor = function()
{
console.log(self.colorArray.length);
};
};

JQuery loop through input elements inside javascript function

I'm new to JQuery so if this is a obvious question my apologies. I have a simple form which holds some input fields. On the change-event I want to change a pre-defined array. The change event is triggered, but in this change-event I want to loop through all input-element again to fill/change an array. However the iteration doesn't work.
<script>
jsonObj = [];
$(document).ready(function(){
$("input[class=domain]").change(function(){
refreshData();
});
$("input[class=domain]").each(function() {
var domain = $(this).attr("name");
var score = $(this).val();
item = {}
item ["domain"] = domain;
item ["score"] = score;
jsonObj.push(item);
});
});
function refreshData() {
alert("Text Changed"); <<-- This line is reached.
$(document)("input [class=domain]").each(function() {
//TO DO: Refresh jsonObj
alert(domain); /<<-- This line is not reached.
});
}
</script>
A second question would be if it is possible to shorten this code. Now I have two separate function in the document.ready-event Change and
each both on the input-element.
T.I.A.
$('.domain').each(function(){
alert(domain);
})
use this instead of $(document)("input [class=domain]").each
You are missing a . and probably a .find before .each. Below code is what it should look like:
$(document).find("input[class=domain]").each(function() {
//TO DO: Refresh jsonObj
alert(domain);
});
UPDATE
With respect to your second question I would have shortened the code as below if the lines inside your .each was same as it would be in refreshData function:
jsonObj = [];
$(document).ready(function(){
refreshData();//call once on DOM Load
$('.domain').change(refreshData); //attach it as named function to change event
});
function refreshData() {
//keep all this code here
$(".domain").each(function() {
var domain = $(this).attr("name");
var score = $(this).val();
item = {}
item["domain"] = domain;
item["score"] = score;
jsonObj.push(item);
});
}
I have done some rectification and you can shorten it like:
<script>
jsonObj = []; // array declaration
$(document).ready(function(){
$("input.domain").change(function(){ // <----better to use a class selector
refreshData($("input.domain")); // <----pass the object in the function
}).change(); //<----trigger it on load to execute
});
function refreshData(el) { // get the passed object in the func arg
$(el).each(function() { // <----have a loop on it this way
var domain = $(this).attr("name"); // extract the name on current object in collection
var score = this.value; // get the value of the current object in iteration
var item = {}; // declare a new object
item["domain"] = domain; // set new prop and assign value here
item["score"] = score; // set new prop and assign value here
jsonObj.push(item); // now push the object in the array.
});
}
</script>
This expression is wrong for some reasons:
$(document)("input [class=domain]")
A. There must be no space between input and [class=domain]. This is the difference between "input that has the class domain" (input[class=domain]) and "input that one of its sub-nodes has the class domain" (input [class=domain]).
B. In order to query inside a jQuery element you need to use the find method like this: $(document).find("input [class=domain]"). But because document is the root element, you can just write $("input [class=domain]").
P.S
In CSS-selectors (like jQuery) there is a special syntax for searching classes, so instead you can just write input.domain.
So this how the line should look at last:
$("input.domain").each...
You can read more about css selectors here.
Strange code...
$(document)("input [class=domain]").each
Try this:
$("input[class=domain]").each

jQuery plugin instance variables

I'm beginning with jQuery plugins, apologies for the newbie question. My objective is to have a single plugin instantiated twice, where each instance has its own variables values. However, they seem to share the namespace.
For example, given the following plugin:
(function ( $ ) {
var x = false;
$.fn.test = function() {
alert(x);
if ( !x )
x = true;
return this;
};
}( jQuery ));
that is invoked from the following divs:
$( "div1" ).test();
$( "div2" ).test();
The alert displays first false, then true, when the objective is to have to sets of variables where the alert would display false twice.
is this possible?
There is some confusion in your question. Your plugin is a simple function. You don't "instantiate" a function by calling it. So you don't "instantiate" your plugin either.
You can instantiate things in your function, and persist them somewhere.
Since the outer scope runs only once, in your original solution you only get one instance of variable x.
If you create it inside the function, a new instance gets created every time you call it.
I assume you want to create an instance for every element you call this plugin on. A good solution would be to attach your data to the DOM element you initiate your plugin on, like:
(function ( $ ) {
$.fn.test = function() {
var vars = this.data('testPlugin');
if (!vars) {
vars = {
x: false,
something: 'else'
};
this.data('testPlugin', vars);
}
alert(vars.x);
vars.x = !vars.x;
return this;
};
}( jQuery ));
Try this fiddle.
You should put
var x = false;
inside $.fn.test function, otherwise the x variable is the same for all test() functions, and set to true after first call.
You can read more here about javascript variable scoping.
Actually, this is much easier than the previous answers. The context of this in your plugin is the jQuery object for the DOM element you're receiving based on the selector you provided. To gain uniqueness, simply iterate over each element, like so:
(function($) {
$.fn.test = function() {
return this.each(function() {
var x = false;
alert(x);
if (!x) {
x = true;
}
});
}
}(jQuery));
$("div1").test(); //false
$("div2").test(); // false
Here's a JSFiddle to confirm: http://jsfiddle.net/Z6j7f/

JavaScript global variables declaration

The following script works correctly although I need to make few amends. In each function I am getting the values need for the different formulas. However I tend to replicate the same line of code in different functions.
Ex.
function one(){ var v1= document.getElementById('one').value; }
function two(){ var v1= document.getElementById('one').value; }
Full code
I would like to declare all of the variables once and than only use the ones I need for the specific functions. If I declare them right at the top than once they are called they still hold the original value so I need to update that value to the current one if changed of course.
Your code will be very hard to read if you do it like in your fiddle.
Instead do
var myVars;
window.onload=function() {
myVars = {
'list_price': document.getElementById('list_price'),
'negotiated': document.getElementById('negotiated'),
.
.
'lease_payment': document.getElementById('lease_payment')
}
now you can do
var price = myVars.list_price.value;
or perhaps add a function
function getVal(id) {
var val = document.getElementById(id).value;
if (val =="" || isNaN(val)) return 0;
return parsetInt(val,10);
}
now you can do
var price = getVal("list_price");
mplungjan's solution is a great one. If you're at all concerned by your global vars leaking into the window scope, wrap your code in an Immediately Invoked Function Expression to prevent that from happening:
(function(){
// code goes here
}());
There are two ways to go about this:
Update your variable when the value changes
Use a function that always returns the correct value
1) You can add a listener for the change event or the keyup event that changes your global variable:
// save initial value
var val = document.getElementById('one').value;
// update the value when input is changed
addEventListener(document.getElementById('one'), 'change', function() {
val = document.getElementById('one').value;
});
console.log(val);
2) You can use a function that always returns the current value:
var val = function() { return document.getElementById('one').value; };
console.log(val());
2b) If you hate parenthesis, you can define a property that uses the function above as a getter:
Object.defineProperty(window, 'one', {
get : function() { return document.getElementById('one').value; }
});
console.log(one);

Changing the state of a toggle in JavaScript/jQuery

Is it possible to change the state of a toggle function? Like:
myDiv.toggle ... function 1 , function 2
I click on the myDiv element, the function 1 executes
I click again, function 2
I click again, function 1
BUT
Change the state
function 1 again
etc.
But I need to be able to change the state from outside the toggle function.
Here is a javascript object that uses closure to track it's state and toggle:
var TOGGLER = function() {
var _state = true;
var _msg = "function1";
var function1 = function() {
_msg = "function1";
}
var function2 = function() {
_msg = "function2";
}
return {
toggle: (function () {
_state = !_state;
if (_state) {
function1();
} else {
function2();
}
return _msg;
})
}
}();
Here is a jsfiddle that shows how to use it to toggle based with the following jquery: http://jsfiddle.net/yjPKH/5/
$(document).ready(function() {
$("#search").click(function() {
var message = TOGGLER.toggle();
$("#state").text(message);
});
});
The toggle function is meant for simple use cases. Changing the state externally is not "simple" anymore.
You cannot easily/safely (it's internal so it may change during minor versions) access the state variable of the toggle function easily as it's stored in the internal dataset of the element.
If you really want to do it, you can try this code though:
$._data(ELEMENT, "lastToggle" + func.guid, 0);
func is the function you passed to .toggle(), so you need to save this function in a variable. Here's a minimal example: http://jsfiddle.net/xqgrP/
However, since inside the function there's a var guid = fn.guid || jQuery.guid++ statement, I somehow think that the devs actually meant to use guid instead of func.guid for the _data key - in that case a minor update is very likely to break things. And after the fix you'd have to iterate over the data set to retrieve the correct key as there is no way to access the guid from outside.

Categories