Error adding options to a select menu with javascript - javascript

I was having two problems: the first is that javascript is not adding options to a menu, and the second was an "Unexpected or invalid token" error at the end of my for loop.
Update:
The token error was a weird character thing. I deleted the line that was causing the problem and retyped it and now I am not getting the error anymore, but my script still is not adding options.
I have read about adding options to a select menu but the answers I've found there haven't worked for me. I should point out that this is part of a Joomla website (v3.8), because that can cause some unexpected behaviour.
I have a function which is supposed to pick out a particular select menu based on the string "id", clear its contents, and re-populate it with the elements of the "options" array.
function resetSelectMenu(id, options){
// Selects the correct menu, enables it, and removes all of its options.
var selectMenu = jQuery('#sel-' + id);
selectMenu.prop('disabled', false);
selectMenu.empty();
// Makes an option element and sets its text and value.
var el = document.createElement("option");
el.text = 'blah';
el.value = 'blah';
// Does not succeed in adding an option to menu.
selectMenu.add(el);
// I declared loop variables here to make sure there are no re-declaration issues.
var i;
var opt;
// The loop is entered and the array is iterated through.
for(i = 0; i < options.length; i++){
opt = options[i];
el = document.createElement("option");
el.text = opt;
el.value = i + 1;
// Does not succeed in adding an option to menu.
selectMenu.add(el);
}​
}
The function does target the correct menu and clear its contents, but it is not adding the "blah" option or anything from the "options" array. I've tried using "appendChild(el)" instead of add but I get an error of the form "appendChild() is not a function". I did a lot of console logs to determine that all the parts of the code are working as expected except for "selectMenu.add(el);"

So this was just a noob mistake. I looked a bit harder and found this related question, and the top answer by Matt told me I needed to use append(el) instead of add(el). I looked into the documentation and the add method just affects the jQuery object but doesn't actually affect the DOM at all, whereas append does. If I were to use add I would need to explicitly tell the jQuery object to refresh the DOM.
It's also possible that there is still an issue with me using selectMenu.empty() instead of something like selectMenu.find('option').remove(), but at the moment it's not causing any errors. Since my select element only contains option elements I feel like these two commands would be the same, but on the other hand maybe the latter is better because it allows for the addition of different kinds of elements later.

Related

Select2 v4 .val() does not maintain order of elements in data object

