Use array value as variable name - javascript

I need to use jQuery's keyup function to take the value from input html form elements and display said values in a div elsewhere.
The working code looks as follows:
$('#name').keyup(function() {
var name = $(this).val();
$('#name-in-document').html(name);
});
Since I have many identical instances of the above code block, I'd like to use a for loop to loop through an array of values. The catch is the name of the variable in the second line
var name = $(this).val();
would come from the array.
I have tried the following loop, which does not work because (as I understand it) a Javascript variable cannot be named an array value:
var inputsArray = ["phone", "name", "address"];
for (var i = 0; i < inputsArray.length; i++) {
$("#"+inputsArray[i]).keyup(function() {
var inputsArray[i] = $(this).val();
$("#"+inputsArray[i]+"-in-document").html(inputsArray[i]);
})
};
So I have two questions:
Is it true that I cannot use the array values to create a variable in the for loop?
Is there an alternate way to accomplish the same thing (getting the variable names from the array) that might work?
I am just beginning JavaScript and really appreciate any insight. Thank you!

1. It is not true
2. You'll need to make a closure over the variable i or over the value from inputArray[i] and inside the event-bind the keyword this refers to the DOMNode witch triggers the event:
Read more absout closures here How do JavaScript closures work?
var inputsArray = ["phone", "name", "address"],
i = 0,
len = inputsArray.length;
for ( ; i < len; i ++ ) {
makeKeyupBind(inputsArray[i]);
}
function makeKeyupBind( value ) {
$("#" + value).on("keyup", function() {
$("#" + value + "-in-document").html( this.value );
});
}

That variable only exists within the scope of the function passed as a callback for the keyup event so I don't really see the need to give it a dynamic name; you could call it absolutely anything at all and not run into conflicts.

For the alternative approach, I would recommend giving #name (and his friends) a class name, e.g.
<input class="js-key-up" id="name" />
Then you can do away with the array and the for loop altogether. Also, adding new HTML elements would not require adding items to the array.
HTML
<input class="js-key-up" id="phone">
<input class="js-key-up" id="name">
<input class="js-key-up" id="address">
<p id="phone-in-document"></p>
<p id="name-in-document"></p>
<p id="address-in-document"></p>
JavaScript
​
$('.js-key-up').keyup(function (e) {
var id = $(this).attr('id');
$('#' + id + '-in-document').html($(this).val());
});​
I've created a jsfiddle with the code in.

Try this:
var inputsArray = ["phone", "name", "address"];
for (var i = 0; i < inputsArray.length; i++) {
$("#"+inputsArray[i]).keyup(function() {
var valuesArray[i] = $(this).val();
$("#"+inputsArray[i]+"-in-document").html(valuesArray[i]);
})

var inputsArray = ["phone", "name", "address"];
for (var i = 0; i < inputsArray.length; i++) {
$("#"+inputsArray[i]).keyup(function() {
var htmlValue = $(this).val();
$("#"+inputsArray[i]+"-in-document").html(htmlValue);
})
I think you don't need to name variable from array, do you?

You can build a selector straight from the array and skip the loop completely. Use the id of the current input to create the selector for the other element
var inputsArray = ["phone", "name", "address"];
$('#'+ inputsArray.join(',#') ).keyup(){
$('#'+this.id+"-in-document").html( $(this).val() );
})
This will create the selector:
$('#phone,#name,#address')
Above assumes that you are trying to find elements :
$("#phone-in-document").html(val);
$("#name-in-document").html(val);/* etc*/

#Wes Cossick: this line inside of the loop is wrong:
var valuesArray[i] = $(this).val();
if you want to do it that way declare the array before the loop. that is problem of OP
#diana: if i understand you correct, you want to add a dynamic keyup handler to every item in the array? if it is that way, that code should do it (dont reassign items in the array!) the trick is to create a closure (code is untested).
var inputsArray = ["phone", "name", "address"];
for (var i = 0; i < inputsArray.length; i++) {
(function(item) {
$("#"+item).keyup(function() {
$("#"+item+"-in-document").html($(this).val());
});
})(inputsArray[i]);
};
if you are using jQuery (and it seems so ;-), take a look at the each-function in jQuery: http://api.jquery.com/jQuery.each/
that should be a lot easier for you ;-)

Related

Making variables assigned HTML ids with a function

