How can I dynamically get all the fields of this rows array objects using a polymer repeat template?
rows = [{
"field1":"test1",
"field2":"test2",
"field3":"test3",
"field4":"test4"
}]
<template repeat="{{data in rows}}">
{{data.field1}}
{{data.field2}}
{{data.field3}}
{{data...}}
</template>
This plunker shows two examples:
How to refresh a repeat using a filter parameter. Less overhead and
simple to implement. It's recommended to use event actions over
observers where possible,
How to observe an Object as an Array (based from this issue comment
Polymer/polymer-expressions#11 (comment))
<!-- parameters passed to filters are observed, so changing refresh updates the repeat -->
<template repeat="{{key in objectData | toKeys(refresh)}}">
{{ objectData[key] }}
</template>
Polymer({
refresh: 0, // update this value to refresh the repeat
toKeys: function(input) {
if (!input) return;
return Object.keys(input);
}
});
Dodgy request...
I tried and my best luck was something like this:
<polymer-element name="x-for-in">
<template>
<template repeat="{{field in keys}}">
{{obj[field]}}
</template>
</template>
<script>
Polymer({
obj : null,
keys : [],
created : function () {
this.obj = {
field1 : 1,
field2 : 2,
field3 : 3
};
this.keys = Object.keys(this.obj);
}
})
</script>
</polymer-element>
OUTPUT : 1,2,3
BTW: I'm not 100% sure what you meant in description, because your code says rows - is array of objects, while you're saying rows is an object....
Anyway so far so good, example above should give an idea.
BTW2: {{data is rows}} where rows is an object - will not work, because it's essentially a javascript for in. polymer restricts such things as I understand
Related
Polymer 1.*
I am trying to refine the behavior of my computed binding with a array. I had <div hidden$="[[getState(uploadState.*)]]">FOO</div> but it was firing off to often.
I refined it to uploadState.value:
<template is="dom-repeat"
initial-count="1"
index-as="index"
items="{{uploadState}}">
<div hidden$="[[getState(uploadState.value)]]">FOO</div>
With:
uploadState: {
type: Array,
value: function() {
var arr = Array.apply(null, Array(5));
var newArray = arr.map(()=> {
return {
value: false,
main: false,
edited: false,
loading: false
};
});
return newArray;
},
notify: true
},
attached: function() {
setTimeout(()=> this.set(`uploadState.0.value`, true), 1000)
}
but it does not fire off at all. How can I make it fire in the computed binding when the value property changes?
Also, how can I use this.get() to get the value when it changes? I tried var uploaded = this.get(['uploadState.value', 0]) in the computed binding getState but it just shows undefined(when it used to fire with the .*)
The problem with your usage of the binding uploadState.value is it doesn't exist. You are making an array of uploadState that have a member with the property value which looks more like uploadState.*.value but you don't really want to change on all the changes of value, just the one in question so you can take advantage of the item binding of dom-repeat so that your code would come out like so:
<template is="dom-repeat"
initial-count="1"
index-as="index"
items="{{uploadState}}">
<div hidden$="[[item.value]]">FOO</div>
</template>
I might suggest you change up your naming convention and use uploadStates being it's an array and all, so that you can do:
<template is="dom-repeat"
initial-count="1"
index-as="index"
items="{{uploadStates}}"
as="uploadState">
<div hidden$="[[uploadState.value]]">FOO</div>
</template>
I am working on a dashboard, in which I have a search panel at the top (let's call it component A), where users can enter a query. The value of this input will change a lot of other components in the dashboard (not only components that are its direct descendants or siblings). I want to send the search value from component A to component B, which should then respond by performing some action with the input value.
I have tried a few things:
Directly calling the function in component B. Haven't been able to get that to work at all.
Manually setting B's local property value and using an observer to trigger a function call. I manager to set the value, but the observer does not trigger.
Using a global variable, which I can easily access across components, but I still can't trigger functions in specific components.
How can I best do this?
I'm relatively new to Polymer, so forgive me if my ideas aren't completely 'Polymerised' :)
Approach 1
<dom-module id="component-B">
<template>
</template>
<script>
Polymer({
is: 'component-B',
properties: {
id: '',
observer: '_idUpdate'
},
_idUpdate: function(){
console.log("HELLO");
}
});
</script>
</dom-module>
<dom-module id="component-A">
<template>
</template>
<script>
Polymer({
is: 'component-A',
idSearch: function() {
var id = this.$.search.value;
document.querySelector('component-B').properties.id = id;
},
});
</script>
</dom-module>
As you want to send data to multiple elements (which might not be siblings of the firing element) you can use any of these two methods
Use iron-signal to fire the signal and then in all the elements where you want the data use iron-signal tag to listen to the signal
<iron-signals on-iron-signal-<signal-name>="<function>"></iron-signals>
You can also use standard HTML method dispatchEvent to fire a signal and then add eventListeners in all the element where you want data.
<dom-module id="payment-list">
<template>
<template is="dom-repeat" items="{{clients}}">
<paper-item>
<span>{{item.Name}}</span>
|
<span>{{item.Amount}}</span>
</paper-item>
</template>
</template>
<script>
Polymer({
is: 'payment-list',
properties: {
clients: {
notify:true,
type: Array,
value: [{Name:'A', Amount:'100'},
{Name:'B', Amount:'200'}]
}
},
handleComplete: function(NewValues){
/***********/alert(NewValues);/***********/
},
ready: function(){
google.script.run.withSuccessHandler(this.handleComplete).GS_GetClients();
}
});
</script>
</dom-module>
I am using google.script.run to communicate with GAS function GS_GetClients(). GS_GetClients will be returning an object and I am trying to bind this new values to the property 'clients'.
When I do the alert I see that new values are passed to the handleComplete function from the server side GAS function. But I am not able assign the new values to the property 'clients'.
I cant set the values by using this.clients = NewValues. This is making the value to undefined.
The call to google.script.run is asynchronous.
The result seems to return, when the rendering of {{clients}} has already happend.
So in your success handler handleComplete(..) you somehow have to tell Polymer to redraw.
I do not know Polymer but from the docs Polymer data binding it seems as if you can do it like this :
Polymer({
...
setClients: function(clients) {
this.clients = clients;
// Notification required for binding to update!
this.notifyPath('clients', this.clients);
}
});
How to call custom methods in Polymer is explained here member-functions , sorry can not provide a more detailed answer regarding Polymer.
I'm learning Polymer. One item that is challenging me is updating the item of an array. I wish there was a CDN for Polymer so I could put together a fiddle. For now though, I have an element defined like this:
my-element.html
<dom-module id="my-element">
<button on-click="onLoadData">Load Data</button>
<button on-click="onTest1Click">Test 1</button>
<button on-click="onTest2Click">Test 2</button>
<template is="dom-repeat" items="[[ data ]]" as="element">
<div><span>[[ element.id ]]</span> - <span>[[ element.status ]]</span></div>
<template is="dom-repeat" items="[[ element.children ]]" as="child">
<div> <span>[[ child.id ]]</span> - <span>[[ child.status ]]</span></div>
</template>
</template>
</template>
<script>
Polymer({
is: 'my-element',
properties: {
data: {
type: Array,
value: function() {
return [];
}
}
},
onLoadData: function() {
// Generate some dummy data for the sake of illustration.
for (var i=1; i<=3; i++) {
var element = {
id: i,
state: 'Initialized',
description: ''
};
element.children = [];
for (var j=1; j<=5; j++) {
var child = {
id: i + '-' + j,
state: 'Initialized',
description: ''
}
element.children.push(child);
}
data.push(element);
}
},
// Setting an individual property value works
onTest1Click: function() {
this.set('data.0.children.0.state', 'data set');
},
// Setting an entire object value does NOT work.
onTest2Click: function() {
var c = this.data[0].children[0];
c.state = 'data set';
this.set('data.0.children.0', c);
}
});
</script>
</dom-module>
For some reason, if I update the property value of an array element (as shown in onTest1Click), the UI is updated properly. However, if I update an entire element (as shown in onTest2Click), the UI does NOT get updated. In my real problem, I'm updating multiple properties on an element. For that reason, I'm trying to update an array element and not just a property. Am I doing something wrong or misunderstanding something? Or, am I going to have to update each property value individually?
If you want to mutate an array, rather than just an object in an array (such as swapping out an entire element in an array), there are array mutation methods similar to this.set.
For example, this.splice('data.0.children', 0, 1, c) will remove the current item at the 0 index of the child array and replace it with a new one, which is what it appears you're trying to do. There's also this.shift, this.unshift, this.push and this.pop. These are all similar to their Array prototype counterparts.
One thing to note is that in your example, you're also not actually swapping out the entire object. When you grab the element from the array, mutate a field, and try and replace it with itself, you're not actually replacing it, so that doesn't actually trigger an update. And since the mutation of the field was done outside of Polymer's notification system, that also doesn't trigger an update. If you replace the item with an actual different object, it will work using splice.
https://jsbin.com/rapomiyaga/1/edit?html,output (This is a modified snapshot of Günter Zöchbauer's jsbin)
If you're not making a copy of the object/a completely new object, you'll want to update each field individually through this.set.
Yes, you are going to need to update each property value individually. When you call set, Polymer will go to the given path and check if the value has changed. If the value is an object it will compare the references (and not the subproperties). Since the object reference has not changed, it will not update the UI.
I want to set filters dynamically. Is it possible?
dynamicFilter is a variable with name of the Polymer expression.
<template is="auto-binding">
<span>{{value | dynamicFilter}}</span>
</template>
AFAIK, there is no handy way to assign Filter to element in runtime. But there is a simple workaround you might find useful:
We are to define the staticFilter function, which would be a proxy (wrapper) to calls to dynamicFilters. Assuming dynamic filters to be instances of PolymerExpression, this might be put together as follows:
<polymer-element name="my-element" attributes="dynamicFilter">
<template>
<span>{{value | staticFilter(dynamicFilter)}}</span>
</template>
<script>
PolymerExpressions.prototype.uppercase = function(input) {
return input.toUpperCase();
},
PolymerExpressions.prototype.lowercase = function(input) {
return input.toLowerCase();
},
Polymer({
value: '¡Hola!',
dynamicFilter: null,
staticFilter: function(v, df) {
return df ? PolymerExpressions.prototype[df](v) : v;
}
});
</script>
</polymer-element>
<my-element></my-element>
<my-element dynamicFilter='uppercase'></my-element>
<my-element dynamicFilter='lowercase'></my-element>
Now you are free to set the dynamicFilter attribute of my-element even in runtime.
The reason is that filters are compiled and bound during element initialization; for security reasons there is no eval behind and therefore you cannot simply pass the arbitrary dynamic value there. On the other hand, filters are ready to receive parameters and that fact actually does the trick. BTW, you might even pass the function instance there whether you are not satisfied with PolymerExpressions for this purpose.
Your use case is not really clear, but you could use this.injectBoundHTML as a workaround.
When you need to change the filter dynamically, just reinject the content of the span