I have a select2 (v4) select box where people are choosing codes, and the order must be maintained. This works great when they originally add the elements:
However, this is a popup that is used for many different elements on the page. That means I must clear this array and load it with stored data objects on the fly.
My data object preserves the order as var codeArray = ['7990', '268'].
But when I use:
$(element).val(codeArray).trigger("change")
I get the following:
How can I maintain the order on load? Is there a sneaky workaround?
Okay, the fix was pretty hacky, but I'll post what I have:
function rebuildForm(codeArray) {
clearFormContents();
$.each(codeArray, function(j,obj){
var found = false;
code_list.some(function(el){
if (el.value == obj) {
var str = (el.text).split(")");
$("element option[value=" + el.value + "]").remove();
$(element).append(new Option("(" + el.value + ")" + str[1] , obj));
found = true;
}
})
if (!found) {
$(element).append(new Option("(" + obj + ") Custom Tag" , obj));
}
$(element).val(codeArray).trigger("change");
}
Sorry if the above code doesn't work perfectly, I had to clean it up to remove some fluff and hide the client/project identity.
Basically, on the rebuild of the form, I clear the old form contents then loop through the array grabbing each value/object. Then, if the value exists in the original code list of options in the select2 element I delete the option and rebuild it. This appends it to the bottom of the element list so that the order is maintained in the box. I also add any free form text tags using the 'found' boolean.
Once the new list of options are created in the "correct" order, then I am able to add the values back into the select input DOM element and trigger the select2 change to build the tags.
This thread posted by #RohitS in the comments showed the concept: https://github.com/select2/select2/issues/3106
I just adapted it to my needs.

adding .value stops flow of javascript

I'm in the middle of creating a program in the browser which compares the selections of the user with a list of pre-defined holidays using Objects. I tried to create an object from the selections of the user to use in comparisons and select the most matching holiday, however when I try to select the value (adding .value) it seems to break the flow of Java, and none of the code read afterwards is read.
var climateVar = document.getElementById('climateselect')/.value\;
var accVar = document.getElementById('accomadationselect')/.value\;
var durationVar = document.getElementById('duration')/.value\;
var userInput = new Input(climateVar/.value\, accVar/.value\, durationVar/.value\);
for (var key in userInput) {
var woo = userInput[key];
document.getElementById('someDiv').innerHTML += woo/.value\;
}
without any .value/s, this prints[object HTMLSelectElement]null[object HTMLSelectElement] - (I changed "getElementById" to "querySelector" which simply made it print "nullnullnull")
, but when I try to add .value anywhere, the entire script stops working, and so everything under this will not run. Why on earth would adding .value stop the script from working? Nothing else changed.
Also, I'm a novice at this, this was meant to be a practice project, but I've been stuck on this for about a day now. any other advice you might feel like giving would also be appreciated
everywhere I typed /.value\ I've tried to add .value, and it has had the effect of stopping the code
Are you sure you are calling value on a valid object? The object has to exist and support .value to get a result - e.g.
http://jsfiddle.net/pherris/t57ktnLk/
HTML
<input type="text" id="textInput" value="123"/>
<div id="divHoldingInfo">123</div>
JavaScript
alert(document.getElementById('textInput').value);
alert(document.getElementById('divHoldingInfo').innerHTML);
alert(document.getElementById('iDontExist').value); //errors out

Adding <optgroup> dynamically from javascript array

This may seem a cack-handed way of doing things, but I'm experimenting with this.
I have a list of UK counties, and a list of US states. When the user selects "UK" or "US" from the dropdown, it repopulates the second select list. (I DID get this to work by submitting the form each time the select options were changed, and rebuilding the HTML form ... but realised that was a somewhat server intensive mode, so now want to do it via Javascript)
I began by reading the text file into a javascript array, (actually, a PERL script reads the file, turns it into code, and then prints out the HTML) So I end up with:
var state_opt = new Array('1','2','3','4',' ...
var state_title = new Array('Alabama','Alaska','Arizona','Arkansas' ...
I then use a loop to load the second array:
for (x=0; x<state_opt.length; x++){
document.userChoice.c_s.options[x]=new Option(state_title[x],state_opt[x])
}
That works fine ... until I try the second array which features <optgroup></optgroup> The above loop automatically makes them into options!! Here are the arrays:
var county_opt = new Array('-','2','3','4', ...
var county_title = new Array('<optgroup label="England">','Bedfordshire','Berkshire','Bristol' ...
** Notice I have made the <optgroup> value into "-" so it can be distinguished. (When writing in PERL, this is the concept I used:
If ($county_opt[$x] eq "-"){
$option.=$county_title[$x];
}
else{
$option.="<option value=\"$county_opt[$x]\">$country_title[$x]";
}
And then write "<select>$option</select>
So what I'm seeking is code something like this:
for (x=0; x<county_opt.length; x++){
var str=county_title[x];
if (str.match(/optgroup/g)){
// ?? document.userChoice.c_s.options[x]=county_title[x];
// ie print the value as is without making it into an option
}
else{
document.userChoice.c_s.options[x]=new Option(county_title[x],county_opt[x])
}
}
Any SIMPLE ideas? If it can't be done, I'll just have to remove the labels
Hmmm ... that was a 'challenging' morning! The solution might be technically wrong in parts ... but it works.
I found a way to add the tags without making them into selectable options, but because they were not options, when changing to another option list, I could not remove these <optgroup> tags by using a loop that removed option elements!! (Does that make sense?)
Instead, the crude way I ended up doing it was to use innerHTML to set the text within the <select> form option to null. I then (incorrectly?) created a string built up with ≤optgroup><option> tags and values, and used innerHTML to replace it again
The "ind2" other option is the (correct) way to replace all option fields.
Hope this helps someone.
Incidentally, you'll also notice the "Not Available" have values of "-". Quite simply, if the user selects this option, an error trap routine sees these values, and simply returns to the form with a false value.
function checkCountry(){
document.userChoice.c_s.innerHTML=''
var ind=document.userChoice.countryChoice.selectedIndex;
// set 1 for UK, 2 for US
//'Please select a Country' has an option value of '0'
if (ind == 0){ // resets 2nd / 3rd option list if don't select US or UK
document.userChoice.c_s.options[0]=new Option("NOT AVAILABLE","-");
document.userChoice.service.options[0]=new Option("NOT AVAILABLE","-");
}
if (ind == 1){
var t='<option value="-">Please select a County</option>';
for (x=0; x<county_opt.length; x++){
var str=county_opt[x];
if (str.match(/-/)){
t+=county_title[x]; // Sets the <optgroup> tag with no option value
}
else{
t+='<option value="'+county_opt[x]+'">'+county_title[x];
}
}
document.userChoice.c_s.innerHTML=t;
}
if (ind == 2){ // preferred method that won't remove <optgroup> from <select> area
document.userChoice.c_s.options[0]=new Option('Please select a State','-');
for (x=1; x<state_opt.length; x++){
document.userChoice.c_s.options[x]=new Option(state_title[x],state_opt[x])
}
}
}
</script>

innerHTML to return a filtered syntax name of all the class with one name

im using this code to return the attrb name of the class tooltip (have more than one class in all the page)
CODE:
var hrefs = document.getElementsByClassName('tooltip_sticky');
for (var i = 0; i < hrefs.length; ++i) {
var item = hrefs[i].innerHTML;
}
alert(item);
HTML:
(http://i.stack.imgur.com/klS0N.png)
but it only return the <span.... of the last tooltip_sticky class, but i dont want this, i want to get the hrefs that have MISSION=1, i know its a matter of filter, but i cant first get the list of hrefs(i used another code that was getting the href outside the name="..", but the href inside, no...
im planning to get automatically all the hrefs that have mission=1 in the page, and open each one in another window automatically, its for a chrome extension!!
if someone can help me please, while this i will read about innerHTML getattribute
You are doing an alert() outside the loop so of course you only get the last one. In a statically scoped programming language, something like this wouldn't even compile because item is introduced inside the loop and used outside it.

getElementsByName in IE7

I have some code doing this :
var changes = document.getElementsByName(from);
for (var c=0; c<changes.length; c++) {
var ch = changes[c];
var current = new String(ch.innerHTML);
etc.
}
This works fine in FF and Chrome but not in IE7. Presumably because getElementsByName isn't working in IE. What's the best workaround?
In case you don't know why this isn't working in IE, here is the MSDN documentation on that function:
When you use the getElementsByName method, all elements in the document that have the specified NAME attribute or ID attribute value are returned.
Elements that support both the NAME attribute and the ID attribute are included in the collection returned by the getElementsByName method, but elements with a NAME expando are not included in the collection; therefore, this method cannot be used to retrieve custom tags by name.
Firefox allows getElementsByName() to retrieve elements that use a NAME expando, which is why it works. Whether or not that is a Good Thing™ may be up for debate, but that is the reality of it.
So, one option is to use the getAttribute() DOM method to ask for the NAME attribute and then test the value to see if it is what you want, and if so, add it to an array. This would require, however, that you iterate over all of the nodes in the page or at least within a subsection, which wouldn't be the most efficient. You could constrain that list beforehand by using something like getElementsByTagName() perhaps.
Another way to do this, if you are in control of the HTML of the page, is to give all of the elements of interest an Id that varies only by number, e.g.:
<div id="Change0">...</div>
<div id="Change1">...</div>
<div id="Change2">...</div>
<div id="Change3">...</div>
And then have JavaScript like this:
// assumes consecutive numbering, starting at 0
function getElementsByModifiedId(baseIdentifier) {
var allWantedElements = [];
var idMod = 0;
while(document.getElementById(baseIdentifier + idMod)) { // will stop when it can't find any more
allWantedElements.push(document.getElementById(baseIdentifier + idMod++));
}
return allWantedElements;
}
// call it like so:
var changes = getElementsByModifiedId("Change");
That is a hack, of course, but it would do the job you need and not be too inefficient compare to some other hacks.
If you are using a JavaScript framework/toolkit of some kind, you options are much better, but I don't have time to get into those specifics unless you indicate you are using one. Personally, I don't know how people live without one, they save so much time, effort and frustration that you can't afford not to use one.
There are a couple of problems:
IE is indeed confusing id="" with name=""
name="" isn't allowed on <span>
To fix, I suggest:
Change all the name="" to class=""
Change your code like this:
-
var changes = document.getElementById('text').getElementsByTagName('span');
for (var c=0; c<changes.length; c++) {
var ch = changes[c];
if (ch.className != from)
continue;
var current = new String(ch.innerHTML);
It's not very common to find elements using the NAME property. I would recommend switching to the ID property.
You can however find elements with a specific name using jQuery:
$("*[name='whatevernameYouWant']");
this will return all elements with the given name.
getElementsByName is supported in IE, but there are bugs. In particular it returns elements whose ‘id’ match the given value, as well as ‘name’. Can't tell if that's the problem you're having without a bit more context, code and actual error messages though.
In general, getElementsByName is probably best avoided, because the ‘name’ attribute in HTML has several overlapping purposes which can confuse. Using getElementById is much more reliable. When specifically working with form fields, you can more reliably use form.elements[name] to retrieve the fields you're looking for.
I've had success using a wrapper to return an array of the elements. Works in IE 6, and 7 too. Keep in mind it's not 100% the exact same thing as document.getElementsByName, since it's not a NodeList. But for what I need it for, which is to just run a for loop on an array of elements to do simple things like setting .disabled = true, it works well enough.
Even though this function still uses getElementsByName, it works if used this way. See for yourself.
function getElementsByNameWrapper(name) {
a = new Array();
for (var i = 0; i < document.getElementsByName(name).length; ++i) {
a.push(document.getElementsByName(name)[i]);
}
return a;
}
Workaround
var listOfElements = document.getElementsByName('aName'); // Replace aName with the name you're looking for
// IE hack, because it doesn't properly support getElementsByName
if (listOfElements.length == 0) { // If IE, which hasn't returned any elements
var listOfElements = [];
var spanList = document.getElementsByTagName('*'); // If all the elements are the same type of tag, enter it here (e.g.: SPAN)
for(var i = 0; i < spanList.length; i++) {
if(spanList[i].getAttribute('name') == 'aName') {
listOfElements.push(spanList[i]);
}
}
}
Just another DOM bug in IE:
Bug 1: Click here
Bug 2: Click here

Categories