I can make variables one by one like this:
var bookName = document.getElementById('bookName').value,
author = document.getElementById('author').value,
translator = document.getElementById('translator').value,
pageCount = document.getElementById('pageCount').value,
publisher = document.getElementById('publisher').value,
isbn = document.getElementById('isbn').value,
printingYear = document.getElementById('printingYear').value;
But it's so hard to write and it doesn't fit with the DRY rule. So I changed the code to this:
function variableMaker(argument) {
var tags = document.getElementsByTagName(argument);
for (var i = 0; i < tags.length; i++) {
var tags[i].name = tags[i].value;
}
}
variableMaker(input);
But I can't understand if it is the true way or if it is working? How do I check if it's true or not?
In this code, I tried to get the computer find all the input tags and make variables with their name property and assign it to its values for each of them.
If I understand correctly then you want to gather data from all <input> elements. If so, then you need to call it like this:
variableMaker('input'); // use quotes!
Still even then your function does not return anything, it just ends.
You'd also better create your own object for the return collection, instead of adding values to an existing object.
Here is a working solution:
function variableMaker(tagName) {
var elements = document.getElementsByTagName(tagName);
var items = {};
for (var i = 0; i < elements.length; i++) {
var elem = elements[i];
items[elem.id] = elem.value; // Use id as key, each points to the corresponding value.
}
return items;
}
var values = variableMaker('input');
console.log(values); // show the entire return object
console.log(values.author); // access individual items from the return object
console.log(values.isbn);
<input type="text" id="author" value="Dahl">
<input type="text" id="isbn" value="1234">
.

Using JQuery's .attr() When Selector Returns Multiple elements

