Javascript array not working as expected - javascript

I'm pretty new to js/jquery. For each checkbox with the ID of check$ (where $ is a sequential number), I want to toggle the class "agree" of the surrounding span that uses the same check$ (but as a class). I don't want to have to hard-code the list of matching checkboxes, as this may vary.
Here's my code. This function works as expected:
agree = function (checkbox, span) {
$(checkbox).change(function(){
$(span).toggleClass('agree');
});
};
This is what I'm trying to pass to the above function, which does not work:
$(function() {
var elemid = 'check',
checks = Array($('[id^='+elemid+']').length);
console.log(checks);
for (i=0; i < checks; i++) {
agree('#'+elemid+checks[i], "."+elemid+checks[i]);
}
});
console.log(checks) returns [undefined × 4]. The number of elements is correct, but I don't know why it's undefined, or whether that is even significant.
The following code works as expected, but as I say, I'd rather not have to specify every matched element:
$(function() {
var checks = ["check1", "check2", "check3", "check4"];
for (i=0; i < checks.length; i++) {
agree('#'+checks[i], "."+checks[i]);
}
});
Thanks.
Edit: Thanks to Jack, I was overlooking the most simple method. I added the same class to all checkboxes and spans, and solved the problem with this:
$('input.check').change(function(){
$(this).closest('span.check').toggleClass('agree');
});

I might be totally missing something, but I'm pretty sure you are just trying to attach a change handler to each checkbox. In this case you can give them all the same class. I'm also guessing at your html structure for the span.
For reference:
http://api.jquery.com/closest/
http://docs.jquery.com/Tutorials:How_jQuery_Works
$('.yourcheckboxclass').change(function(){ //grab all elements with this class and attach this change handler
$(this).closest('span').toggleClass('agree');
});

The reason that the array is full of undefined values, is that you are just getting the number of items in the jQuery object, and create an array with that size. The jQuery object is discarded.
Put the jQuery object in the variable instead:
var elemid = 'check', checks = $('[id^='+elemid+']');
checks.each(function(){
agree(this, "."+elemid+checks[i]);
});

Related

Detect if a div with id including number is clicked

