Multiple instances of elements seem to be sharing property values ?

1,275 views
Skip to first unread message

Rob Stone

unread,
Mar 18, 2016, 10:42:20 AM3/18/16
to Polymer
I've just discovered something that is a little confusing and was hoping a polymer expert could explain what is going on :)

I've defined an element with an array property (initialised to empty) with an attach method that then uses 'this.push' to add items to the array. If I then create multiple instances of the element, in the browser debugger it looks like the array is shared across all of these instances as each subsequent copy of the element seems to inherit the array values from previous elements. What's even more confusing is that if I create a dom-repeat that iterates over the array, it shows the 'correct' values for each instance, ie. it seems to be using an array that doesn't have duplicate values in it.

I have a very small test project that shows this problem, however I haven't got anywhere to host it so cannot put a link up.

Cut down code follows:

<dom-module id="test-element">
   
<template>
       
<template is="dom-repeat" items="[[items]]">
           
<content></content>
           
<div>[[item]]</div>
       
</template>
   
</template>


   
<script>
   
(function () {
       
Polymer({
            is
: 'test-element',
            properties
: {
                items
: {
                    type
: Array,
                    value
: []
               
}
           
},


            attached
: function () {
                console
.log('attached');
               
this.push('items', "1");
               
this.push('items', "2");
               
this.push('items', "3");
                console
.log('items=' + this.items); // The 1st instance of the element displays 'items=1,2,3' the 2nd displays 'items=1,2,3,1,2,3' !!!!
           
}
       
});
   
})();
   
</script>
</dom-module>

<!DOCTYPE html>
<head>
    <title>instance test</title>
    <script src="bower_components/webcomponentsjs/webcomponents-list.min.js"></script>
    <link rel="import" href="test-element.html"></link>
</head>
<body>
    <test-element>One</test-element>
    <test-element>Two</test-element>
</body>
</html>



I'm hoping this is a simple misunderstanding on my part, but it does have some slightly annoying implications for a project I am working on.

Rob

Karl Tiedt

unread,
Mar 18, 2016, 11:08:59 AM3/18/16
to Rob Stone, Polymer

Read the docs on properties and you'll see a statement about using:

value: function() { return []; }

In relation to arrays and objects with the appropriate change to the function.

Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/6a372d9b-fc65-4dd6-9a66-f6020aa39c1f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rob Stone

unread,
Mar 18, 2016, 11:48:11 AM3/18/16
to Polymer, rob.a...@gmail.com
Ouch !!! Thanks Karl, that's a really nasty gotcha, would be interested to hear from the polymer team why this is necessary.

Rob Stone

unread,
Mar 18, 2016, 12:00:48 PM3/18/16
to Polymer, rob.a...@gmail.com
Thinking about the mechanics of this, I can now see why it works this way. However, it is still a pretty nasty gotcha and it might be worth looking at that area of the documentation and making this issue a bit more obvious.

Karl Tiedt

unread,
Mar 18, 2016, 12:13:54 PM3/18/16
to Rob Stone, Polymer
It is how Javascript has always worked... Arrays and Objects are by reference, so in this situation, you have to return a new instance to get that separation.

In other libraries this was usually handled in the constructor with this.varname = []; but in Polymer, if you want to handle it in the properties definition (recommended way) requires the function call.

-Karl Tiedt

On Fri, Mar 18, 2016 at 9:00 AM, Rob Stone <rob.a...@gmail.com> wrote:
Thinking about the mechanics of this, I can now see why it works this way. However, it is still a pretty nasty gotcha and it might be worth looking at that area of the documentation and making this issue a bit more obvious.

Follow Polymer on Google+: plus.google.com/107187849809354688692

---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.

Rob Stone

unread,
Mar 18, 2016, 12:56:14 PM3/18/16
to Polymer, rob.a...@gmail.com
Would it be feasible for polymer to auto-wrap array/object types in a function call? I can't imagine anyone wanting the existing behaviour - but if this was deemed to be necessary, then a new 'disableAutoWrap' option could be added to the type definition object?

Justin Fagnani

unread,
Mar 18, 2016, 12:59:53 PM3/18/16
to Rob Stone, polymer-dev

There's really no way to do that. Critically, there's no way to fully clone an object.

Karl Tiedt

unread,
Mar 18, 2016, 1:03:52 PM3/18/16
to Rob Stone, Polymer
I cant imagine adding code to prevent a native JS feature will happen... and sometimes this effect *is* desired. Is adding a 1 line function that much trouble? This is the first complaint I can remember about this. However if you feel that strongly about it, I encourage you to file an issue on the Polymer/Polymer github repo

-Karl Tiedt

Rob Stone

unread,
Mar 18, 2016, 1:10:35 PM3/18/16
to Polymer, rob.a...@gmail.com
It's not so much the effort of adding the function call, more that the problem (when it occurs) isn't particularly obvious. Hopefully this thread will come up in google searches to help the next person that comes across this issue :)

Rob Stone

unread,
Mar 18, 2016, 2:30:25 PM3/18/16
to Polymer, rob.a...@gmail.com
Issue raised 7 months ago, if only the console.warn mentioned there had been implemented ;)
https://github.com/Polymer/polymer/issues/2240

lar...@gmail.com

unread,
Oct 21, 2016, 2:57:34 AM10/21/16
to Polymer
Actually - this is a very nice feature, e.g. to use in behaviors, as there are no other clean (including data binding) way AFAIK to obtain singleton-ish behavior.  PLEASE don't try to 'fix' in the framework so it disappears :)

Toni