I am trying to pull 2 pieces of data from each of several fields. All the fields have been given the same "name" so as to allow them to be referenced easily.
<input type="text" name="common_name" data-X='ABC'>
The first piece of data I am pulling is their values, which does seem to be working. My issue is when I try to use attr(). It just stops dead in the water at that point.
var length = $('[name=common_name]').size();
for(var i=0; i < length; i++){
var value = parseInt($('[name=common_name]').get(i).value); //doesn't kill the script
var dataX = $('[name=common_name]').get(i).attr('data-X'); //Script is killed here
}
Since I'm not having issues with using attr() in general when the selector is selecting the element based on an id, I would think the issue has to do with the fact that in this case multiple elements are being returned by jQuery. What I am confused by is that I thought that get(#) is supposed to grab a specific one…in which case I don't see what the problem would be. (After all, using get(#) DOES work when I use val()).
So…why doesn't attr() work here?
.get() returns a dom element reference which does not have the .attr() method, so you can use the .eq() method which will return a jQuery object
var length = $('[name=common_name]').size();
for (var i = 0; i < length; i++) {
var value = parseInt($('[name=common_name]').eq(i).val()); //doesn't kill the script
var dataX = $('[name=common_name]').eq(i).attr('data-X'); //Script is killed here
}
The correct way to iterate over an jQuery object collection is to use the .each() method where the callback will be invoked for each element in the jQuery collection
$('[name=common_name]').each(function () {
var $this = $(this);
var value = parseInt($this.val()); //or this.value
var dataX = $this.attr('data-X'); //or $this.data('X')
})
Suppose the html is like this
<input type="text" name="common_name" data-X='ABC'>
<input type="text" name="common_name" data-X='DEF'>
<input type="text" name="common_name" data-X='GHI'>
Now the script part
$('input[name="common_name"]').each(function() {
var el = $(this);
text_val = el.val();
data = el.attr('data-X');
console.log(text_val);
console.log(data);
});
attr is a jquery fn, should call by jquery object
use like this
$('[name=common_name]').attr('data-X')
so try
dataX = $($('[name=common_name]').get(i)).attr('data-X');

Javascript innerHTML updating issue

I have the following JavaScript line:
<div id="box" name="1" margin="4px" padding="4px" onclick="memory(1)"></div>
With the associated memory() function being:
function memory(a) {
var tmpDar = a-1;
var m = document.getElementsByName(tmpDar);
m.innerHTML = arrA[tmpDar];
}
However, when I try executing the code, the HTML doesn't alter... Can somebody please help me?
document.getElementsByName() returns a NodeList and not a single element!
So in order to set the innerHTML of your div, you have to reference an entry inside that array, e.g., like this:
function memory(a) {
var tmpDar = a-1;
var m = document.getElementsByName(tmpDar);
m[0].innerHTML = arrA[tmpDar];
}
In your code you set the innerHTML property for the NodeList object, which has no (visual) effect in the document.
In general it would be better to use id instead of name. Then you could use document.getElementById() in a way like this:
function memory(a) {
var tmpDar = a-1;
var m = document.getElementById(tmpDar);
m.innerHTML = arrA[tmpDar];
}
document.getElementsByName returns an array. So if the element that you want is unique with this name, you should replace your code by :
function memory(a) {
var tmpDar = a-1;
var m = document.getElementsByName(tmpDar);
m[0].innerHTML = arrA[tmpDar]; // Here I have added index 0
}
your trying to find all elements with a name of 0 as far as I can tell. And there is no 0 name.
Also what the other two said, it returns an array you need to call an index on that array.

Get value of JSON object with inner objects by HTML form field name without eval

I have a problem like this Convert an HTML form field to a JSON object with inner objects but in to the other direction.
This is the JSON Object response from the server:
{
company : "ACME, INC.",
contact : {
firstname : "Daffy",
lastname : "Duck"
}
}
And this is the HTML form:
<form id="myform">
Company: <input type="text" name="company" />
First Name: <input type="text" name="contact.firstname" />
Last Name: <input type="text" name="contact.lastname" />
</form>
And this is the (pseudo)code:
var aFormFields;
for (var i = 0, iMax = aFormFields.length; i < iMax; i++) {
var sFieldName = aFormFields[i].getAttribute('name');
eval("sFieldValue = oResponse."+sFieldName);
}
Ok my solution works, but i looking for a good way to remove the evil eval from the code.
And the solution should also work for form fields with any count of dots in the field name.
Instead of:
eval("sFieldValue = oResponse."+sFieldName);
Use for single dotted fields:
sFieldValue = oResponse[sFieldName];
This will retrieve the value via its key.
Now if you need more than that you need to do the following:
Split sFieldName on .
Loop over that array and go down in oResponse till you reach the value that you desire
Code could look like this:
var node = oResponse, parts = sFieldName.split('.');
while(parts.length > 0) {
node = node[parts.shift()];
}
// node will now have the desired value
Further information on "Member Operators":
https://developer.mozilla.org/en/JavaScript/Reference/Operators/Member_Operators
This works for a single property:
sFieldValue = oResponse[sFieldName]
But it won't work for nested data like contact.firstname.
For that, split the name by dots, and use loop through each name:
var aFormFields;
for (var i = 0, iMax = aFormFields.length; i < iMax; i++) {
var aFieldNameParts = aFormFields[i].getAttribute('name').split(".");
var oFieldValue = oResponse;
for(var j=0; j<aFieldNameParts.length; j++) {
oFieldValue = oFieldValue[aFieldNameParts[j]];
}
var sFieldValue = oFieldValue;
}
Note: if a property does not exist, an error will occur. You might want to check whether oFieldValue[ aFieldNameParts[j] ] exists or not.
While it is possible, I wouldn't loop over the input fields, but over the JSON object:
function fillForm (form, data, prefix) {
prefix = prefix ? prefix + "." : "";
for (var x in data) {
if (typeof data[x] === "string") {
var input = form.elements[prefix + x];
if (input)
input.value = data[x];
} else
fillForm(form, data[x], prefix + x);
}
}
fillForm(document.getElementById("myform"), oResponse);
(untested)
Assuming your naming scheme is consistent, you can convert the dot-notation into subscripts. You'd have to split the field name on the period and iterate or recurse over the tokens, converting each into a subscript. Of course this assumes that oResponse always contains a value for every field.
for (var i = 0; i < aFormFields.length; i++) {
var sFieldName = aFormFields[i].getAttribute('name');
var tokens = sFieldName.split('.');
var cur = oResponse;
for (var j = 0; j < tokens.length; j++) {
cur = cur[tokens[j]];
}
sFieldValue = cur;
}
please treat this as a combination of answer and question :)
i am currently trying to get my server to jsonify the data that i get sent from a form just like you...
in my case the form will in the end create a json object with multiple subobjects that can have subobjects which can have... as well.
the depth is up to the user so i should be able to support infinite recursion.
my "solution" so far just feels wrong, but it correctly does the job,
the function getRequestBody gets fed a req.body object from expressjs,
this is basically an object with the following mapping:
{
"ridic-ulously-deep-subobject": "value",
"ridic-ulously-deep-subobject2": "value",
"ridic-ulously-deep2-subobject3": "value",
}
the following html is in use:
<form>
<input name="ridic-ulously-long-class-string" value="my value" />
</form>
and the javascript function (that should work genericly, feed it a req.body object like above and it will return a json object):
function getRequestBody(reqB){
var reqBody = {};
for(var keys in reqB) {
var keyArr = keys.split('-');
switch(keyArr.length){
case 1:
if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
reqBody[keyArr[0]] = reqB[keys];
break;
case 2:
if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};
reqBody[keyArr[0]][keyArr[1]] = reqB[keys];
break;
case 3:
if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};
if(!reqBody[keyArr[0]][keyArr[1]][keyArr[2]]) reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = {};
reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = reqB[keys];
break;
case 4:
// ...
//and so on, always one line longer
}
return reqBody;
}
this just feels wrong and its only covering 5 levels of subobjects right now,
it might happen that an application has enough functionality to reach seven or even ten levels though.
this should be a common problem, but my search effort turned up nothing within 10 minutes,
which usually means that i am missing some keywords
or
that there is no viable solution [yet] (which i cant really imagine in this case).
is there someone out there who has imagination and logic sufficient enough to unspaghettify this or will i just have to expand this function with even more clutter to get me down to 10 possible sublevels?
i think that in the end it wont make a big difference performance wise,
but i would really like NOT to create this awful behemoth :D
have fun
jascha