My html code has X elements, with their ids in this form:
viewer_mX
Here, X is a number from 1 to m (m can be different each time).
I want to use javascript to get the number X of the respective element when somebody clicks one of these elements.
I realise I should probably use a class (.viewer) and and id (#x) containing the number. However, I am using a library to generate the html elements and I am stuck with this protocol and will have to make the best of it.
This is the javascript I have so far:
$(document).ready(function () {
$("#viewer>...").click(function () {
x = ...
var number = x;
});
});
What's missing in this code (indicated by 3 dots) is that viewer is not the full ID, but could be post-pended with something. I want to store whatever is after the clicked div in number, but I can't figure out which function to use for that.
Try this,
$("[id^='viewer_']").click(function () {
var number = this.id.match(/\d+$/)[0];
});
Why not use class to identify elements and then data-attribute for storing your id (data-id for example) and then get value of this data-attribute?
Otherwise I would personally use something like this
$(this).attr('id').substr("viewer_m".length);
Either split or a reg exp
var id = this.id.split("_m")[1]
or
var id = this.id.match(/\d+$/)[0];
or better yet, use a data attribute
<div data-mid="123">
and reference it
$("[data-mid]").on("click", function () {
var id = $(this).data("mid");
});
A better approach to this, as #Wax Cage mentioned, is to use classes and data attributes for better organizing. Example:
<div class="viewer" data-viewer-id="1">...</div>
$('.viewer').on('click', function() {
var viewerId = $(this).data('viewerId');
// ...
});

How can I select with jQuery and use javascript method to apply a change?

I'd like to use a variation of this code, but I'm having a bit of trouble concatenating the following snippet. Essentially using a for loop from a returned value.length and append the buttons, then replace data for buttons:
for(var i...){
var button = "'<button>%data%</button>'";
$(".buttons").append(button).replace("%data%", var);
};
You don't need to make the replace after you append the element. You should just set var directly on element either with text or html, depending on what var holds. Also, please notice that jQuery doesn't have a method called replace, it only has replaceWith (http://api.jquery.com/replaceWith/) and replaceAll (http://api.jquery.com/replaceAll/).
for(var i...){
var button = $("<button></button>").text(var);
$(".buttons").append(button);
};

traverse of tree in javascript

I have a javascript variable like below:
var treeNode= [{"id":"T1"},{"id":"T2","children":[{"id":"T3"},{"id":"T4"},{"id":"T5","children":[{"id":"T6"}, {"id":"T7"},{"id":"T8"}]},{"id":"T9"},{"id":"T10"}]},{"id":"T11"},{"id":"T12"}];
node t3,t4,t5,t6,t7,t8,t9,t10 are the child of node t2
i have a link of deactivate on each node.on click on deactivate link make active and delete link .mentioned in image.
now i want to make same active and delete link on all child node of parent node.
for example T3,T4,T5,T6,T7,T8,T9,T10 are the child of T2.
if i click on T5 then this will work on T6,T7,T8.
I tried below recursive code.may be my approach is not right.please advice.
var objTreeNode = eval(treeNode);
trav(objTreeNode);
function trav(TreeNodeObj){
var i=0;
for (i=0;i<TreeNodeObj.length;i++){
if(!TreeNodeObj[i].children){
if(objID==TreeNodeObj[i].id){ // will get T2 if click on deactivate link of Item T2
document.getElementById('span_'+TreeNodeObj[i].id).innerHTML = 'Activate <a href="javascript:deleteNode(\'' + objID
+'\');">Delete</a>';
}
}
else{
childObj = TreeNodeObj[i].children;
trav(childObj)
}
}
}
There are a few silly things in your code, let me fix them:
1. "Eval is evil!"
var treeNode= [{"id":"T1"},{"id":"T2","children":[{"id":"T3"}]}];
var objTreeNode = eval(treeNode);
trav(objTreeNode);
Why would you call eval()?
Let's see what MDN has to say about this:
Don't use eval! It's dangerous and slow. There are safe (and fast!) alternatives to eval() for common use-cases.
So what is your "use-case"? Why do you call eval here? What is the "better" solution? If you read the whole documentation on MDN you can read that:
If the argument of eval() is not a string, eval() returns the argument unchanged.
So unless treeNode is a string var objTreeNode = eval(treeNode); basically equals to var objTreeNode = treeNode;
You can drop that whole eval() line and just use treeNode. It's already an object.
2. camelCase
function trav(TreeNodeObj) {
This is not an error just a convention: In JavaScript (and also in most languages with C-like syntax) the parameters of a function are written with lower camel case (first letter is lowercase, and every other word's first letter is uppercase).
function trav(treeNodeObj) {
3. objID is undefined
There is no objID variable defined in your code. Although it is possible that you have a global defined elsewhere at the given time, it is much safer to introduce it as a parameter in your function.
function trav(treeNodeObj, objID) {
4. What your code does with what and when
Let me just figure out what your code currently does:
Iterates over a given object's children property (which is hopefully an array).
If an element has no children
Check if the array item has a desired ID property, and change it's innerHTML
Else
Call the function on the children
So what it does: Changes the element with the given ID if it has no children.
What you need is: Change the element with the given ID and also it's children.
I just modified your function like this:
function trav(treeNodeObj, objID, activate) {
var i = 0;
for (i = 0; i < treeNodeObj.length; i++) {
var childrenActive = false;
if (objID === treeNodeObj[i].id || activate) { // will get T2 if click on deactivate link of Item T2
childrenActive = true;
document.getElementById('span_' + treeNodeObj[i].id).innerHTML = 'Activate Delete';
}
if (treeNodeObj[i].children) {
childObj = treeNodeObj[i].children;
trav(childObj, objID, childrenActive);
}
}
}
Since you need to change all the child elements I needed to introduce a cut. This is the activate parameter. If the activate parameter is true you don't need to check the ID anymore you know that we are iterating over the subelements of the element with the given ID, and therefore change the element anyway.
Also you need to change the elements even if they have child nodes, so I restructured the if-s.
I have also made a jsfiddle for you to test: http://jsfiddle.net/JZ52g/3/
You can change the id parameter at the function call.

Selecting from a list of previously selected elements via jQuery

I'm having a bit of a brain fart here, and hoping someone can help me find a 1-line solution to this problem, without having to call .each().
So I get a list of all checkboxes within a container like this:
var checkboxes = $(':checkbox', '#surveyModal');
At some point later, I need to find out if any (or none) of the checkboxes are checked within that list.
I expected something like these to work:
$(':checked', checkboxes)
// or
checkboxes.attr(':checked')
// or
$(checkboxes).attr(':checked')
But it doesn't. The only thing I've had success with is calling each() and then checking each individually. But that means I'll have to keep a separate variable (.e.g. someAreChecked at a higher-level scope, which I don't feel is optimal.
checkboxes.each(function () {
if ($(this).attr('checked')) {
someAreChecked = true;
}
});
I was hoping that I can easily in a single line do such a check:
if (checkboxes.('get checked count') == 0)
{
}
Thanks in advance.
The filter function is what you're looking for :)
checkboxes.filter(':checked').length;
.attr returns the value of an attribute, and you have to pass the attribute's name to it, not a selector.
Just use .is instead.
Description: Check the current matched set of elements against a
selector, element, or jQuery object and return true if at least one of
these elements matches the given arguments.
$(checkboxes).is(':checked')
This should do it:
$("input[type=checkbox][checked]").length

jQuery set call back on child elements

I am trying to attach an onChange callback to all the input elements under the div #dim. It selects all 3 input elements, but returns an exception:
Uncaught TypeError: Object 0 has no method 'change'
It may be because x may not be a jQuery object. How would I make this work?
function registercb() {
var sel = $("div.dim > input");
for (x in sel) {
x.change(function() {
dosomething();
});
}
}
You can simply do:
function registercb() {
$("div.dim > input").change(dosomething);
}
A few things to watch for:
Inside that iteration (don't use this, see the next point) x is the DOM element, not a jQuery object which has the .change() method, you would need to wrap it in a jQuery object like $(x), but again that isn't the correct solution here.
Don't use a for(...in...) loop to iterate an object (a jQuery object is array-like), that type of loop is for enumeration.
Most jQuery functions (almost all) run on more than one element, so just run it on the set to affect all elements, .change() is one of these.
In the cases you do need to loop, check out .each(), as it'll make your life much easier, don't use this here, it's only an example of what it would look like:
Example:
function registercb() {
$("div.dim > input").each(function() {
$(this).change(dosomething);
});
}
You don't have to loop over the elements. You can think of a jQuery object as holding a collection. When you do:
var sel = $("div.dim > input");
It means that sel has all the input elements in it, so then when you run a method like change() it will affect all of the elements in the collection. Thus you can do something like this:
function registercb() {
$("div.dim > input").change(function(){
dosomething();
});
}
Bonus knowledge: Now your problem is that when you were doing for( x in sel ) you are getting a lot of stuff on the jQuery object itself that you don't want. If you run the following code in chrome you'll see it outputting a lot unexpected stuff:
for( x in sel ){
console.log( x );
}
Instead jQuery has the each that lets you loop over the things you want:
sel.each(function(index, item){
console.log(item);
});
You can even use it on other things, which is really handy!
$([1,2,3]).each(function( index item ){
console.log( item ); // 1,2,3
})
Assuming your 'dim' div has an ID rather than a class of dim, you can simply do this:
$("#dim > input").change(function() { dosomething(); });
Working example.
In the text you refer to #dim whereas in the code you're refering to .dim - # selects by ID and . selects by class, so if your div is in the format <div id="dim"> then you won't find any matched elements with div.dim as your selector.

Categories

Resources