With the power of jquery...
I'm attempting to add two selections together, they both contain the same type of element (<option>).
But the add(..) method doesn't seem to be playing ball.
var matchingRemovedOptions = removedOptions.filter(function() {
return this.text.toLowerCase().match(str.toLowerCase());
});
tempOptions.add(matchingRemovedOptions);
console.log(tempOptions.length);
console.log(matchingRemovedOptions.length);
As you can see im trying to filter out some option elements from the removedOptions selection and add these to the tempOptions selection.
But when using the console.log, the length of tempOptions stays the same as in, does not increase.
.add() returns a set with the elements/selector added, it doesn't actually add them to the set that it's called on. To get the effect you want, you need to update to the set it returns, like this:
tempOptions = tempOptions.add(matchingRemovedOptions);
If you think about all other tree traversal functions, they behave the same way, for example obj.find("...") doesn't change obj to what's found, only the rest of the chain operates on that set, which .find() returns.
You need to do another assignation:
tempOptions = tempOptions.add(matchingRemovedOptions);
Related
I'm editing a plugin that creates filters on an table like excel(drop-down), the problem is when I use it on a table that uses a table inside it, in fact the plugin will also take the values of the sub-table.
I therefore decided to exclude from the initial array, made up of all the rows, those elements that have a parent with a table that does not have an id.
So i forEach array and see if have id like:
this.tds.forEach((el) =>{
console.log(el.parentElement.parentElement.parentElement.id);
});
I was wondering if using parentElement three times like this is correct or there is another way
It's perfectly fine, as long as you're sure that the structure will always be the same.
But let's assume that you don't know if the structure will always be like this, but you do know the class of the parent you're looking for (or any other CSS query), then you could use the Element.closest() method to query your way up.
So let's say you want to find the closest table with an id value.
this.tds.forEach((el) => {
const parent = el.closest('table:not([id=""])');
if (parent !== null) {
console.log(parent.id);
}
});
This will walk up the DOM tree from the el as starting point, doing something in the likes of parentElement.parentElement.parentElement... until it reaches an element that has a value in the id attribute.
There's nothing wrong with the code.
But if you want to make the code a little more robust you can use Optional Chaining.
this.tds.forEach((el) =>{
console.log(el?.parentElement?.parentElement?.parentElement?.id);
});
I'm trying to get the values of all selected checkboxes with the following code to insert them in a textarea.
$('input[name="user"]:checked').each(function(){
parent.setSelectedGroup($(this).val()+ "\n");
});
but i always get only one value.
How to write the code in a correct way to get the value of ALL selected checkboxes?
Thanks ahead!
EDIT
1) "parent" because the checkboxes are in a fancybox.iframe.
2) setSelectedGroup in the parent window is
function setSelectedGroup(groupText){
$('#users').val(groupText);
You are getting all the values, simply on each loop through the collection you're passing a new value to setSelectedGroup. I assume that method replaces content rather than appending so you are simply not seeing it happen because its too fast.
parent.setSelectedGroup(
//select elements as a jquery matching set
$('[name="user"]:checked')
//get the value of each one and return as an array wrapped in jquery
//the signature of `.map` is callback( (index in the matching set), item)
.map(function(idx, el){ return $(el).val() })
//We're done with jquery, we just want a simple array so remove the jquery wrapper
.toArray()
//so that we can join all the elements in the array around a new line
.join('\n')
);
should do it.
A few other notes:
There's no reason to specify an input selector and a name attribute, usually name attributes are only used with the input/select/textarea series of elements.
I would also avoid writing to the DOM inside of a loop. Besides it being better technique to modify state fewer times, it tends to be worse for performance as the browser will have to do layout calculations on each pass through the loop.
I strongly recommend almost always selecting the parent element for the parts of the page that you're concerned with. And passing it through as the context parameter for jquery selectors. This will help you scope your html changes and not accidentally modify things in other parts of the page.
We can use dojo.query to get certain elements based of CSS selectors but how do we query on object types?
For example, get all the TextBox elements on the page and then use dojo.connect to bind a function?
This is not completely supported, yet there are two ways of doing it as i see it.
One, figure out which is the unique class for a TextBox (.dijitTextBox), call dojo.query('.dijitTextBox'), loop result dojo.forEach and get the widget with dijit.getEnclosingWidget(domnode)
var textboxArray = [];
dojo.forEach(dojo.query('.dijitTextBox'), function(domnode) {
textboxArray.push(dijit.getEnclosingWidget(domnode));
});
Or two, loop the dijit.registry._hash, test declaredClass, if its dijit.form.TextBox - connect.
var textboxArray = dojo.filter(dijit.registry._hash, function(widget) {
return widget.declaredClass && widget.declaredClass == 'dijit.form.TextBox';
})
Depending your setup, choose the most efficient one. The latter is commonly best - unless you have 100's of widgets in your page. The first will have to xpath all your elements of the page. Allthough, remember that dojo.query takes a second parameter as 'parentNode'
I'm making a small appwith localstaorage (not implemented yet): you type a note int the text area and it is display in a list
the note are stacked in an object called notes (for localstorage in the future);
But my problem is : I can add a note, but when I try to remove on of them, I have to remove my li and the related note object in the 'notes' array, so i decided to use splice method, but it works in a strange way...
when i click 'close', it works fine one or two times but at a moment the array stays with one or two object in it...
I tried different ways to solve the problem but without success...
Here is the fiddle : http://jsfiddle.net/h8hg6/1/
thanks for your help
I have made some modifications to your fiddle that I think solve the problem. Essentially you were using .splice incorrectly, and your Array was falling out of sync with your note elements. I've replaced your array with an numeric-based object because it is much easier to deal with. Here are some of the relevant changes:
http://jsfiddle.net/h8hg6/2/
var notes = {}; // notes is now an object instead of an array
// snip
var number = jQuery(this).parents('li').data('number');
delete notes[number]; // this is how you remove properties from an object
// snip
var note = {
color: color,
text: text
};
notes[i] = note; // add this object as a property of the notes object
i++;
The problem is that your call to splice uses the value of the queue variable to determine the index of the element that will be removed in the notes array. Right here:
notes.splice(queue, 1);
Since the queue value is always increasing (right here):
function addNoteToPage(){
i++;
...
jQuery('ul#notes li:first').before('<li data-queue="'+ i +'">'+ note.text +' <a href=""#>CLOSE</a>
You hit a moment where you call splice on an non-existing index of the notes array and nothing is removed as a result. Basically, you end up with an out-of-sync notes array.
You need to make sure that the value of the data-queue attribute coincides with the real index of the element in the notes array so that your call to splice(queue,1) always succeeds and removes the appropriate array element.
With that said, if above answer works for you, I'd go with that one. I just wanted to give you more insight on what was going on...
Is there any problem with loading the same set of values in 2 different HTML form dropdowns? My code looks like this:
var dr1=document.getElementById("dr1");
var dr2=document.getElementById("dr2");
for (nombre in elements) {
var opcion=document.createElement('OPTION');
var cam=elements[nombre];
opcion.value=nombre;
opcion.text=cam["nombreCompleto"];
//Añadimos a los 2 dropdowns
dr2.add(opcion, null);
dr1.add(opcion, null);
}
dr1.selectedIndex=0;
dr2.selectedIndex=0;
This load the same set of values to two different dropdowns. However, when executed, it only loads whatever dropdown appears last in the code; in the above example, it would have been "dr1" (and if I put the "dr2.add(option.null)" line last, it loads that one). If I load only one dropdown (commenting out the other one) it works fine.
All of this is on Firefox 3.6.10.
Yes, your OPTION objects will first be added to dr2, then to dr1. There won't be created copies when calling add, but the object you just created will be moved from nowhere to dr2, then to dr1.
The general idea is that you can't have a DOM object in two different places at the same time. You may want to take a look into JavaScript object cloning. See here for some useful information: What is the most efficient way to deep clone an object in JavaScript? .
If you just need to clone DOM element objects you can use cloneNode(). See here for a complete list of available members and methods: http://www.w3schools.com/jsref/dom_obj_all.asp
No, it doesn't work. Refactor the code to create the option node into a function.
function createOption(...) {
var opcion=document.createElement('OPTION');
var cam=elements[nombre];
opcion.value=nombre;
opcion.text=cam["nombreCompleto"];
return opcion;
}
dr1.add(createOption(), null);
dr2.add(createOption(), null);
To add it to the second element just clone it ..
dr2.add(opcion, null);
dr1.add(opcion.cloneNode(true), null);
example at http://www.jsfiddle.net/7Kxdu/