unread,
Oct 23, 2016, 3:59:14 PM10/23/16
to Polymer, rob.a...@gmail.com
Although this question is a few months old, I ran into this problem just now and was not able to solve it immediately with the explanation given. So for anyone still having issues with this, here is the solution (without telling you to go anywhere else and try to find it in the documentation...):

1. By default, properties of Polymer objects are shared across all instances of the object (or, to be more precise, all references to the object, since Polymer doesn't create new instances, as in "new Element()"). Basically, all properties are by default static. 
2. Every property that is supposed to be individual to the specific reference, in other words, be not static, and changable without messing with any other instance/reference, has to have the field "value: function() { return []; }". 
3. Example: 

Polymer({
   
is: 'txt-carousel-view',
    properties
: {
        myOwnList
: {
            value
: function() { return []; } // this is a non-static array, invididual and fresh for every instance
       
},
        mySharedList
: {
            value
: []; // this is a static array, shared with every instance array
       
}
   
}
})
 
As a Polymer newbie, I assumed that every instance of an Polymer element in HTML would be handled as a separate instance code-wise. For me, it would have been more intuitive that properties are "fresh", except I declare them explicitly to be static. (Since ES6 is moving Javascript more towards OOP, I'd like to see the Polymer team to at least consider making Polymer attributes non-static by default.) 

Daniel Llewellyn

unread,
Oct 23, 2016, 4:13:01 PM10/23/16
to Toni, Polymer, rob.a...@gmail.com
On Sun, 23 Oct 2016 at 20:59 Toni <nullsum...@gmail.com> wrote:
1. By default, properties of Polymer objects are shared across all instances of the object (or, to be more precise, all references to the object, since Polymer doesn't create new instances, as in "new Element()"). Basically, all properties are by default static. 

This is not quite accurate.
 
2. Every property that is supposed to be individual to the specific reference, in other words, be not static, and changable without messing with any other instance/reference, has to have the field "value: function() { return []; }". 

This is only required for Arrays and Objects.
 
Explanation:

In Javascript all variables are passed-by-value. The variable "holding" an Object doesn't actually hold the Object; it only holds a reference to the Object in memory. Whereas a variable pertaining to a primitive type actually holds the value rather than a reference to the value in memory.

When Polymer creates a new instance of your element it copies the prototype into a new Object. When the variable is copied the value is copied and passed-by-value but as the value is actually a reference to the original Object then the new instance will use the same object as all other instances.

This is a problem with Javascript in general and not specific to Polymer.

Dan.

Lars Knudsen

unread,
Oct 23, 2016, 5:23:42 PM10/23/16
to Daniel Llewellyn, Toni, Polymer, rob.a...@gmail.com
.. making it (somewhat) possible to make e.g. behaviors that act like a (singleton) service - like in angular.  As long as you don't reassign any full object/array to the ones that should live a shared life.
 

This is a problem with Javascript in general and not specific to Polymer.
..or "the quirks of javascript came to the rescue as polymer doesn't have other (known to me at least :)) ways of replicating angular (singleton) services" :)

- Lars
 

Dan.

Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to a topic in the Google Groups "Polymer" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/polymer-dev/pa_Ak2ATRw8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to polymer-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/CABtuYwfLtupeCsgP-NVxoXbHEC2Yqna9%3DyfRuqCXxQRjGKVgXQ%40mail.gmail.com.

mpa...@ugcloud.ca

unread,
Apr 12, 2017, 11:49:07 AM4/12/17
to Polymer, rob.a...@gmail.com, nullsum...@gmail.com
I agree fully with Toni, Polymer is designed to help make web components, and I thought the idea of a web component is that is isolated.  This make it easy to test and re-use etc.  If having multiple copies of an element changes the behavior of it that would makes this harder to test and not intuitive.  I can see people not testing multiple copies of their elements, I have created 8 elements and it wasn't until my 9th one I noticed this issue.  I now have to go back and double check everything.

I would actually suggest removing the static array (object) option completely, as you can simple use a parent object to handle this kind of situation, and I think this would be the minority of cases anyway.

lka...@gmail.com

unread,
Jan 4, 2018, 8:57:39 AM1/4/18
to Polymer
Totally agree. Many developers won't know this after they finish reading the tutorial. It's like learning Python without being warned of the differences between class variables and instance variables.
To keep a shared state across multiple same type of elements, is not a daily demand, but will cause potential troubles in a daily work.

Lars Knudsen

unread,
Jan 4, 2018, 9:17:59 AM1/4/18
to lka...@gmail.com, Polymer
I think this should rather be explained clearly in the guidelines. It is a valuable thing when needed

You received this message because you are subscribed to a topic in the Google Groups "Polymer" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/polymer-dev/pa_Ak2ATRw8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to polymer-dev+unsubscribe@googlegroups.com.

adi....@gmail.com

unread,
Jan 10, 2018, 4:11:08 AM1/10/18
to Polymer
Hi,

Maybe a bit off-topic, but still related to data binding. What is the difference between defining a property inside the properties object, and outside of it? For example:

Polymer({ is: 'some-element', properties: { name0: String }, name1: "" });

Both this.name0 and this.name1 are accessible and both are set on the some-element object. Both can be used in data bindings, so having [[name1]] in a template will work.

Is this behavior documented or explained somewhere?

Thank you.

christo...@google.com

unread,
Feb 20, 2018, 1:13:04 PM2/20/18
to Polymer
I would consider this to be a bug, or at the very least a design flaw. It's not readily apparent that you are defining prototypes in the property specifications. Shared state through parent prototypes seems to violate the whole nature of reusable components. I think property defaults should be mixed into the instantiated object, rather than shared across all instances.
To unsubscribe from this group and all its topics, send an email to polymer-dev...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages