netteForms.js a validace RadioListu
- chloris
- Člen | 23
Zdravím vás,
narazil jsem na zjevně chybné chování v netteForms.js spojené
s validací RadioListu.
Mám formulář, v něm mám RadioList ve kterém je pouze jedno radio.
Je to výběr z několika provedení produktů, kde někdy zkrátka může být
k dispozici pouze jedna varianta.
Mám na to navěšené validační pravidlo pro povinný výběr.
$form->addRadioList('provedeni', 'Provedení', $provedeniItems)->setDefaultValue($default)
->addRule(Form::FILLED, 'Zvolte si provedení produktu');
Pokud nechám validaci v javascriptu proběhnout a je tam více než 1 provedení (více než jeden radio button), tak vše zafunguje správně. Pokud ovšem je dostupný pouze jeden radio button, validace selže js chybou „Uncaught RangeError: Maximum call stack size exceeded“.
Celý zakopaný pes je v netteForms zde (viz komentáře v kódu):
Nette.getValue = function(elem) {
var i, len;
if (!elem) {
return null;
// TADY BY MĚLA PODMÍNKA VYHOVĚT A VRÁTIT HODNOTU RADIA ...
} else if (!elem.nodeName) { // radio
for (i = 0, len = elem.length; i < len; i++) {
if (elem[i].checked) {
return elem[i].value;
}
}
return null;
} else if (elem.nodeName.toLowerCase() === 'select') {
var index = elem.selectedIndex, options = elem.options;
if (index < 0) {
return null;
} else if (elem.type === 'select-one') {
return options[index].value;
}
for (i = 0, values = [], len = options.length; i < len; i++) {
if (options[i].selected) {
values.push(options[i].value);
}
}
return values;
} else if (elem.type === 'checkbox') {
return elem.checked;
} else if (elem.type === 'radio') {
// ... MÍSTO TOHO SPADNE AŽ SEM A VOLÁ SAMA SEBE REKURZIVNĚ POŘÁD DOKOLA
return Nette.getValue(elem.form.elements[elem.name]);
} else {
return elem.value.replace(/^\s+|\s+$/g, '');
}
};
Problém je v tom, že je-li tam pouze jedno radio, tak
elem.nodeName
je nastaveno.
- chloris
- Člen | 23
Navrhuji následující fix:
Nette.getValue = function(elem) {
var i, len;
if (!elem) {
return null;
} else if (!elem.nodeName) { // radio
for (i = 0, len = elem.length; i < len; i++) {
if (elem[i].checked) {
return elem[i].value;
}
}
return null;
} else if (elem.nodeName.toLowerCase() === 'select') {
var index = elem.selectedIndex, options = elem.options;
if (index < 0) {
return null;
} else if (elem.type === 'select-one') {
return options[index].value;
}
for (i = 0, values = [], len = options.length; i < len; i++) {
if (options[i].selected) {
values.push(options[i].value);
}
}
return values;
} else if (elem.type === 'checkbox') {
return elem.checked;
} else if (elem.type === 'radio') {
var radio = elem.form.elements[elem.name];
if(!radio.length) radio = [radio];
return Nette.getValue(radio);
} else {
return elem.value.replace(/^\s+|\s+$/g, '');
}
};