Skip to content

Commit

Permalink
Addresses issue #188:
Browse files Browse the repository at this point in the history
 - attributes are now reflected to property values at runtime, not only at create time. The rules are the same, the attribute is deserialized to the data type of the property in the element's prototype.
 - `published` properties are now reflected to attributes at runtime. This is done via observation and all published properties are now observed. Properties are serialized directly to strings and object and undefined valued
properties are ignored.
  • Loading branch information
sorvell committed Jul 24, 2013
1 parent f50c6f8 commit 318a260
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 3 deletions.
2 changes: 1 addition & 1 deletion polymer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ var modules = [
"api.js",
"instance/utils.js",
"instance/events.js",
"instance/properties.js",
"instance/attributes.js",
"instance/properties.js",
"instance/mdv.js",
"instance/base.js",
"instance/styles.js",
Expand Down
13 changes: 13 additions & 0 deletions src/instance/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@
// convert representation of 'stringValue' based on type of 'defaultValue'
deserializeValue: function(stringValue, defaultValue) {
return scope.deserializeValue(stringValue, defaultValue);
},
serializeValue: function(value) {
if (typeof value != 'object' && value !== undefined) {
return value;
}
},
propertyToAttribute: function(name) {
if (Object.keys(this[PUBLISHED]).indexOf(name) >= 0) {
var serializedValue = this.serializeValue(this[name]);
if (serializedValue !== undefined) {
this.setAttribute(name, serializedValue);
}
}
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/instance/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@
};
}
},
attributeChangedCallback: function() {
attributeChangedCallback: function(name, oldValue) {
this.attributeToProperty(name, this.getAttribute(name));
if (this.attributeChanged) {
this.attributeChanged.apply(this, arguments);
}
Expand Down
7 changes: 6 additions & 1 deletion src/instance/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// magic words

var OBSERVE_SUFFIX = 'Changed';

var PUBLISHED = scope.api.instance.attributes.PUBLISHED;

// element api

Expand Down Expand Up @@ -53,10 +55,13 @@
unregisterObservers(this);
},
// property should be observed if it has an observation callback
// or if it is published
shouldObserveProperty: function(name) {
return Boolean(this[name + OBSERVE_SUFFIX]);
return Boolean(this[name + OBSERVE_SUFFIX] ||
Object.keys(this[PUBLISHED]).indexOf(name) >= 0);
},
dispatchPropertyChange: function(name, oldValue) {
this.propertyToAttribute(name);
invoke.call(this, name + OBSERVE_SUFFIX, [oldValue]);
}
};
Expand Down
70 changes: 70 additions & 0 deletions test/html/prop-attr-reflection.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<!doctype html>
<html>
<head>
<title>publish attributes</title>
<script src="../../polymer.js"></script>
<script src="../../tools/test/htmltest.js"></script>
<script src="../../node_modules/chai/chai.js"></script>
</head>
<body>

<x-foo></x-foo>
<polymer-element name="x-foo" attributes="foo baz" noscript></polymer-element>

<x-bar></x-bar>
<polymer-element name="x-bar" extends="x-foo">
<script>
Polymer('x-bar', {
publish: {
zot: 3,
zim: false,
str: 'str',
obj: null
}
});
</script>
</polymer-element>

<script>
var assert = chai.assert;
document.addEventListener('WebComponentsReady', function() {
//
var xfoo = document.querySelector('x-foo');
xfoo.foo = 5;
Platform.flush();
assert.equal(String(xfoo.foo), xfoo.getAttribute('foo'), 'attribute reflects property as string');
xfoo.setAttribute('foo', '27');
assert.equal(xfoo.foo, xfoo.getAttribute('foo'), 'property reflects attribute');
//
xfoo.baz = 'Hello';
Platform.flush();
assert.equal(xfoo.baz, xfoo.getAttribute('baz'), 'attribute reflects property');
//
var xbar = document.querySelector('x-bar');
//
xbar.foo = 'foo!';
xbar.zot = 27;
xbar.zim = true;
xbar.str = 'str!';
xbar.obj = {hello: 'world'};
Platform.flush();
assert.equal(xbar.foo, xbar.getAttribute('foo'), 'inherited published property is reflected');
assert.equal(String(xbar.zot), xbar.getAttribute('zot'), 'attribute reflects property as number');
assert.equal(String(xbar.zim), xbar.getAttribute('zim'), 'attribute reflects property as boolean');
assert.equal(xbar.str, xbar.getAttribute('str'), 'attribute reflects property as published string');
assert.isFalse(xbar.hasAttribute('obj'), 'attribute does not reflect object property');
xbar.setAttribute('foo', 'foo!!');
xbar.setAttribute('zot', 54);
xbar.setAttribute('zim', 'false');
xbar.setAttribute('str', 'str!!');
xbar.setAttribute('obj', "{'hello': 'world'}");
assert.equal(xbar.foo, xbar.getAttribute('foo'), 'property reflects attribute as string');
assert.equal(xbar.zot, 54, 'property reflects attribute as number');
assert.equal(xbar.zim, false, 'property reflects attribute as boolean');
assert.equal(xbar.str, 'str!!', 'property reflects attribute as published string');
assert.deepEqual(xbar.obj, {hello: 'world'}, 'property reflects attribute as object');
done();
});
</script>
</body>
</html>
1 change: 1 addition & 0 deletions test/js/attrs.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ htmlSuite('attributes-declarative', function() {
htmlTest('html/publish-attributes.html');
htmlTest('html/take-attributes.html');
htmlTest('html/attr-mustache.html');
htmlTest('html/prop-attr-reflection.html');
});

0 comments on commit 318a260

Please sign in to comment.