Passing objects to events jQuery - javascript

In this example I'm trying to iterate over the properties of an object that's passed to a click handler, but I am getting unexpected results.
Here's the fiddle
So with a JS script like
$(document).ready(function ()
{
Label = function (name, toDate, fromDate)
{
this.name = name;
this.toDate = toDate;
this.fromDate = fromDate;
}
lbl = new Label('John', 'Today', 'Yesterday');
$('#btnSubmit').click(function ()
{
for (var i in lbl)
{
console.log(i);
}
});
$('#btnSubmit2').click(function (Label)
{
for (var i in Label)
{
console.log(i);
}
});
});
Why can't I pass an object in the function of a click event and iterate over its properties instead of using the forin loop like I did in the btnSubmit example?

The callback is always called with the event as argument. When you write click(function(Label){ you only give that event variable the name Label (thus shadowing your outside constructor).
But you can access the variables defined in the outer scope, so what you want is probably
var lbl = new Label('John', 'Today', 'Yesterday');
$('#btnSubmit').click(function(){
for (var i in lbl) {
console.log(i, lbl[i]); // for example "name", "John"
}
});

Related

Object Passed to Callback Function Not Updating

I have a global object variable that I pass to a function, then I call another function and assign that return value to the variable which was passed to the original function. This return value does not propagate to the global object which was passed into the function for some reason.
var DEFAULT_OPTIONS = {...}
var optionsElements = new Object();
function initializeOptions(elements, optionsObject, defaultOptions) {
elements = getOptionsElements();
optionsObject = loadOptions(elements, defaultOptions);
document.getElementById("movie_categories").addEventListener("change",
function(event) {
onCategoryChange(elements, event);
});
document.getElementById("tv_categories").addEventListener("change",
function(event) {
onCategoryChange(elements, event);
});
}
initializeOptions(optionsElements, currentOptions, DEFAULT_OPTIONS);
The elements var inside initializeOptions gets set properly, why does it not update optionsElements? My understanding is that Objects are passed by reference, so it seems to me this should work.
function getOptionsElements() {
options = {
"all_movies": document.getElementById("all_movies"),
"movie_3d": document.getElementById("movie_3d"),
"movie_480p": document.getElementById("movie_480p"),
"movie_bd-r": document.getElementById("movie_bd-r"),
"movie_bd-rip": document.getElementById("movie_bd-rip"),
"movie_cam": document.getElementById("movie_cam"),
"movie_dvd-r": document.getElementById("movie_dvd-r"),
"movie_hd-bluray": document.getElementById("movie_hd-bluray"),
"movie_kids": document.getElementById("movie_kids"),
"movie_mp4": document.getElementById("movie_mp4"),
"movie_non-english": document.getElementById("movie_non-english"),
"movie_packs": document.getElementById("movie_packs"),
"movie_web-dl": document.getElementById("movie_web-dl"),
"movie_xvid": document.getElementById("movie_xvid"),
"all_tv": document.getElementById("all_tv"),
"tv_documentaries": document.getElementById("tv_documentaries"),
"tv_sports": document.getElementById("tv_sports"),
"tv_480p": document.getElementById("tv_480p"),
"tv_bd": document.getElementById("tv_bd"),
"tv_dvd-r": document.getElementById("tv_dvd-r"),
"tv_dvd-rip": document.getElementById("tv_dvd-rip"),
"tv_mp4": document.getElementById("tv_mp4"),
"tv_non-english": document.getElementById("tv_non-english"),
"tv_packs": document.getElementById("tv_packs"),
"tv_packs-non-english": document.getElementById("tv_packs-non-english"),
"tv_sd-x264": document.getElementById("tv_sd-x264"),
"tv_web-dl": document.getElementById("tv_web-dl"),
"tv_x264": document.getElementById("tv_x264"),
"tv_xvid": document.getElementById("tv_xvid"),
"sort_options": document.getElementById("sort_options")
}
return options;
}
so after I assign elements = getOptionsElements, elements no longer
points to optionsElements, but is now a reference to the object
created inside getOptionsElements?
Yes. Try passing elements to getOptionsElements , using for..in loop within getOptionsElements to set properties of elements : optionsElements , return elements from getOptionsElements
var optionsElements = new Object();
function initializeOptions(elements, optionsObject, defaultOptions) {
elements = getOptionsElements(elements);
return elements
}
function getOptionsElements(opts) {
options = {
"a":1,
"b":2,
"c":3
};
for (var prop in options) {
opts[prop] = options[prop];
}
return opts;
};
console.log(initializeOptions(optionsElements), optionsElements)

Problems with scope

I am trying to assign a handler to every child element that I loop over. My problem is that the: target = child.items[i].id; will have the id of the last element that I loop over. So this part:
fn: function() {
isoNS.injectKey(target);
}
will always have the the id (target) of the last child. How can I do this?
I have tried put this in front, like this: isoNS.injectKey(this.target);
var arr=[];
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(target);
},
});
}
So my main problem, is that each different value of: target = child.items[i].id; is overwritten with the latest element each time. I hope I am making myself understood.
In case you are wondering what obj and child is... I left them out to make the code shorter and more understandable. just know that they do have values in them, and are never null
You could do this
var arr = Array.prototype.map.call(obj.items, function(obj, i) {
return {
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(child.items[i].id);
}
};
});
the Array map function provides the closure, and a nicer way to build up your arr
I use Array.prototype.map.call because there's no indication if obj.items is a TRUE array ... if it is, then it's a bit simpler
var arr = obj.items.map(function(obj, i) {
return {
key: sHolder.charAt(i),
fn: function() {
isoNS.injectKey(child.items[i].id);
}
};
});
The problem is your function is a closure and it has captured a reference to the target variable and this gets changed by your loop before the call back is invoked. A simple way to get around this is to wrap your function in another closure that captures the value of the target variable.
You can do this like so:
(function(capturedValue){
return function () {
// do something with the capturedValue
};
}(byRefObject));
The first function is part of an Immediately Invoked Function Expression (IIFE). It serves to capture the value of the byRefObject. You can read more about IIFE here.
Your code could look like this:
var arr=[];
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: (function(target) {
return function() {
isoNS.injectKey(target);
};
})(target)
},
});
}
This has to do with closures:
var arr=[];
function getFunc(t){
return function() {
isoNS.injectKey(t);
}};
for(var i = 0; i < obj.items.length; ++i) {
target = child.items[i].id;
arr.push({
key: sHolder.charAt(i),
fn: getFunc(target),
});
}

JavaScript: Not Calling Constructor Function

Can someone shed some light as to why this doesn't work the way I think it should (or what I'm overlooking).
function Pane(data) {
var state = {
show: function(data) {
var pane = document.querySelector('.pane[data-content='+data.target+']');
pane.classList.add('active');
},
hide: function(data) {
var pane = document.querySelector('.pane[data-content='+data.target+']');
var paneSibling = $(pane.parentNode.childNodes);
paneSibling.each(function(sibling) {
if(check.isElement(sibling)) {
var isActive = sibling.classList.contains('active');
if(sibling != pane && isActive) {
sibling.classList.remove('active');
};
};
});
}
}
return state;
}
So I can console log Pane(arg).show/hide and it'll log it as a function, so why is it when I call Pane(arg).show it doesn't do anything? The functions in the object work (outside of the constructor function in their own functions).
The function is returning the state object, so it will never return the constructed object, even when used with new. Since state contains those methods, you can just call the function and immediately invoke one of the methods on the returned object.
Now, if you're expecting show and hide to automatically have access to data via closure, it's not working because you're shadowing the variable by declaring the method parameters. You can do this instead:
function Pane(data) {
var state = {
show: function() {
var data = data || arguments[0];
var pane = document.querySelector('.pane[data-content='+data.target+']');
pane.classList.add('active');
},
hide: function() {
var data = data || arguments[0];
var pane = document.querySelector('.pane[data-content='+data.target+']');
var paneSibling = $(pane.parentNode.childNodes);
paneSibling.each(function(sibling) {
if(check.isElement(sibling)) {
var isActive = sibling.classList.contains('active');
if(sibling != pane && isActive) {
sibling.classList.remove('active');
};
};
});
}
}
return state;
}
Then you can use it like this:
Pane({}).show();
Or like this:
var p = Pane();
p.show();
Or force a new argument when needed:
p.show({foo:'bar'});
You are overriding the original argument in each function.
So what you are doing is to find elements with the attribute data-content='undefined'
This obviously doesn't work.
So to fix this you should just remove the data argument in the show/hide function.
Here is a plnkr showing the problem and fix.

variable closure using jQuery object notation

