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.
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.
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); }
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");
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");
<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>