#

# Example: Read-Only and Write-Once Attributes

Attributes can be configured to be `readOnly`, stopping them from being modified by the end user, or `writeOnce` allowing them to be set by the end user, but only once. This example demonstrates how to setup attributes for your class as `readOnly` or `writeOnce` attributes, and shows how their behavior differs when the end user attempts to set their values.

Construct o1, setting initial values for both foo and bar in the constructor:

foo: bar:

Try setting values again, after they've been set once:

foo: bar:

Call a MyClass method, which sets foo internally (using _set):

foo:

## ReadOnly And WriteOnce

Attribute supports the ability to configure attributes to be `readOnly` or `writeOnce`. `readOnly` attributes cannot be set by the end user, either through initial values passed to the constructor, or by invoking the `set` method. `writeOnce` attributes on the other hand, can be set by the user, but only once, either during initialization or through a call to `set`. Once a value is established for a `writeOnce` attribute, it cannot be reset to another value by the user.

## Configuring ReadOnly And WriteOnce Attributes

This example sets up a custom class, `MyClass`, with two attributes, `foo` and `bar`. `foo` is configured to be a `readOnly` attribute, and `bar` is configured to be a `writeOnce` attribute:

    // Setup a custom class with attribute support
    function MyClass(cfg) {

        // Attribute configuration
        var attrs = {
            "foo" : {
                value: "Default Foo",
                readOnly: true
            },

            "bar" : {
                value: "Default Bar",
                writeOnce: true
            }
        }

        this.addAttrs(attrs, cfg);
    }

## Attempting To Set Values

We first attempt to set values for both attributes in the constructor (used to intialize the attributes) and see that only `bar`, the `writeOnce` attribute, gets set to the user provided value:

    var fooVal = Y.one("#writeInitial .fooVal").get("value");
    var barVal = Y.one("#writeInitial .barVal").get("value");

    o1 = new MyClass({
        foo: fooVal,
        bar: barVal
    });

    displayValues(o1, "Attempt to set initial values in constructor",
                    "#writeInitial .example-out");

We then attempt to set values for both attributes again, using `set`, and see that niether of the values are modified:

    var fooVal = Y.one("#writeAgain .fooVal").get("value");
    var barVal = Y.one("#writeAgain .barVal").get("value");

    // Attempt to reset values:
    o1.set("foo", fooVal);
    o1.set("bar", barVal);

    displayValues(o1, "Attempt to set values again, using set",
                    "#writeAgain .example-out");

## Setting The State Of ReadOnly Values Internally

Although the user cannot update the value of `readOnly` attributes, it maybe neccessary for the host object to update it's value internally. The example shows how this can be done, using the private `_set` property on the host:

    MyClass.prototype.doSomething = function(val) {
        // ... Do something which requires
        // MyClass to change the value
        // of foo ...

        // Host code can reset value of
        // readOnly attributes interally,
        // by working with the private _set
        // property

        this._set("foo", val);
    };

    ...

    var val = Y.one("#writeInternally .fooVal").get("value");

    // Call method, which sets foo internally...
    o1.doSomething(val);

    displayValues(o1, "Set value of foo (readOnly) interally",
                    "#writeInternally .example-out");

## Complete Example Source

    <form id="writeInitial" action="#">
        <p>Construct o1, setting initial values for both foo and bar in the constructor: </p>
        <label>foo: <input type="text" value="Initial Foo" class="fooVal"></label>
        <label>bar: <input type="text" value="Initial Bar" class="barVal"></label>
        <button type="submit" class="do">Initial Values</button>
        <div class="example-out"></div>
    </form>
    <form id="writeAgain" action="#">
        <p>Try setting values again, after they've been set once: </p>
        <label>foo: <input type="text" value="Set Foo Again" class="fooVal"></label>
        <label>bar: <input type="text" value="Set Bar Again" class="barVal"></label>
        <button type="submit" class="do">Set Again</button>
        <div class="example-out"></div>
    </form>
    <form id="writeInternally" action="#">
        <p>Call a MyClass method, which sets foo internally (using _set): </p>
        <label>foo: <input type="text" value="Set Foo Internally" class="fooVal"></label>
        <button type="submit" class="do">Set Internal</button>
        <div class="example-out"></div>
    </form>

    <script type="text/javascript">
    YUI().use("node", "attribute", "escape", function(Y) {

        // Setup a custom class with attribute support
        function MyClass(cfg) {

            var attrs = {
                "foo" : {
                    value: "Default Foo",
                    readOnly: true
                },

                "bar" : {
                    value: "Default Bar",
                    writeOnce: true
                }
            }

            this.addAttrs(attrs, cfg);
        }

        MyClass.prototype.doSomething = function(val) {
            // ... Do something which requires
            // MyClass to change the value
            // of foo ...

            // Host code can reset value of
            // readOnly attributes interally,
            // by working with the private _set
            // property

            this._set("foo", val);
        };

        Y.augment(MyClass, Y.Attribute);

        function displayValues(o, title, node) {
            var str =
                '<div class="myclass"><div class="myclass-title">'
                + title +
                '</div><ul class="myclass-attrs"><li>foo (readOnly): '
                + Y.Escape.html(o.get("foo"))
                + '</li><li>bar (writeOnce): '
                + Y.Escape.html(o.get("bar"))
                + '</li></ul></div>';

            Y.one(node).set("innerHTML", str);
        }

        var o1;

        Y.on("submit", function(e) {

            e.preventDefault();

            var fooVal = Y.one("#writeInitial .fooVal").get("value");
            var barVal = Y.one("#writeInitial .barVal").get("value");

            o1 = new MyClass({
                foo: fooVal,
                bar: barVal
            });

            displayValues(o1, "Attempt to set initial values in constructor", "#writeInitial .example-out");

        }, "#writeInitial");

        Y.on("submit", function(e) {

            e.preventDefault();

            if (o1) {
                var fooVal = Y.one("#writeAgain .fooVal").get("value");
                var barVal = Y.one("#writeAgain .barVal").get("value");

                // Attempt to reset values:
                o1.set("foo", fooVal);
                o1.set("bar", barVal);

                displayValues(o1, "Attempt to set values again, using set", "#writeAgain .example-out");
            }

        }, "#writeAgain");

        Y.on("submit", function(e) {

            e.preventDefault();

            if (o1) {
                var val = Y.one("#writeInternally .fooVal").get("value");
                // Call method, which sets foo internally...
                o1.doSomething(val);

                displayValues(o1, "Set the value of foo (readOnly) internally", "#writeInternally .example-out");
            }

        }, "#writeInternally");
    });
    </script>