Jquery: Matching indexes of two arrays, string and object to replace text in object?

I have two arrays, one is full of strings, the other is an array of objects. The indexes on each correspond, and I want to replace the text of each of the objects in my object array with the corresponding text in my string array.
For example, I have an array like this:
var textarr = ["value1", "value2", "value3"]
and a Jquery object array that contains a bunch of span elements:
var spans = $("span.myClass");
var spanarr = $.makeArray(spans);
I'm trying to use $.each() to iterate over each of the spans and use the corresponding index of my text array to assign a text value to the current span.
I've tried a couple different ways, and nothing seems to work. I'm missing some logic here, but why wouldn't this work?:
i = 0;
jQuery.each(spanarr, function() {
$(this).text(textarr[i]);
i++;
});
EDIT:
I think maybe the rest of my function might be causing this not to work. Here's the entire script:
$("span input:radio").click(function() {
if (($(this).is(":checked")) == true) {
var parent = $(this).parent();
var aunts = parent.parent().children();
var parentIndex = aunts.index(parent);
var indexToNthChild = parentIndex + 1;
var otherSpans = $(".DropDownMenu span:nth-child(" + indexToNthChild + ")");
var position = parent.position();
var topValue = position.top;
var smallPrice = otherSpans.children("span.dropDownPrice");
var pricearr = jQuery.makeArray(smallPrice);
var textarr = [];
jQuery.each(pricearr, function() {
textarr[i] = $(this).text();
});
alert(textarr); // Returns all the text values expected in array
var changers = $(".bigPriceChanger");
var changerarr = $.makeArray(changers);
$(".DropDownMenu").css({ "top": "-" + topValue + "px" });
$(".DropDownMenu span").css("background-image", "none");
parent.css({ "background": "#f3f1e7 url(assets/images/branding/DropDownArrow.gif) no-repeat right" });
otherSpans.css({ "background": "#f3f1e7 url(assets/images/branding/DropDownArrow.gif) no-repeat right" });
alert(changearr); // Returns all span objects in array
i = 0;
jQuery.each(changearr, function() {
$(this).text(textarr[i]);
i++;
});
}
});
Try
$("span.myClass").each(function (i) {
$(this).text(textarr[i]);
});
I think you don't need the call to makeArray. Just write:
i = 0;
jQuery.each($("span.myClass"), function() {
$(this).text(textarr[i++]);
});
I hate to end the question with a 'it was all a dream afterall' copout, but it turns out my browser was funked.
I've since checked my script (and the million variations of it that everyone suggested) in IE8 and someone else's firefox, and low and behold, it works.
You might want to try something like this:
var spans = $("span.myClass");
for(i=0;i<spans.length;i++){
spans[i].innerHTML = textarr[i];
}
You can think of a jQuery object like an extended version of an array. You can use length and [i] in reference to the number of DOM elements selected and the DOM element at a certain index respectively.
Your code is fine, although the makeArray call is redundant
There must be an error somewhere else,
here is your code running fine in firefox
http://jsbin.com/oxiwu
to edit go to http://jsbin.com/oxiwu/edit
I think your code is not working because the variable i was defined outside its scope.
Probably there is a better solution, but you could try the following:
function createF() {
var i = 0;
function f() {
$(this).text(textarr[i]);
i++;
}
return f;
}
f = createF();
jQuery.each(spanarr, f);
What's the reason for calling $.makeArray? You can iterate through your spans like this...
$("span.myClass").each(function(i) {
alert(textarr[i]);
$(this).text(textarr[i]);
});

Categories

Resources