Forum Moderators: open

Message Too Old, No Replies

javascript dynamic select windows.onload

         

Oldsoldier

11:47 am on Feb 15, 2014 (gmt 0)

10+ Year Member



Am trying to create a four Dynamic Dropdown Selects but it does not work in IE Browse.It refuses to fire.
It work in safari,mozilla and opera but not internet explorer

This my code unobtrusiveDSBoxes.js
function dynamicSelect(id1, id2) {
// Feature test to see if there is enough W3C DOM support
if (document.getElementById && document.getElementsByTagName) {
// Obtain references to both select boxes
var sel1 = document.getElementById(id1);
var sel2 = document.getElementById(id2);
// Clone the dynamic select box
var clone = sel2.cloneNode(true);
// Obtain references to all cloned options
var clonedOptions = clone.getElementsByTagName("option");
// Onload init: call a generic function to display the related options in the dynamic select box
refreshDynamicSelectOptions(sel1, sel2, clonedOptions);
// Onchange of the main select box: call a generic function to display the related options in the dynamic select box
sel1.onchange = function() {
refreshDynamicSelectOptions(sel1, sel2, clonedOptions);
};
}
}
function refreshDynamicSelectOptions(sel1, sel2, clonedOptions) {
// Delete all options of the dynamic select box
while (sel2.options.length) {
sel2.remove(0);
}
// Create regular expression objects for "select" and the value of the selected option of the main select box as class names
var pattern1 = /( |^)(select)( |$)/;
var pattern2 = new RegExp("( |^)(" + sel1.options[sel1.selectedIndex].value + ")( |$)");
// Iterate through all cloned options
for (var i = 0; i < clonedOptions.length; i++) {
// If the classname of a cloned option either equals "select" or equals the value of the selected option of the main select box
if (clonedOptions[i].className.match(pattern1) || clonedOptions[i].className.match(pattern2)) {
// Clone the option from the hidden option pool and append it to the dynamic select box
sel2.appendChild(clonedOptions[i].cloneNode(true));
}
}
}

index.html
<select id="select-1" name="firstChoice">
<option value="">[SELECT]</option>
<option value="Nursing">Nursing</option>
<option value="Allied Health">AlliedHealth</option>
</select>

<select id="select-2" name="secondChoice">
<option class="select" value="select">[SELECT]</option>
<option class="Nursing" value="Auxilary">Auxilary</option>
<option class="Nursing" value="Basic-Diploma">Basic(Diploma)</option>
<option class="Allied Health" value="Certificate">Certificate</option>
<option class="Allied Health" value="Diploma">Diploma</option>
</select>

<select id="select-3" name="thirdChoice">
<option class="select" value="select">[SELECT]</option>
<option class="Auxilary" value="Community-Health-Nursing">Community Health Nursing</option>
<option class="Auxilary" value="Health-Assistant-Clinical">Health Assistant Clinical</option>
</select>

<select id="select-4" name="fourthChoice" required="Yes" message="Please select your choice of School">
<option class="select" value="">[SELECT]</option>
<option class="Community-Health-Nursing" value="CHNTS-AKIM-ODA">CHNTS AKIM ODA</option>
<option class="Community-Health-Nursing" value="CHNTS-ESIAMA">CHNTS ESIAMA</option>
</select>

<script type="text/javascript" src="unobtrusiveDSBoxes.js"></script>
<script type="text/javascript">
window.onload = function() {
dynamicSelect("select-1", "select-2");
dynamicSelect("select-2", "select-3");
dynamicSelect("select-3", "select-4");
}
</script>

Fotiman

4:55 pm on Feb 15, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I tried it in IE8 and it seems to be doing the same thing as Chrome. What version of IE are you using?

Oldsoldier

5:28 pm on Feb 15, 2014 (gmt 0)

10+ Year Member



Am using version 11. Am worried because i might have to put it on a production server later and people might not able to use the drop down list
Pls is there anyway around this

Oldsoldier

6:25 pm on Feb 15, 2014 (gmt 0)

10+ Year Member



i was able to change the action code to this and it works but it can't link up the third and fourth select boxes


