I noticed that template/data-binding in Polymer doesn't seem to reflect when a array property is mutated (i.e. push()). Sample code below:
<body>
<dom-module id="my-element">
<template>
<pre>
[my-element]
myArray: [[jsonStringify(myArray)]]
</pre>
</template>
</dom-module>
<my-element id="elm"></my-element>
<button onclick="pushArray()">pushArray</button>
<button onclick="setArray()">setArray</button>
<script>
(function registerElements() {
Polymer({
is: 'my-element',
properties: {
myArray: {
type: Array,
value: function () {
return [];
}
}
},
pushArray: function(value) {
this.push('myArray', {id: value});
},
setArray: function(value) {
this.set('myArray', [{id: value}]);
},
jsonStringify: function(obj) {
return JSON.stringify(obj);
}
});
})();
function pushArray () {
var elm = document.querySelector('#elm');
elm.pushArray('Push');
}
function setArray () {
var elm = document.querySelector('#elm');
elm.setArray('Set');
}
</script>
</body>
Whenever I click the pushArray button, an item "Push" should be added in myArray, but it wasn't reflected in the template [[jsonStringify(myArray)]]. is this an expected behavior? Anyway to work around this?
The Array change observer is a bit tricky. In your code, by using myArray, you implicitly observe (only) the reference for the (whole) array, which only changes when you run setArray.
In order to overcome this, you must also use a deep observer, namely myArray.*. The correct code for your dom-module is therefore the following:
<dom-module id="my-element">
<template>
<pre>
[my-element]
myArray: [[jsonStringify(myArray, myArray.*)]]
</pre>
</template>
</dom-module>
Live demo: http://jsbin.com/yulivuwufu/1/edit?html,css,output
No other code changes are necessary.
Related
I'm a little new to Polymer and don't quite get what's happening here. I'm trying to create a simple form page. This is the code:
<dom-module id="sams-add-student">
<template >
<div class="vertical-section">
<paper-button on-click="addstudent">SUBMIT</paper-button>
</div>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'sams-add-student',
properties: {
item: {
type: Object
},
addstudent: function (event) {
console.log('addstudent');
}
}
});
})();
</script>
</dom-module>
However, I get an error that the listener method is not defined. Am I missing something?
You've incorrectly declared the addstudent method inside properties when it should actually be outside properties at the top-level of the object.
Polymer({
is: 'sams-add-student',
properties: {
// addstudent: function() {...} // DON'T DO THIS HERE
},
addstudent: function() {...} // DO THIS HERE
}
codepen
If it is a paper input, you could use something like :
this.$.IDofyourelement.value;
I have the following excerpt which should be displayed if there are no elements in an array:
<template is="dom-if" if="[[isEmpty(arrayList)]]">
<p>some text</p>
</template>
The element has the following methods:
<script>
(function() {
'use strict';
Polymer({
...
properties: {
arrayList: {
type: Array,
value: function() {return []}
}
},
...
_addElement: function(obj) {
this.push('arrayList', obj);
},
isEmpty: function(obj) {
return obj.length === 0;
}
});
})();
</script>
When I invoke _addElement_, it appears the [[isEmpty(arrayList)]] expression is not evaluated and consequently the text is not displayed.
Am I doing something wrong?
You need to change the expression to [[isEmpty(arrayList.*)]] or [[isEmpty(arrayList.splices)]].
Otherwise, the isEmpty function will only be called if you assign a new array to arrayList, but not when you change its content. You can find more information in the docs.
How can I access the value of a property inside a function?
Here is the property
properties:{
name: {type: String}
}
<my-element name="Subrata"></my-element>
Inside <my-element> I have a function like this:
Approach #1
<dom-module id="my-element">
<template>
...
...
</template>
<script>
(function () {
is: 'my-element',
properties:{
name: {type: String}
},
getMyName: function(){
return this.name;
}
})();
</script>
</dom-module>
My another approach was to put the value inside an element but that did not work either.
Approach #2
<dom-module id="my-element">
<template>
<!-- value of name is rendered OK on the page -->
<p id="maxp">{{name}}</p>
</template>
<script>
(function() {
is: 'my-element',
properties: {
name: {type: String}
},
getMyName: function(){
var maxpValue = this.$$("#maxp").innerHTML;
return maxpValue;
}
})();
</script>
</dom-module>
How can I accomplish this? Please help.
Thanks in advance
Instead of using a self-invoking anonymous function, you should be using the Polymer function. Change (function() { ... })(); in your code to read Polymer({ ... });.
Here's an example:
<dom-module id="my-element">
<template>
...
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
name: {
type: String
}
},
getMyName: function() {
return this.name;
}
});
</script>
I suggest that you follow the Getting Started guide from the Polymer documentation as it goes over all of this and more. It is a good starting point when you are looking to begin working with Polymer.
You could simple do
this.name
Anywhere in any function to access the variable
In 0.5 it was possible to add a JS-functions like:
PolymerExpressions.prototype.timeofdate = function(input) {
if(input) {
return input.substring(11,16)
}
(Extracting hour:minute from "MongoDB-timestamp" like 2014-10-04T12:34:56+02:00)
And use it with piped variable like:
{{starts | timeofdate}}
When I tried to upgrade the code above to 0.9, I had to create this element instead:
<script>
Polymer({
is: 'x-substr',
properties: {
start: Number,
end: Number,
},
attached: function() {
this.innerHTML = this.innerHTML.substring(this.start, this.end);
}
});
</script>
And use it like this:
<x-substr start="11" end="16">{{starts}}</x-substr>
(Use "attached" callback instead of "ready", if you should use this element with any data binding)
Is this the "right way" to do filter functionality like above in Polymer 0.9+?
The closest you will get to the filter behaviour in 0.5 are computed bindings in 0.9+.
For your example this would be something like this:
<dom-module id="...">
<template>
...
<span>{{timeofdate(starts)}}</span>
...
</template>
<dom-module>
Polymer({
...
timeofdate: function (input) {
return input.substring(11,16);
}
...
});
If you need this time in more than one place you could also make it a computed property instead.
<dom-module id="...">
<template>
...
<span>{{starttime}}</span>
...
</template>
<dom-module>
Polymer({
...
properties: {
starts: String,
starttime: {
type: String,
computed: 'timeofdate(starts)'
}
},
timeofdate: function (input) {
return input.substring(11,16);
}
...
});
i have a polymer custom element like this
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="my-foo" constructor="MyFoo" attributes="controller" noscript>
<template>
hello from {{options.name}}
</template>
<script>
Polymer({
get options() {
return this.controller.options;
}
});
</script>
</polymer>
<div id="container"></div>
<script>
document.addEventListener('polymer-ready',function() {
var foo = new MyFoo();
foo.controller = {
options : {
name : "here"
}
};
document.body.appendChild(foo);
});
</script>
attribute "controller" is expected to be a object having a property "options" of type object.
I can create a Instance of the custom element using
var foo = new Foo();
but i am unable to set the attribute "controller" which results in an error:
Uncaught TypeError: Cannot read property 'options' of undefined.
Sure - i could modify the options getter in the polymer component to be fail-safe like this :
...
get options() {
return this.controller ? this.controller.options : null;
}
...
But also in this case the custom element doesnt recognize the applied data.
Final question : How do I pass required attributes to an custom element constructor ?
One solution is to use a computed property:
<script src="http://www.polymer-project.org/components/platform/platform.js"></script>
<link rel='import' href='http://www.polymer-project.org/components/polymer/polymer.html'>
<polymer-element name="my-foo" constructor="MyFoo" attributes="controller" noscript>
<template>
hello from {{options.name}}
</template>
<script>
Polymer({
computed: {
options: 'controller.options'
}
});
</script>
</polymer-element>
<script>
document.addEventListener('polymer-ready',function() {
var foo = new MyFoo();
document.body.appendChild(foo);
foo.controller = {
options : {
name : "here"
}
}
});
</script>
You can even make the computed property just a call to a method. The key thing is that by doing it this way, Polymer can tell when to check if options has changed, because it knows the inputs necessary to compute options.
Polymer({
computed: {
options: 'getOptions(controller)'
},
getOptions: function(controller) {
return controller ? controller.options : null;
}
});