2

Background

As per the WHATWG someForm.elements should return a HTMLFormElementsCollection.

A HTMLFormElementsCollection returns a RadioNodeList if multiple elements share the same name.

The RadioNodeList has special value semantics where it returns the value of the first checked radio list in the nodelist.

This would allow the following answer to work if it were implemented

I naively attempted a polyfill that is based on host objects being well behaved (as per WebIDL), which they are clearly not.

Question

What is an alternative efficient implementation for this polyfill whilst we wait for browsers to become either RadioNodeList or WebIDL compliant?

Example Reference code

<form name="myform">
    <input type="radio" name="foo" value="10" /> foo 
    <input type="radio" name="foo" value="30" /> bar 
</form>

var myform = document.forms.myform;

var radio = myform.elements.foo;
var price = radio.value;

Naive attempt reference code

(function () {
    var pd = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, "elements"),
        getElements = pd.get;

    pd.get = get;

    Object.defineProperty(HTMLFormElement.prototype, "elements", pd);

    function get() {
        var elements = getElements.call(this);

        if (elements.length) {
            Object.defineProperty(elements, "value", {
                get: getRadioNodeListValue,
                set: setRadioNodeListValue,
                configurable: true
            });
        }

        return elements;
    }

    function getRadioNodeListValue() {
        for (var i = 0, len = this.length; i < len; i++) {
            var el = this[i];
            if (el.checked) {
                return el.value;   
            }
        }
    }

    function setRadioNodeListValue(value) {
        for (var i = 0, len = this.length; i < len; i++) {
            var el = this[i];
            if (el.checked) {
                el.value = value;
                return;   
            }
        }    
    }
}());
Community
  • 1
  • 1
Raynos
  • 166,823
  • 56
  • 351
  • 396

2 Answers2

4

Why? You know that requiring ES5 and WebIDL will fail in common-use browsers on the web today. Your code requires new features, both in ES5 )Object.getOwnPropertyDescriptor, get/set), and as you mentioned WebIDL interface objects being well-behaved.

The HTML5 polyfill aims at generalization and generally fails at implementation. It is a harmful trend.

Don't modify other objects. Especially host objects.
If there is any variance from the HTML5 definition (and there is) there will be problems when a second feature-testing script tries to detect if there is a value property on a group of radios, and then assumes standard support.It's way off from the 2-step algorithm in HTML5.

Your code polyfills only if elements.length > 0 and affects checkboxes, too (keep in mind that radios aren't the only element with a checked property). Your setter changes the value of the first checked radio. Shouldn't setting the value check the first unchecked radio of that name, having that value?

Instead, write functions that are only as general as you need them to be.

function getRadioValue(form, radioName) {
  // Delete comment, write code.
}

function setRadioValue(form, radioName, value) {
  // Delete comment, write code.
}
Garrett
  • 2,936
  • 1
  • 20
  • 22
  • That is the superior approach. However it's ugly to write utility functions which mirror features of the HTML spec. The fact that the naive implementation of the polyfill is bugged is an aside. – Raynos Sep 12 '12 at 17:35
  • you also claim to be based in SF and have a ton of knowledge about web scripting. I would love to have some coffee / lunch ! – Raynos Sep 12 '12 at 17:36
  • Sure, I'm no fan of utils objects but it's really about the best option here. For a forms-heavy app, it can make sense to group those functions on `FormUtils` object for such things (also setting the value of `SELECT` and checkbox inputs). Hold off on writing any code that uses `RadioNodeList` in any way until it is at least testable in at least some browsers. – Garrett Sep 13 '12 at 23:18
  • your right. I should implement functions for this `getValue(RadioList(form, radioName))`. – Raynos Jan 14 '13 at 22:33
  • I guess the situation is different now in 2015. In the projects we do we can safely assume ES5. [Thanks for the polyfill @Raynos](http://stackoverflow.com/a/8942643/2816199). – tomekwi Apr 28 '15 at 09:16
4

If you can accept bolting the value getter onto NodeList then the following should work

RadioNodeList polyfill

Credit to @@Esailija

you could also just add .value to NodeList prototype

Raynos
  • 166,823
  • 56
  • 351
  • 396