When making a JavaScript script to iterate through a set of elements with the same class name, you can alter each of their properties individually.
How does the script know which element to edit if they don't have unique IDs? If they do in fact have unique ID's, how do you retrieve them? Using alert(); to display what is held in the node array from a simple document.getElementsByClassName(''); seems to display the type of element.
Could I actually store these results in an array for later use?
If on the documents load, I fetch an array of elements with a certain class name:
<script>
var buttonArray = document.getElementsByClassName('button');
</script>
Then iterate through this, and add the result at 'r' position to an object:
<script>
var buttonArray = document.getElementsByClassName('button');
var buttonObject = {};
for(r=0;r<buttonArray.length;r+=1)
{
buttonObject[buttonArray[r]] = [r*5,r*5,r*5];
}
</script>
Would I be able to find the array for each individual element with classname 'button' like so:
<script>
var buttonArray = document.getElementsByClassName('button');
var buttonObject = {};
function changeCol(buttonID)
{
var red = buttonObject[buttonID][0];
var green = buttonObject[buttonID][1];
var green = buttonObject[buttonID][2];
buttonID.style.backgroundColor = "rgb("+red+","+green+","+blue+")";
}
for(r=0;r<buttonArray.length;r+=1)
{
buttonObject[buttonArray[r]] = [r*5,r*5,r*5];
buttonArray[r].onclick = function(){ changeCol(this); };
}
</script>
I thought the this part of onclick = function(){ changeCol(this); }; would hold the same unique ID as I stored in the buttonObject object, as the variable name that held the array?
Should this work? I can't seem to get it to on my web page, so instead, I used the buttons innerHTML in the buttonObject as the variable name that held the array for that object. The problem with that, is that I will probably need two or more buttons to have the same innerHTML.
Here's the webpage as it currently is:
http://www.shadespeed.com
I need to re-make the script to allow buttons to have the same name.
Any tips / advice would be greatly appreciated.
Many thanks!
- Dan. :)
Let's say I have a deck of cards spread out on my desk, face up. I want to flip over all the red ones. I might do this:
desk.getCardsByColour("red").forEach(flipit);
// note, obviously not real JavaScript for a not real situation :p
So I scan through my cards, finding all the red ones. Then I flip them over. What you're asking is basically "how do I know which cards to flip over if they don't have unique IDs?" Well, do I need an ID to iterate through a collection of objects, in this case a set of cards? Of course not.
(Note that while cards in a deck do have a unique property in their content, let's just assume that's the element's content and not an id attribute, kay?)
Now, here's how I'd do what you're doing:
for( r=0; r<buttonArray.length; r++) {
buttonArray[r].buttonObject = [r*5,r*5,r*5];
buttonArray[r].onclick = changeCol;
}
function changeCol(button) {
var red = button.buttonObject[0];
var green = button.buttonObject[1];
var blue = button.buttonObject[2];
button.style.backgroundColor = "rgb("+red+","+green+","+blue+")";
}
Related
I've imported some XML files inside InDesign (you can see the structure in the picture below) and I've also created a script to get some statistics concerning this hierarchy.
For example, to count the "free" elements:
var items = app.activeDocument.xmlElements.everyItem();
var items1 = items.xmlElements.itemByName("cars");
var cars = items1.xmlElements.everyItem();
var c_free = cars.xmlElements.itemByName("free");
var cars_free = c_free.xmlElements.count().length;
I also have apartments in my structure that's why I'm using itemByName.
The code above returns the correct number of free cars in my structure.
What I'm trying to do - without any luck so far - is to target those free items (inside cars) and either delete all of them or a specific number.
My last attempt was using:
var del1 = myInputGroup2.add ("button", undefined, "Delete All");
del1.onClick = function () {
cars.xmlElements.everyItem().remove();
}
inside a dialog I've created.
Any suggestions will be appreciated cause I'm really stuck here.
I would probably use XPath for this. You can use evaluateXPathExpression to create an array of the elements you want to target. Assuming your root element is cars and it contains elements called cars1, and you want to delete all free elements within a cars1 element, you could do something like:
var myDoc = app.activeDocument;
//xmlElements[0] is your root element, in this case "cars". The xPath expression is evaluated from cars.
//evaluateXPathExpression returns an array of all of the free elements that are children of cars.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("cars1/free");
for (var i = myFrees.length - 1; i>=0; i--){
myFrees[i].remove();
}
Tweaking this would require some knowledge of xPath, but it's not terribly hard to learn the basics and it does seem like the simplest approach.
I think your main problem was that XMLElements hasn't a itemByName method. You can only reference XMLElements through their indeces or ids.
Secondly you assume that you got xmlElements from XPath expression but it's likely that you got nothing as your xpath seems uncorrect.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("./cars1/free");
var n = myFrees.length;
if ( !n ) {
alert("Aucun élément trouvé");
}
else {
while (n--) myFrees[n].remove();
}
You need to start your expression by setting the origin of your xpath. Here a dot "./" is used to tell you want to look for cars1/free xml elements at the "root" of the xmlelement. Using "//" on the contrary would have returned any cars/free items unregardingly of their locations.
I wish to name an array according to the table row containing the button that was clicked.
I get the table row thus:
var rowNum = $(this).parent().parent().index();
Now, I wish to name the array and access it.
var arrayName = 'arrTR' + rowNum;
window[arrayName] = new Array();
window[arrayName]["First"] = "Bob";
window[arrayName]["Last"] = "Roberts";
window[arrayName]["email"] = "me#there.com";
//The array should be accessible as arrTR__
alert(arrTR1["Last"]);
The alert does not work, so I am doing something wrong.
How should I refactor the code to allow me to update and access the array?
jsFiddle
What you're doing with the dynamically named variables is essentially creating an array of those variables (one for each rowNum), but giving each of those array elements its own individual named variable.
There is a much better way to do this. Instead of generating a series of dynamically named variables, make a single array or an object. Then add an element or property for each of the dynamically named variables you were going to generate.
Your test code could look like this:
var arrTR = [];
var rowNum = 1;
arrTR[rowNum] = {
First: 'Bob',
Last: 'Roberts',
email: 'me#there.com'
};
alert( arrTR[1].Last );
Alternatively, you can do something with $.data as mentioned in Johan's answer. But if you do use plain JavaScript code, use a single array as described here instead of multiple dynamically named variables.
There are several reasons to do it this way. It's cleaner and easier to understand the code, it may be faster when there are large numbers of entries, and you don't have to pollute the global namespace at all. You can define the var arrTR = []; in any scope that's visible to the other code that uses it.
Arrays and objects are made for keeping track of lists of things, so use them.
There is nothing wrong with your code, and the only place it has error is the alert since it is not defined on the first click button
see this fiddle with a little update
if(rowNum === 1)
alert(arrTR1["Last"]);
else if(rowNum === 2)
alert(arrTR2["Last"]);
fiddle
How about something like this?
$('.getinfo').click(function() {
var result = $('table tr:gt(0)').map(function(k, v){
return {
firstName: $(v).find('.fname').val(),
lastName: $(v).find('.lname').val(),
email: $(v).find('.email').val(),
}
}).get();
//update to show how you use the jQuery cache:
//1. set the value (using the body tag in this example):
$('body').data({ result: result });
//2. fetch it somewhere else:
var res = $('body').data('result');
});
Not sure how you want to handle the first row. I skip in in this case. You can access each row by result[index].
As you might have noticed, this saves all rows for each click. If you want to use the clicked row only, use the this pointer.
http://jsfiddle.net/nwW4h/4/
I know there are a lot of questions about this, but I can't find the solution to my problem and have been on it for a while now. I have two sets of input fields with the same name, one for product codes, and one for product names. These input fields can be taken away and added to the DOM by the user so there can be multiple:
Here is what I have so far, although this saves it so there all the codes are in one array, and all the names in another:
var updatedContent = [];
var varCode = {};
var varName = {};
$('.productVariationWrap.edit input[name="varVariationCode[]"]')
.each(function(i, vali){
varCode[i] = $(this).val();
});
$('.productVariationWrap.edit input[name="varVariationName[]"]')
.each(function(i1, vali1){
varName[i1] = $(this).val();
});
updatedContent.push(varCode);
updatedContent.push(varName);
I am trying to get it so the name and code go into the same array. i.e. the code is the key of the K = V pair?
Basically so I can loop through a final array and have the code and associated name easily accessible.
I can do this in PHP quite easily but no luck in javascript.
EDIT
I want the array to look like:
[
[code1, name1],
[code2, name2],
[code3, name3]
];
So after I can do a loop and for each of the arrays inside the master array, I can do something with the key (code1 for example) and the associated value (name1 for example). Does this make sense? Its kind of like a multi-dimensional array, although some people may argue against the validity of that statement when it comes to Javascript.
I think it's better for you to create an object that way you can access the key/value pairs later without having to loop if you don't want to:
var $codes = $('.productVariationWrap.edit input[name="varVariationCode[]"]'),
$names = $('.productVariationWrap.edit input[name="varVariationName[]"]'),
updatedContent = {};
for (var i = 0, il = $codes.length; i < il; i++) {
updatedContent[$codes.get(i).value] = $names.get(i).value;
}
Now for example, updatedContent.code1 == name1, and you can loop through the object if you want:
for (var k in updatedContent) {
// k == code
// updatedContent[k] == name
}
Using two loops is probably not optimal. It would be better to use a single loop that collected all the items, whether code or name, and then assembled them together.
Another issue: your selectors look a little funny to me. You said that there can be multiple of these controls in the page, but it is not correct for controls to have duplicate names unless they are mutually exclusive radio buttons/checkboxes--unless each pair of inputs is inside its own ancestor <form>? More detail on this would help me provide a better answer.
And a note: in your code you instantiated the varCode and varName variables as objects {}, but then use them like arrays []. Is that what you intended? When I first answered you, i was distracted by the "final output should look like this array" and missed that you wanted key = value pairs in an object. If you really meant what you said about the final result being nested arrays, then, the smallest modification you could make to your code to make it work as is would look like this:
var updatedContent = [];
$('.productVariationWrap.edit input[name="varVariationCode[]"]')
.each(function(i, vali){
updatedContent[i] = [$(this).val()]; //make it an array
});
$('.productVariationWrap.edit input[name="varVariationName[]"]')
.each(function(i1, vali1){
updatedContent[i1].push($(this).val()); //push 2nd value into the array
});
But since you wanted your Code to be unique indexes into the Name values, then we need to use an object instead of an array, with the Code the key the the Name the value:
var updatedContent = {},
w = $('.productVariationWrap.edit'),
codes = w.find('input[name="varVariationCode[]"]'),
names = w.find('input[name="varVariationName[]"]');
for (var i = codes.length - 1; i >= 0; i -= 1) {
updatedContent[codes.get(i).val()] = names.get(i).val();
});
And please note that this will produce an object, and the notation will look like this:
{
'code1': 'name1',
'code2': 'name2',
'code3': 'name3'
};
Now you can use the updatedContent object like so:
var code;
for (code in updatedContent) {
console.log(code, updatedContent[code]); //each code and name pair
}
Last of all, it seems a little brittle to rely on the Code and Name inputs to be returned in the separate jQuery objects in the same order. Some way to be sure you are correlating the right Code with the right Name seems important to me--even if the way you're doing it now works correctly, who's to say a future revision to the page layout wouldn't break something? I simply prefer explicit correlation instead of relying on page element order, but you may not feel the need for such surety.
I don't like the way to solve it with two loops
var updatedContent = []
$('.productVariationWrap.edit').each(function(i, vali){
var $this = $(this)
, tuple = [$this.find('input[name="varVariationCode[]"]').val()
, $this.find('input[name="varVariationName[]"]').val()]
updatedContent.push(tuple)
});
I need to use the web storage api to store style changes of the elements on one page.
I actually have no clue how to do this but I thought I'd start by getting the CSS attribute that's been changed and storing it in an array. Im trying to follow what's going here and tailoring it to my problem.
this is what i've tried in order to get the values but im not sure if it's correct:
function newItem(){
var bgImg = document.getElementsByTagName('body').bgImg[0].style.getPropertyValue('background');
var wideScreen = getElementById('sidebar').style.getPropertyValue('display');
var playerColor = getElementById('video_container').style.getPropertyValue('background-color');
}
I am not sure if the code i've written above grabs the information I need.
You can use getComputedStyle().
getComputedStyle() gives the final used values of all the CSS properties of an element.
var element = document.getElementById('sidebar'),
style = window.getComputedStyle(element),
display = style.getPropertyValue('display');
var element = document.getElementById('video_container'),
style = window.getComputedStyle(element),
bg = style.getPropertyValue('background-color');
Basically what I am wanting to do is take the variable named FROM and swap it with the variable named TO and vice visa, the reason for this is to allow the user to press a button which swaps the variables over when pressed. Exactly how it does when you press the swap button on google translate. Below is the code for the variables ect, but I have no idea on how to code the button so they swap over so to speak.
function save_options_from() {
var select = document.getElementById("FROM");
var FROM = select.children[select.selectedIndex].value;
localStorage["default_currency"] = FROM;
var
}
function save_options_to() {
var select = document.getElementById("TO");
var TO = select.children[select.selectedIndex].value;
localStorage["default_currency_to"] = TO;
The FROM and TO variables are local to the two functions and don't exist at the same time. I think what you want is this:
var originalDefault = localStorage['default_currency'];
localStorage['default_currency'] = localStorage['default_currency_to'];
localStorage['default_currency_to'] = originalDefault;
I would suggest two hidden fields FROM_old and TO_old for doing the swapping, as you need to capture the value before you change it.