How do I retrieve the actual string selector - javascript

Given a select tag with options:
<div id='mydiv'>0</div>
<select id="mysel">
<option id="opt1">a</option>
<option id="opt2">b</option>
</select>...
How do I retrieve the actual string selection? Ie. How do I retrieve the actual "select#mysel" from the var mysel?
example of how this might be used?
var mysel = $("select#mysel");
var myopt = $(mysel.actualstringselection + " option");
var myoptcount = myopt.length;
alert("my option count:" + myoptcount );
$("#mydiv").html(myoptcount);

Answer for updated question:
How do I retrieve the actual "select#mysel" from the var mysel?
example of how this might be used?
var mysel = $("select#mysel");
var myopt = $(mysel.actualstringselection + " option");
So basically, you want the original selector string that you passed into $() in order to get mysel.
You can't get that. jQuery never offered an official way to do it. For a long time, there was an undocumented property on jQuery instances that contained it (mostly, most of the time), but it was always undocumented because it wasn't entirely reliable, and it doesn't even exist in current versions.
So instead, you can do it yourself:
var selector = "select#mysel";
var mysel = $(selector).data("selector", selector);
// Presumably somewhere else where you no longer have the `selector` variable:
var myopt = $(mysel.data("selector") + " option");
But, you wouldn't want to use that for the above. (You'd use find, as described originally [below]). The only reason I can think of for such a thing is if you've changed the DOM and want to repeat the original query. E.g.:
mysel = $(mysel.data("selector")); // Goes looking for the elements again
Original answer:
If after this line:
var mysel = $("select#mysel");
...you're trying to use mysel to find something within the descendant elements of any DOM elements in that jQuery object, you use find:
var optionElements = mysel.find("option");

Related

parentNode.removeChild not removing last element. But why?

I am working on a javascript code where I can clone an element, but also want to delete one on click. Cloning works, but I can't remove one.
I have the following elements.
<input list="accountsdeb" name="deblist[1]" id="deblist" autocomplete="off">
<input list="accountsdeb" name="deblist[2]" id="deblist" autocomplete="off">
And now I want to remove the last one on click (last = highest number).
function remove1() {
var dbl = document.querySelectorAll('#deblist').length;
var dbla = dbl;
var elem = document.getElementsByName("deblist["+dbla+"]");
alert(dbla);
//var last = debelelast - 1;
elem.parentNode.removeChild(elem);
}
As an orientation I used to have a look on an example from W3S and Stack. I have also seen that this works:
var elem = document.getElementById("myDiv");
elem.parentNode.removeChild(elem);
But this is random and as you can see I have tried to include this in my code.
The error I get is:
Uncaught TypeError: Cannot read property 'removeChild' of undefined
at HTMLAnchorElement.remove1 (index.php:179)
Where's the problem in my code, where is my thinking wrong?
I see two issues in the piece of code you provided,
deblist is used as id for 2 elements which is not advisable and due to this document.querySelectorAll('#deblist').length returns 2 (I am not sure if you intending to do so)
document.getElementsByName() (check here) will return a NodeList which needs to be iterated in order to access any of the returned elements. So here you need to select the child element by giving its index. In your case elem will have one element for the matched name deblist[2] and hence you need to access it like elem[0] for selecting its parent and deleting its child.
So the updated the code would be,
var dbl = document.querySelectorAll('#deblist').length;
var dbla = dbl;
// console.log('dbla', dbla);
var elem = document.getElementsByName("deblist["+dbla+"]");
// console.log('elem 0', elem[0]);
// console.log('elem parentNode', elem[0].parentNode);
//var last = debelelast - 1;
elem[0].parentNode.removeChild(elem[0]);
Check the fiddle here
If the inputs are part of a group they could share a name property or such, and the use of jQuery could help you do something like...
$("input[name='group1']").last().parent().remove()
Or if not part of a group then just....
$("input").last().parent().remove()

JavaScript - Find ID that matches data attribute value

I have a variable that finds the data attribute of an element that is clicked on in a callback function:
var dropdown = document.getElementsByClassName('js-dropdown');
for (i = 0; i < dropdown.length; i++) {
dropdown[i].addEventListener("click", callBack (dropdown[i]));
}
function callBack (i) {
return function () {
var thisDropdown = i.getAttribute('data-dropdown');
//rest of the code here
}
}
I am basically trying to do this
$('#' + thisDropdown ).toggleClass('is-active');
...but in vanilla JS.
This works fine using jQuery however I would like a vanilla version.
So when a user clicks on an element that activates a drop down, I want it to dynamically find its relevant ID matching value within the document so it can toggle a show/hide class.
I've searched through a lot of SO questions and everyone replies with a jQuery answer which is not what I am looking for.
I've been trying to do something along the lines of
var idValue = document.getElementById(thisDropdown);
Then
var findId= idValue + thisDropdown;
findId.toggleClass('is-active');
Obviously that does not work the same way the jQuery statement works... any ideas?
Ignore the toggleClass method! Some of you may find this contradictory as I want vanilla JS.
To replace $('#' + thisDropdown ).toggleClass('is-active'); with plain js, use Element.classList. Like this:
const someElement = document.querySelector('#' + thisDropdown);
someElement.classList.toggle("is-active");
I like #kamyl's answer, but you might need backward compatibility. For that, see if you can find a polyfill.
If you have to write it yourself, use string.split(" ") to get your list of active attributes and iterate to find if it exists; add if not, remove if so...then array.join(" ") and replace the class attribute with it.