function DynamicSelect(id1, id2) {
// Get references
this.s1 = document.getElementById(id1);
this.s2 = document.getElementById(id2);

// Parse the dependent select box and create an object representation
var o = this.s2Obj = {};
o.id = id2;
o.options = [];
var oNodes = this.s2.getElementsByTagName("option"),
ol = oNodes.length;
for (var i = 0; i < ol; i++) {
var cNodes = oNodes[i].childNodes,
cl = cNodes.length,
txt;
for (var j = 0; j < cl; j++) {
if(cNodes[j].nodeType === 3) {
txt = cNodes[j].nodeValue;
break;
}
}
o.options.push({
dataParentVal: oNodes[i].getAttribute("data-parent-value"),
val: oNodes[i].getAttribute("value"),
label: txt
});
}
//console.dir(this.s2Obj);

//Add handlers and init
var _this = this;
this.s1.onchange = function() {
_this.update();
};
this.update();
}
DynamicSelect.prototype.update = function() {
// Recreate the select box from the object
var s2New = document.createElement("select");
s2New.setAttribute("id", this.s2Obj.id);
var options = this.s2Obj.options,
ol = options.length;
for (var i = 0; i < ol; i++) {
// Only add the relevant options
if (options[i].dataParentVal === "0" || options[i].dataParentVal === this.s1.options[this.s1.selectedIndex].value) {
var oNode = document.createElement("option");
oNode.setAttribute("data-parent-value", options[i].dataParentVal);
oNode.setAttribute("value", options[i].val);
var txtNode = document.createTextNode(options[i].label);
oNode.appendChild(txtNode);
s2New.appendChild(oNode);
}
}

// Swap out old and new select elements
var s2 = document.getElementById(this.s2Obj.id);
s2.parentNode.replaceChild(s2New, s2);
};
window.onload = function() {
var pdaDynamicSelect = new DynamicSelect("select-1", "select-2");
var pda2DynamicSelect = new DynamicSelect("select-2", "select-3");
var pda3DynamicSelect = new DynamicSelect("select-3", "select-4");
};
</script>


<form id="aggregateform" enctype="multipart/form-data" preservedata="yes">
<p>
<select name="firstChoice" id="select-1">
<option value="0">Select PDA brand...</option>
<option value="dell">Dell</option>
<option value="hp">HP</option>
<option value="palmone">PalmOne</option>
</select>
<select name="secondChoice" id="select-2">
<option data-parent-value="0" value="0">Select PDA type...</option>
<option data-parent-value="dell" value="aximx30">Axim X30</option>
<option data-parent-value="dell" value="aximx50">Axim X50</option>
<option data-parent-value="hp" value="ipaqhx2750">iPAQ hx2750</option>
<option data-parent-value="hp" value="ipaqrx3715">iPAQ rx3715</option>
<option data-parent-value="hp" value="ipaqrz1710">iPAQ rz1710</option>
<option data-parent-value="palmone" value="tungstene2">Tungsten E2</option>
<option data-parent-value="palmone" value="tungstent5">Tungsten T5</option>
<option data-parent-value="palmone" value="zire72">Zire 72</option>
</cfselect>
<select name="thirdChoice" id="select-3">
<option data-parent-value="0" value="0">Select PDA type...</option>
<option data-parent-value="aximx30" value="big">Axim X30</option>
<option data-parent-value="aximx30" value="small">Axim X50</option>
<option data-parent-value="ipaqhx2750" value="large">iPAQ hx2750</option>
<option data-parent-value="ipaqhx2750" value="thin">iPAQ rx3715</option>
<option data-parent-value="ipaqhx2750" value="thick">iPAQ rz1710</option>
<option data-parent-value="tungstene" value="curvy">Tungsten E2</option>
<option data-parent-value="tungstenee" value="slender">Tungsten T5</option>
<option data-parent-value="zire72" value="skinny">Zire 72</option>
</select>
<select name="fourthChoice" id="select-4">
<option data-parent-value="0" value="0">Select PDA type...</option>
<option data-parent-value="big" value="aximx30">Axim X30</option>
<option data-parent-value="small" value="aximx50">Axim X50</option>
<option data-parent-value="large" value="ipaqhx2750">iPAQ hx2750</option>
<option data-parent-value="thin" value="ipaqrx3715">iPAQ rx3715</option>
<option data-parent-value="thick" value="ipaqrz1710">iPAQ rz1710</option>
<option data-parent-value="curvy" value="tungstene2">Tungsten E2</option>
<option data-parent-value="slender" value="tungstent5">Tungsten T5</option>
<option data-parent-value="skinny" value="zire72">Zire 72</option>
</select>
</form>

Fotiman

7:17 pm on Feb 15, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Here's your previous script, formatted for easier viewing:


function DynamicSelect(id1, id2) {
// Get references
this.s1 = document.getElementById(id1);
this.s2 = document.getElementById(id2);

// Parse the dependent select box and create an object representation
var o = this.s2Obj = {};
o.id = id2;
o.options = [];
var oNodes = this.s2.getElementsByTagName("option"),
ol = oNodes.length;
for (var i = 0; i < ol; i++) {
var cNodes = oNodes[i].childNodes,
cl = cNodes.length,
txt;
for (var j = 0; j < cl; j++) {
if (cNodes[j].nodeType === 3) {
txt = cNodes[j].nodeValue;
break;
}
}
o.options.push({
dataParentVal: oNodes[i].getAttribute("data-parent-value"),
val: oNodes[i].getAttribute("value"),
label: txt
});
}
//console.dir(this.s2Obj);

//Add handlers and init
var _this = this;
this.s1.onchange = function () {
_this.update();
};
this.update();
}
DynamicSelect.prototype.update = function () {
// Recreate the select box from the object
var s2New = document.createElement("select");
s2New.setAttribute("id", this.s2Obj.id);
var options = this.s2Obj.options,
ol = options.length;
for (var i = 0; i < ol; i++) {
// Only add the relevant options
if (options[i].dataParentVal === "0" || options[i].dataParentVal === this.s1.options[this.s1.selectedIndex].value) {
var oNode = document.createElement("option");
oNode.setAttribute("data-parent-value", options[i].dataParentVal);
oNode.setAttribute("value", options[i].val);
var txtNode = document.createTextNode(options[i].label);
oNode.appendChild(txtNode);
s2New.appendChild(oNode);
}
}

// Swap out old and new select elements
var s2 = document.getElementById(this.s2Obj.id);
s2.parentNode.replaceChild(s2New, s2);
};
window.onload = function () {
var pdaDynamicSelect = new DynamicSelect("select-1", "select-2");
var pda2DynamicSelect = new DynamicSelect("select-2", "select-3");
var pda3DynamicSelect = new DynamicSelect("select-3", "select-4");
};


My initial thought is that your method of getting the text nodes is risky. That is, I think some versions of IE allow multiple text node children (though this might only have been in old versions of IE). I think it'd be more reliable to get the "text" property of the HTMLOptionElement.

Note, when I run the example above I get an error:
Uncaught TypeError: Cannot call method 'getElementsByTagName' of null

On this line:
var oNodes = this.s2.getElementsByTagName("option"),

Oldsoldier

8:34 pm on Feb 15, 2014 (gmt 0)

10+ Year Member



Please can you help me with that.Am new to this and what i know is to getElementByTagName but it seems not to work

Fotiman

8:42 pm on Feb 15, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Here's how I'd approach it:

function DynamicSelect(id1, id2) {
var s1 = document.getElementById(id1),
s2 = document.getElementById(id2),
i,
o,
ol,
p,
omap = {},
_this = this;

this.s1 = s1;
this.s2 = s2;

// iterate through s2's options to create a map of data-parent-value -> values
ol = s2.options.length;
for (i = 0; i < ol; i++) {
o = s2.options[i];
p = o.getAttribute("data-parent-value");
if (omap[p] == null) {
omap[p] = [];
}
omap[p][omap[p].length] = o;
}
this.omap = omap;

this.s1.onchange = function () {
_this.update();
};
}

DynamicSelect.prototype.update = function () {
var i,
ol = this.s2.length,
p = this.s1.options[this.s1.selectedIndex].value;

// Remove all options
for (i = ol; i > 0; i--) {
this.s2.remove(i - 1);
}

// Add back only the ones that apply
// Always include the option with parent-value="0"
this.s2.add(this.omap["0"][0]);
for (i = 0; i < this.omap[p].length; i++) {
this.s2.add(this.omap[p][i]);
}
};

window.onload = function () {
var pdaDynamicSelect = new DynamicSelect("select-1", "select-2");
var pda2DynamicSelect = new DynamicSelect("select-2", "select-3");
var pda3DynamicSelect = new DynamicSelect("select-3", "select-4");
pdaDynamicSelect.update();
pda2DynamicSelect.update();
pda3DynamicSelect.update();
};

Note, I moved the update() call out of the constructor, since calling update removes options, and subsequent DynamicSelect objects will need those options.

Also, still not handled is how to update the later DynamicSelect elements when one of the earlier ones is changed (since changing the input elements programatically doesn't trigger the onchange event).

Oldsoldier

8:56 pm on Feb 15, 2014 (gmt 0)

10+ Year Member



I place an onchange attribute in the select option and it fired up
Thank you

<select name="secondChoice" id="select-2" onChange="firstChoice">
<option data-parent-value="0" value="0">Select PDA type...</option>
<option data-parent-value="dell" value="aximx30">Axim X30</option>
<option data-parent-value="dell" value="aximx50">Axim X50</option>
<option data-parent-value="hp" value="ipaqhx2750">iPAQ hx2750</option>
<option data-parent-value="hp" value="ipaqrx3715">iPAQ rx3715</option>
<option data-parent-value="hp" value="ipaqrz1710">iPAQ rz1710</option>
<option data-parent-value="palmone" value="tungstene2">Tungsten E2</option>
<option data-parent-value="palmone" value="tungstent5">Tungsten T5</option>
<option data-parent-value="palmone" value="zire72">Zire 72</option>
</select>

Fotiman

9:00 pm on Feb 15, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Minor update. I think this might handle updating the related DynamicSelect's.

function DynamicSelect(id1, id2) {
var s1 = document.getElementById(id1),
s2 = document.getElementById(id2),
i,
o,
ol,
p,
omap = {},
_this = this;


this.s1 = s1;
this.s2 = s2;
this.related = [];

// iterate through s2's options to create a hash map of data-parent-value -> value
ol = s2.options.length;
for (i = 0; i < ol; i++) {
o = s2.options[i];
p = o.getAttribute("data-parent-value");
if (omap[p] == null) {
omap[p] = [];
}
omap[p][omap[p].length] = o;
}

this.omap = omap;
this.s1.onchange = function () {
_this.update();
};

//this.update();
}
DynamicSelect.prototype.relate = function (dynamicSelect) {
this.related[this.related.length] = dynamicSelect;
}

DynamicSelect.prototype.update = function () {
var i,
ol = this.s2.length,
p = this.s1.options[this.s1.selectedIndex].value;

// Remove all options
for (i = ol; i > 0; i--) {
this.s2.remove(i - 1);
}

// Add back only the ones that apply
// Always include the option with parent-value="0"
this.s2.add(this.omap["0"][0]);
if (this.omap[p]) {
for (i = 0; i < this.omap[p].length; i++) {
this.s2.add(this.omap[p][i]);
}
}

for (i = 0; i < this.related.length; i++) {
this.related[i].update();
}
};

window.onload = function () {
var pdaDynamicSelect = new DynamicSelect("select-1", "select-2");
var pda2DynamicSelect = new DynamicSelect("select-2", "select-3");
var pda3DynamicSelect = new DynamicSelect("select-3", "select-4");
pdaDynamicSelect.relate(pda2DynamicSelect);
pda2DynamicSelect.relate(pda3DynamicSelect);
pdaDynamicSelect.update();
};

Also added a minor bug fix to the update method. Note, your HTML has some items with no matching parent (looks like minor typos). For example, in select-2:
<option data-parent-value="palmone" value="tungstene2">Tungsten E2</option>
<option data-parent-value="palmone" value="tungstent5">Tungsten T5</option>
<option data-parent-value="palmone" value="zire72">Zire 72</option>

And in select-3:
<option data-parent-value="tungstene" value="curvy">Tungsten E2</option>
<option data-parent-value="tungstenee" value="slender">Tungsten T5</option>
<option data-parent-value="zire72" value="skinny">Zire 72</option>

Fotiman

9:02 pm on Feb 15, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I place an onchange attribute in the select option and it fired up

No, don't do that. You already have an onchange handler assigned in the JavaScript code. What I was saying was that if you updated list 1, list 2 would update, but 3 and 4 would not. The post preceding this one has a method for handling that.