Es6 Objects And Polymer Web Components
ES6 brings a lot of new functionality to objects. You can get a nice walk-through on Bjorn Tipling’s site.
The basic object, created with no prototype, causes problems for Polymer.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( null, {
foo: {
value: 'bar'
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello -->
So, we need at least the basic Object prototype.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
foo: {
value: 'bar'
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello bar -->
But adding additional properties to the prototype won’t transfer to the web component.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo + bar }}
</template>
<script>
(function () {
var config = Object.create( {
foo: 'bar'
}, {
bar: {
value: 'baz'
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello undefinedbaz -->
So that leaves configurable
, writable
, enumerable
,
the Object methods: freeze
, seal
, and preventExtensions
,
and getters and setters.
writable
seems to be the most generally helpful option. Since Polymer’s
web components keep references to objects in their registration, this
technique could help prevent certain properties from changing.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
foo: {
value: 'bar',
//change to true to see 'Hello baz'
writable: false
},
ready: {
value: function () {
this.foo = 'baz';
}
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello bar -->
In Polymer, properties don’t delete and configurable
can’t change that.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
foo: {
value: 'bar',
writable: true,
configurable: true
},
ready: {
value: function () {
var self = this;
//this won't do anything
setTimeout( function () {
delete self.foo;
}, 100 );
}
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello bar -->
The most pressing use for enumerable
seems to be the use of
mixins,
which allow for some extending of common objects. Marking something as
non-enumerable means it won’t get mixed-in.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
foo: {
value: 'bar',
//change to true to see 'Hello bar'
enumerable: false
}
} );
Polymer( 'es6-object', Platform.mixin( {}, config ) );
}());
</script>
</polymer-element>
<!-- Hello -->
Object.preventExtensions
works and could be a great help in preventing
unwanted additions to an element’s model.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
ready: {
value: function () {
//comment this out to see 'Hello bar'
Object.preventExtensions( this );
this.foo = 'bar';
}
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- Hello -->
Object.freeze
and Object.seal
throw a Uncaught NoModificationAllowedError
. This
probably has something to do with the way properties get copied, not unlike why delete
fails with generic objects.
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="es6-object" attributes="name">
<template>
Hello {{foo }}
</template>
<script>
(function () {
var config = Object.create( {}, {
foo: {
value: 'bar',
writable: true
},
ready: {
value: function () {
Object.freeze( this );
this.foo = 'baz';
}
}
} );
Polymer( 'es6-object', config );
}());
</script>
</polymer-element>
<!-- [Error] -->
Getters and setters sort of work. In the example below, you see the
right fullName
but if you change either name using the input field,
the echo message won’t update even though the first and last names updated
on the model. However, if you uncomment the lines where we bind to first
and last name, it works as expected.
This means that using a setter circumvents Polymer’s observance of the model change and, as a result, you probably want to avoid setters for now.
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../paper-input/paper-input.html">
<polymer-element name="es6-object" attributes="firstName lastName">
<template>
<paper-input value="{{ fullName }}"></paper-input>
<div>Hello {{ fullName }}</div>
<!--<div>Firstname: {{ firstName }}</div>-->
<!--<div>Lastname: {{ lastName }}</div>-->
</template>
<script>
(function () {
var person = {
firstName: 'Jimmy',
lastName: 'Smith',
};
Object.defineProperty( person, 'fullName', {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function( name ) {
var words = name.split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
} );
Polymer( 'es6-object', person );
}());
</script>
</polymer-element>