Search key in json object based on value

I populate the options of a select input field based on json data I get from a php-script.
This works fine, but I want to show some extra info, based on the selected option.
Basically, I'm looking for a way to find the key that goes with the selected option:
$("#code").html(result[whichkey]["uniquecode"]);
This fiddle hopefully makes my question a bit more clearer.
Any help is much appreciated!
Given that the option element is created with the uniquecode of the object as its value, why do you even need to access the object again? You can just retrieve the value property of the selected option...?
Assuming this is just because you've oversimplified your example, and the objects within the array do hold other useful data which is not held in the option element itself, then you can use $.grep to filter the array of objects by the selected uniquecode, like this:
var json = '[{"uniquecode":"b32dez2","name":"John Doe","foo":"bar"},{"uniquecode":"a2df32","name":"Adam Smith","foo":"buzz"}]';
var result = JSON.parse(json);
var $sel = $('#names').change(function() {
var value = this.value;
var obj = $.grep(result, function(e) {
return e.uniquecode == value;
});
$("#code").html(obj[0].uniquecode + ' / ' + obj[0].foo)
});;
result.forEach(function(obj) {
$('<option value="' + obj.uniquecode + '">' + obj.name + '</option>').appendTo($sel)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="names"></select>
<div id="code"></div>
Note that I added the foo property to the object to show you how to access properties of the object outside of those placed directly on the option element.
Also note that I simplified the code that generates the option elements as well. If you're going to use jQuery once in your project, you may as well use it everywhere.

Why do you have to re-select a JQuery element from a collection?

I have a number of check-boxes on my page, each has a name attribute for its useful value.
I want to get a list of values for the checked items only. I can get a collection of elements like so...
var checkedItems = $(".checkbox:checked");
Now I want to create the list (string) so I create a loop...
var list = "";
for (var i = 0; i < checkedItems.length; i++) {
list += $(checkedItems[i]).attr("name") + "\n";
}
This works and gives me my list. But the question is, why do I have to apply the JQuery object thingy i.e. $(...) to use the attr property?
if I had the following instead it would not work...
list += checkedItems[i].attr("name") + "\n";
But surely the array should be a collection of JQuery elements already? Why re-cast?
Here is a JSFiddle of the working example if anybody wants to try it
EDIT: Why does this work...
var item = $("#item");
var name = item.attr("name");
checkedItems[i] is a raw DOM element, not a jQuery object.
To get a jQuery object for a given element in the set, call checkedItems.eq(i).
You can do this more nicely by writing
var list = $(".checkbox:checked")
.map(function() { return this.name; })
.get()
.join('\n');
The code in your question is wrong, because
$(checkedItems[i].attr("name"))
should really be
$(checkedItems[i]).attr("name")
Besides that, you should really do it like this
var list = "";
checkedItems.each(function(){ list += this.name + '\n'; });
Demo at http://jsfiddle.net/dGeNR/2/
The reason it would not work, is that when you access the elements in the jQuery object with [] you get back a direct reference to the DOM element, and not another jQuery object.
I presume that what you actually do is this:
list += $(checkedItems[i]).attr("name") + "\n";
checkedItems is a jQuery selection. It contains references to the elements that it contains. These elements can be manipulated by jQuery methods, or accessed directly with checkedItems[n], where n is a 0-based index.
Those properties are not jQuery selections: they are the native DOM elements. If you want to use a jQuery method like attr, you need to create a new jQuery object, wrapping that native object.
In this case, you can avoid that by using the eq method, which gets a jQuery selection from an original selection by using a numeric key:
list += checkedItems.eq(i).attr('name') + "\n";
Even better in your case would be to use a combination of map and get and Array.prototype.join:
var list = checkedItems.map(function() {
return this.name;
}).get().join('\n');
Well the list-building code in your question doesn't work; it should be:
for (var i = 0; i < checkedItems.length; i++)
list += $(checkedItems[i]).attr("name") + "\n"; // or just checkedItems[i].name
The ".attr()" function is just defined to return the attribute value for the first element in the list of matched elements. It could have been designed to return an array (like the ".pluck()" function in the Prototype library), but it just doesn't work that way.
The ".css()" jQuery method is similar in that regard, as is ".val()".
Another way to do what you want is:
var list = checkedItems.map(function() {
return this.name;
}).get().join('\n'); // thanks SLaks :-)
To be able to call jQuery functions, you need to wrap the content in $() or jQuery().
I have fixed the example at http://jsfiddle.net/dGeNR/1/
You need to use list += $(checkedItems[i]).attr("name") + "\n";

How do I get element's className inside loop of elements?

I am trying to create a function that given a divid, and a list of classes, will then do some text replacing inside them.
Having learned of how Firefox Dom is handling text nodes differently, I read that I had to use javascript to loop through the elements, sibling to nextSibling.
The last obstacle I had in my script, of which you see a small portion of, is getting the classname. I need the class name so that I can filter down what content get's text replaced.
Having looked all the answers, and with the help of a co-worker named Ryan at work, we have redone this in jquery.
$(divid).find(".status_bar").each( function() {
var value = $.trim($(this).text());
// if value is not defined thru browser bugs do not replace
if (typeof(value) != 'undefined') {
// it is a text node. do magic.
for (var x = en_count; x > 0; x--) {
// get current english phrase
var from = en_lang[x];
// get current other language phrase
var to = other_lang[x];
if (value == from) {
console.log('Current Value ['+value+'] English ['+from+'] Translation ['+to+']');
value = to;
$(this).attr('value', to);
}
}
}
});
This currently works in all areas, except in the replacing of text.
The reason I had originally with doing this in jQuery, had to be not sure I could loop thru elements, and avoid the problem with firefox and text nodes.
I am doing a loop of all elements inside a div, and I now need to get the classname of the element that I am looping by.
Then i can check if the current element's class is one, I need to do something with...
// var children = parent.childNodes, child;
var parentNode = divid;
// start loop thru child nodes
for(var node=parentNode.firstChild;node!=null;node=node.nextSibling){
var myclass = (node.className ? node.className.baseVal : node.getAttribute('class'));
}
But this code for getting the classname only get's null values.
Any suggestions?
For those of you who are trying to figure out what the whole point is, read this JavaScript NextSibling Firefox Bug Fix I have code that does my language translation that works in Google Chrome and IE. But when I use it in Firefox, and try to translate div content after ajax has loaded it, it fails because of the whitespace issue.
I really don't have a preference of jQuery or Pure Javascript, I just want a working solution.
Thank you all for being patient. I personally thought I was extremely clear in my description, I apologize if it wasn't. I wasn't trying to be obscure or make it difficult to get help. But please don't insult me, by implying I am trying to make it unclear.
Thanks.
Hm... You have jQuery but don't use it?
$(divid).children(".yourSpecialClassName").each( function() {
doSomethingWith(this);
});
To get the CSS class attribute value, this will do:
$(divid).children().each( function() {
alert(this.className);
});
Based on the function you posted now, you want this:
$(divid).find(".status_bar").each( function() {
$(this).text( function(i, text) {
var x = $.inArray(en_lang, $.trim(text));
if (x > -1) {
console.log('Current Value ['+text+'] English ['+en_lang[x]+'] Translation ['+other_lang[x]+']');
return other_lang[x];
}
return text;
});
});
And please, don't ever use "do magic" as a comment again. This is incredibly lame.
EDIT. This can be made much more efficient (superfluous console.log() removed):
$(divid).find(".status_bar").each( function() {
// prepare dictionary en_lang => other_lang
var dict = {};
$.each(en_lang, function(x, word) { dict[word] = other_lang[x]; });
$(this).text( function(i, text) {
var t = $.trim(text);
return (t in dict) ? dict[t] : text;
});
});
if you are using jquery you can do this:
$("#myDiv").find("*").each(
function(){
var myclass = $(this).attr("class");
}
);
Your sample code doesn't make sense.
$(this).attr('value', to);
'value' is an attribute of the tag, not the text content.
Did you really mean to do this instead?
$(this).text(to);
Also, you've re-edited your question, but you're still trying to loop through the child nodes using non-jQuery methods. You said "The last obstacle I had in my script, of which you see a small portion of, is getting the classname. I need the class name so that I can filter down what content get's text replaced."
If you are using jQuery it is completely unnecessary to loop through anything to get a class name. You simply have to use a proper selector in the first place.
$(divid).find(".status_bar.replaceme").each( function() {
// .replaceme is whatever class you're using for the stuff you want to change
// .status_bar.replaceme matches all elements with BOTH status_bar and replaceme classes
var value = $.trim($(this).text());
// if value is not defined thru browser bugs do not replace
if (typeof(value) != 'undefined') {
// it is a text node. do magic.
// NOTE: The following is inefficient but I won't fix it.
// You're better off using an associative array
for (var x = en_count; x > 0; x--) {
// get current english phrase
var from = en_lang[x];
// get current other language phrase
var to = other_lang[x];
if (value == from) {
console.log('Current Value ['+value+'] English ['+from+'] Translation ['+to+']');
// value = to; <-- useless, get rid of it.
$(this).text(to);
// or $(this).html(to);
}
}
}
});

Categories