I have the following:
for (var i = 0; i <= 10; i += 1) {
var $page_button = $('<a>', {
html : i,
click : function () {
var index = i;
console.log(index);
return false;
}
});
$page_button.appendTo($wrapper);
}
I thought that var index would be defined separately for each iteration of the loop because it is enclosed within a function. In this case the value of index that is printed is always 10.
The link text is the correct value of i, because this is written to the DOM and is then immutable .
Why is this, and what should I change to fix my problem?
I know this is similar to lots of other questions but the behaviour of using this notation is causing a different result. I am using jQuery 1.7.2 (Can't use any newer unfortunately.)
You need to enclose that in a closure to solve the problem..
var $page_button = $('<a>', {
html : i,
click : (function (num) {
return function(){
var index = num;
console.log(index);
return false;
}
})(i)
});
A reference to i is closed up as part of the anonymous function. Note: not to its value, but a reference to i itself. When the function is run, the value is evaluated. Because the function runs after the loop has ended, the value will always be the last value of i. To pass just the value around, you do something like this:
click : (function (index) {
return function () {
console.log(index);
return false;
};
})(i)
You create an anonymous function which you execute immediately, which takes a value as argument and returns your actual function.
The variable index is defined separately for each execution of the function, but you copy the value from the variable i inside the function, so you will use the value of i as it is when the function runs, not when the function is created.
You need a function that is executed inside the loop to capture the value of the variable:
for (var i = 0; i <= 10; i += 1) {
(function(){
var index = i;
var $page_button = $('<a>', {
html : i,
click : function () {
console.log(index);
return false;
}
});
})();
$page_button.appendTo($wrapper);
}
Every handler is sharing the same i variable. Each one needs its own variable scope in order to reference a unique index.
for (var i = 0; i <= 10; i += 1) {
var $page_button = $('<a>', {
html : i,
click : makeHandler(i) // invoke makeHandler, which returns a function
});
$page_button.appendTo($wrapper);
}
function makeHandler(index) {
return function () {
console.log(index);
return false;
};
}
Here I made a makeHandler function that accepts the index argument, and returns a function that is used as the handler.
Because a function invocation sets up a new variable scope, and because a function is created and returned inside the makeHandler, each handler returned will reference its own scoped index number.

get value from one function to another function using javascript

i want to get value from one function to the another function. and i want to pass the value to handler page. but in that i cant get the value to pass .. here i had given the code. please help me. for example assume that for radio=MR & fname=john.
function getdata()
{
alert('hi');
var radio = document.getElementsByName("radiobuttonlist1");
for (var i = 0; i < radio.length; i++)
{
if (radio[i].checked)
alert(radio[i].value);
}
var fname=document.getElementById("Firstnametxt").value;
alert(fname);
}
here i want to get all those values to another function this is my another function.
function sendinfo()
{
getdata();
$(document).ready(function(){
var url="Handler.ashx?radio="+radio+"&fname="+fname+""; "here i want the values from above function"
alert(url);
$.getJSON(url,function(json)
{
$.each(json,function(i,weed)
{
});
});
});
}
thank you . help me
You can do this two ways.
Option 1
You can define those variables outside of both functions like:
var radio;
var fname;
getdata() {
radio = document.getElementsByName("radiobuttonlist1");
fname=document.getElementById("Firstnametxt").value;
// VALUE UPDATED HERE
}
sendinfo() {
// VARIABLE ACCESSIBLE HERE
}
And then whenever the values of those variables is updated it will be updated at the scope those variables were initially defined (outside those functions).
The scope of a javascript variable is within the curly braces {} that variable is in and any curly braces within that set. Scope in javascript often refers to those curly braces {}. There are exceptions including the if statement in which you can define variables inside of and access outside (assuming the condition was true).
Option 2
Or you can pass those variables as parameters to the second function like: sendinfo(radio, fname);
Passing values by returning them
You can return the values as an object literal in your getdata() function like this:
getdata() {
return {
radio : document.getElementsByName("radiobuttonlist1"),
fname : document.getElementById("Firstnametxt").value
}
}
Then do this:
sendinfo() {
var data = getdata();
}
And then access those variables like: data.radio and data.fname.
You can declare two variables globally,set them to the values you need in the first function and access them in the second function.
var radio;
var fname;
function getdata()
{
alert('hi');
radio = document.getElementsByName("radiobuttonlist1");
for (var i = 0; i < radio.length; i++)
{
if (radio[i].checked)
alert(radio[i].value);
}
fname=document.getElementById("Firstnametxt").value;
alert(fname);
}
function sendinfo()
{
getdata();
$(document).ready(function(){
var url="Handler.ashx?radio="+radio+"&fname="+fname+""; "here i want the values from above function"
alert(url);
$.getJSON(url,function(json)
{
$.each(json,function(i,weed)
{
});
});
});
}

Categories

Resources