J
jezaustin
Hi guys,
I'm using the onchange event on a SELECT element to pull extra inputs
into a form based on the value in the SELECT. It works fine in both
firefox and explorer: user selects an option and relevant extra fields
appear / disappear immediately.
However, explorer has a feature that allows a user to scroll through
the options in a select field using the onmousewheel, and the onchange
function appears not to fire.
What's the simplest way around this? I've considered the following:
1) trap the onmousewheel event
a) update the fields there and then
b) repress the change in the SELECT on the mousewheel
2) alter the server side code to offer a second round of questioning
if there's a discrepancy between the selected options and the
dependent fields offered.
2) is definitely doable, but I feel is a degraded user experience.
I've attempted both 1a) and 1b) but I can't make either work.
With 1a) I do seem to be able to trigger the function on a mouse
scroll, but it doesn't do the actual DOM work. I don't know why, I
believe it should work, I'm not using "this" or the event object at
all. See below for code, am I doing something stupid?
With 1b) I've just had no luck at all. Returning false doesn't stop
the scroll wheel altering values in the SELECT. Anybody know how or if
you can do this? Or is there another solution to this that I haven't
thought of?
I'd be very grateful for any help or advice, general or specific.
Thanks,
Jez Austin.
Here's the function:
<pre>
function
select_traits(i)
{
// i is
integer
// usually called from "measure"+i
onchange
var elem =
document.getElementById("measure"+i);
// record array of selected
measures
var selected_measures =
[];
var
measureIndex;
for (var j=1; j<5; j+
+)
if (0 != (measureIndex
=
document.getElementById("measure"+j).selectedIndex))
// all measure selects have the same
options
selected_measures.push(elem.options[measureIndex].value);
// hide irrelevent traits
// that is, move them to a hidden div outside the
form
var traits = get_trait_fieldset(); // returns the fieldset
element, creates it if it doesn't yet
exist
var hidden_traits =
document.getElementById("traits_hidden");
var row_div =
traits.firstChild;
while (row_div)
{
if ("div" != row_div.nodeName.toLowerCase())
{
row_div =
row_div.nextSibling;
continue;
}
// Each of these spans has an attribute "measures",
// a comma separated list of the measures it is associated
with
var my_measures
=
row_div.getElementsByTagName("span")
[0].getAttribute("measures").split(",");
if (array_overlap(my_measures, selected_measures))
{
row_div =
row_div.nextSibling;
continue;
}
var next_div =
row_div.nextSibling;
hidden_traits.appendChild(row_div);
row_div =
next_div;
}
// reveal relevent
inputs
row_div =
hidden_traitts.firstChild;
while (row_div)
{
if ("div" != row_div.nodeName.toLowerCase())
{
row_div =
row_div.nextSibling;
continue;
}
var my_measures
=
row_div.getElementsByTagName("span")
[0].getAttribute("measures").split(",");
if (! array_overlap(my_measures, selected_measures))
{
row_div =
row_div.nextSibling;
continue;
}
var next_div =
row_div.nextSibling;
traits.appendChild(row_div);
row_div =
next_div;
}
if (0 ==
traits.getElementsByTagName('div').length)
traits.parentNode.removeChild(traits);
// test: is this called be wheel
code?
return 'called select_traits('+i+')';
// needn't / shouldn't return
anything
}
</pre>
and here's where I set the onchange events
<pre>
for (var i=1; i<5; i++)
{
var measure_select =
document.getElementById("measure"+i);
measure_select.onchange = measure_select.onleave = function(evt)
{
// alert("hello
world");
refuse_duplicates();
evt = (evt) ? evt : ( (event) ? event :
null );
if(evt)
{
var elem = (evt.target) ?
evt.target :
((evt.srcElement) ? evt.srcElement :
null);
if(elem)
{
elem = (elem.nodeType==1 || elem.nodeType==9) ? elem :
elem.parentNode;
select_traits(elem.id.substring(7));
}
}
};
}
select_traits(1);
</pre>
That last line pulls in the relevant traits when editing an existing
record, and proves that the function works in IE both when called
explicitly and when called by the event.
Here's how I attach it to the onmousewheel event
<pre>
var soc_id =
null;
function update_on_wheel_for_ie( code, delay )
{
delay = delay || 1000; // default
1s
window.clearTimeout( soc_id );
// appears as though the select_traits function isn't getting
purchase on the DOM elements when called this
way... ??
//
alert(select_traits(1));
soc_id = window.setTimeout( code,
delay );
}
document.onmousewheel = window.onmousewheel = function()
{
// alert("hello
world");
update_on_wheel_for_ie('refuse_duplicates(); select_traits(1);
select_traits(\
2); select_traits(3);
select_traits(4);');
//'document.getElementById("measure1").onchange();');
return
true;
};
</pre>
Sorry if this bit isn't very clear, I've just been trying out a few
things, thought I'd include it though.
I'm using the onchange event on a SELECT element to pull extra inputs
into a form based on the value in the SELECT. It works fine in both
firefox and explorer: user selects an option and relevant extra fields
appear / disappear immediately.
However, explorer has a feature that allows a user to scroll through
the options in a select field using the onmousewheel, and the onchange
function appears not to fire.
What's the simplest way around this? I've considered the following:
1) trap the onmousewheel event
a) update the fields there and then
b) repress the change in the SELECT on the mousewheel
2) alter the server side code to offer a second round of questioning
if there's a discrepancy between the selected options and the
dependent fields offered.
2) is definitely doable, but I feel is a degraded user experience.
I've attempted both 1a) and 1b) but I can't make either work.
With 1a) I do seem to be able to trigger the function on a mouse
scroll, but it doesn't do the actual DOM work. I don't know why, I
believe it should work, I'm not using "this" or the event object at
all. See below for code, am I doing something stupid?
With 1b) I've just had no luck at all. Returning false doesn't stop
the scroll wheel altering values in the SELECT. Anybody know how or if
you can do this? Or is there another solution to this that I haven't
thought of?
I'd be very grateful for any help or advice, general or specific.
Thanks,
Jez Austin.
Here's the function:
<pre>
function
select_traits(i)
{
// i is
integer
// usually called from "measure"+i
onchange
var elem =
document.getElementById("measure"+i);
// record array of selected
measures
var selected_measures =
[];
var
measureIndex;
for (var j=1; j<5; j+
+)
if (0 != (measureIndex
=
document.getElementById("measure"+j).selectedIndex))
// all measure selects have the same
options
selected_measures.push(elem.options[measureIndex].value);
// hide irrelevent traits
// that is, move them to a hidden div outside the
form
var traits = get_trait_fieldset(); // returns the fieldset
element, creates it if it doesn't yet
exist
var hidden_traits =
document.getElementById("traits_hidden");
var row_div =
traits.firstChild;
while (row_div)
{
if ("div" != row_div.nodeName.toLowerCase())
{
row_div =
row_div.nextSibling;
continue;
}
// Each of these spans has an attribute "measures",
// a comma separated list of the measures it is associated
with
var my_measures
=
row_div.getElementsByTagName("span")
[0].getAttribute("measures").split(",");
if (array_overlap(my_measures, selected_measures))
{
row_div =
row_div.nextSibling;
continue;
}
var next_div =
row_div.nextSibling;
hidden_traits.appendChild(row_div);
row_div =
next_div;
}
// reveal relevent
inputs
row_div =
hidden_traitts.firstChild;
while (row_div)
{
if ("div" != row_div.nodeName.toLowerCase())
{
row_div =
row_div.nextSibling;
continue;
}
var my_measures
=
row_div.getElementsByTagName("span")
[0].getAttribute("measures").split(",");
if (! array_overlap(my_measures, selected_measures))
{
row_div =
row_div.nextSibling;
continue;
}
var next_div =
row_div.nextSibling;
traits.appendChild(row_div);
row_div =
next_div;
}
if (0 ==
traits.getElementsByTagName('div').length)
traits.parentNode.removeChild(traits);
// test: is this called be wheel
code?
return 'called select_traits('+i+')';
// needn't / shouldn't return
anything
}
</pre>
and here's where I set the onchange events
<pre>
for (var i=1; i<5; i++)
{
var measure_select =
document.getElementById("measure"+i);
measure_select.onchange = measure_select.onleave = function(evt)
{
// alert("hello
world");
refuse_duplicates();
evt = (evt) ? evt : ( (event) ? event :
null );
if(evt)
{
var elem = (evt.target) ?
evt.target :
((evt.srcElement) ? evt.srcElement :
null);
if(elem)
{
elem = (elem.nodeType==1 || elem.nodeType==9) ? elem :
elem.parentNode;
select_traits(elem.id.substring(7));
}
}
};
}
select_traits(1);
</pre>
That last line pulls in the relevant traits when editing an existing
record, and proves that the function works in IE both when called
explicitly and when called by the event.
Here's how I attach it to the onmousewheel event
<pre>
var soc_id =
null;
function update_on_wheel_for_ie( code, delay )
{
delay = delay || 1000; // default
1s
window.clearTimeout( soc_id );
// appears as though the select_traits function isn't getting
purchase on the DOM elements when called this
way... ??
//
alert(select_traits(1));
soc_id = window.setTimeout( code,
delay );
}
document.onmousewheel = window.onmousewheel = function()
{
// alert("hello
world");
update_on_wheel_for_ie('refuse_duplicates(); select_traits(1);
select_traits(\
2); select_traits(3);
select_traits(4);');
//'document.getElementById("measure1").onchange();');
return
true;
};
</pre>
Sorry if this bit isn't very clear, I've just been trying out a few
things, thought I'd include it though.