Does polymer core-ajax reuse bindings? - javascript

I created two polymer elements: http://jsbin.com/vusere/1
sparkline-chart
node-list
My goal is to render a list of sparkline charts backed up by data out of a REST API.
Now I've got the problem that on each iteration over nodes all sparkline-chart values are set to those of the actual iteration. But this only occures for the history binding and not the node.id binding.
Do I miss a point here?
node-list
<polymer-element name="node-list">
<template>
<core-ajax
auto
url="http://demonstrator.herokuapp.com/nodes"
handleAs="json"
response="{{nodes}}"></core-ajax>
<template repeat="{{node in nodes}}">
<core-ajax
auto
url="http://demonstrator.herokuapp.com/node/{{node.id}}/hist_bandwidth"
handleAs="json"
response="{{history}}"></core-ajax>
<sparkline-chart values="{{history | filterHistory}}"></sparkline-chart>
<h4>{{history | filterHistory}}</h4>
<h4>{{node.id}}</h4>
</template>
</template>
<script>
Polymer('node-list', {
filterHistory: function (data) {
if (data) {
return _(data.histBandwidth.data).pluck('bandwidth').last(20).valueOf();
}
}
});
</script>
</polymer-element>
sparkline-chart
<polymer-element name="sparkline-chart" attributes="values width">
<template>
<span id="values">{{values}}</span>
<h4>{{values}}</h4>
</template>
<script>
Polymer('sparkline-chart', {
width: 100,
created: function () {
this.values = [0];
},
domReady: function () {
$(this.$.values).peity('line', { width: this.width, fill: 'none' });
},
valuesChanged: function () {
$(this.$.values).change();
}
});
</script>
</polymer-element>

Mustache bindings always refer to a property on a model object (the default model object in a polymer element is the element itself). So, in this case history refers to this.history, which is a single property, and will be constantly overwritten by the various ajax calls.
One way to fix this is by using a history per node like so:
<core-ajax
auto
url="http://demonstrator.herokuapp.com/node/{{node.id}}/hist_bandwidth"
handleAs="json"
response="{{node.history}}"></core-ajax>
<sparkline-chart values="{{node.history | filterHistory}}"></sparkline-chart>

Related

How to reference a child component from the parent in Vue

I'm trying to figure out the Vue-way of referencing children from the parent handler.
Parent
<div>
<MyDropDown ref="dd0" #dd-global-click="ddClicked"></MyDropDown>
<MyDropDown ref="dd1" #dd-global-click="ddClicked"></MyDropDown>
<MyDropDown ref="dd2" #dd-global-click="ddClicked"></MyDropDown>
</div>
export default {
methods: {
ddClicked: function(id) {
console.log("I need to have MyDropDown id here")
}
}
}
Child
<template>
<h1>dropdown</h1>
<Button #click="bclick"></Button>
</template>
export default {
methods: {
bclick: function() {
this.$emit('dd-global-click')
}
}
}
In the parent component I need to see which dropdown was clicked.
What I've tried so far
I tried to set "ref" attribute in the parent. But I can't refer to this prop within the child component. Is there a way to do it? There is nothing like this.ref or this.$ref property.
I tried to use $event.targetElement in the parent, but it looks like I'm mixing Real DOM and Vue Components together. $event.targetElement is a DOM like . So in the parent I have to go over the tree until I find my dropdown. It is ugly I guess.
I set an additional :id property for the dropdown making it the copy of the 'ref' property. In the blick and I called this.$emit('dd-global-click', this.id). Later in the parent I check this.$refs[id]. I kind of works, but I'm not really content with it, because I have to mirror attributes.
Using the _uid property didn't work out either. On top of that, I think, that since it starts with an underscore it is not a recommended way to go.
It seems like a very basic task, so there must be a simplier way to achieve this.
If this custom dropdown element is the top level one (the root element) in the component, you could access the native DOM attributes (like id, class, etc) via this.$el, once it's mounted.
Vue.component('MyDropdown', {
template: '#my-dropdown',
props: {
items: Array
},
methods: {
changed() {
this.$emit('dd-global-click', this.$el.id);
}
}
})
new Vue({
el: '#app',
data: () => ({
items: [
{
id: 'dropdown-1',
options: ['abc', 'def', 'ghi']
},
{
id: 'dropdown-2',
options: ['jkl', 'lmn', 'opq']
},
{
id: 'dropdown-3',
options: ['rst', 'uvw', 'xyz']
}
]
}),
methods: {
ddClicked(id) {
console.log(`Clicked ID: ${id}`);
}
}
})
Vue.config.devtools = false;
Vue.config.productionTip = false;
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.11"></script>
<div id="app">
<my-dropdown
v-for="item of items" :key="item.id"
:id="item.id"
:items="item.options"
#dd-global-click="ddClicked">
</my-dropdown>
</div>
<script id="my-dropdown" type="text/x-template">
<select #input="changed">
<option v-for="item of items" :key="item" :value="item">
{{item}}
</option>
</select>
</script>

Get data from an Array in Vue

Right now, displayed data in my page is an array as per snippet below:
But I want only to get or display the project names.
This is what I have only right now:
fetch(context,id){
if(context.getters['isEmpty']){
Vue.api.mediasetting.index()
.then(response=>{
var medias = response.data[key];
context.commit('setMedias',medias);
// console.log("init medias", medias[0].project_name)
},response=>{
});
}
},
Can I apply filter here and how? Thanks.
Depends on what html element you want to use for rendering the values, you may use a v-for directive to rendering the project_name values:
<template>
<ul id="example">
<li v-for="(media) in medias">
{{ media.project_name }}
</li>
</ul>
</template>
You are going to need to get the medias data from your store, you may get it using a computed property:
<script>
export default {
computed: {
medias: function () {
return this.$store.medias
}
}
}
</script>
Example above is assuming you are using single file component structure.

Accessing object values programmatically in Polymer 2 nested templates

With the conventional use of a dom-repeat loop and a template, the field
reference is hard-coded against the source object. In the example below we're
pulling the name and description fields from a JSON object. Works fine.
<template is="dom-repeat" items="[[subjects]]">
{{item.name}}, {item.description}}
</template>
In my application I'd like to pull values programmatically by using a
nested template that loops through a supplied list of fields. However I'm not
able to make it work, the results come out as literal text rather than performing as I'd like:
<template is="dom-repeat" items="[[subjects]]">
<template is="dom-repeat" items="[[fields]]" as="field">
{{item.{{field}}}},
</template>
</template>
These are the variations I've tried and the results using 'name' and 'description'
as the fields:
{{item.{{field}}}}, -> "{{item.name}} {{item.description}}"
{{item[ {{field}} ]}}, -> "{{item[ name ]}} {{item[ description ]}}"
Ideally, I would like it to work like this:
someFunction( {{item}}, {{field}} )
Where someFunction would take in the object & field specifier and return a string.
Just not sure how to make it happen. Any ideas?
Addendum showing missing parts called out:
<iron-ajax>
auto
url="https://api.github.com/users/burczu/repos"
params='{"type":"all"}'
handle-as="json"
on-response="handleResponse">
</iron-ajax>
and
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
static get properties() {
return {
subjects: { type: Array },
fields: { type: Object }
};
}
ready() {
super.ready();
this.fields = JSON.parse('{"show": ["name", "description"] }').show;
}
handleResponse(data) {
this.subjects = data.detail.response;
}
}
window.customElements.define(MyElement.is, MyElement);
</script>
Ok, the solution isn't far off from what I wanted. It was a matter of applying the right syntax:
<template is="dom-repeat" items="[[subjects]]">
<template is="dom-repeat" items="[[fields]]" as="field">
[[ _formatText(item, field) ]],
</template>
</template>
<script>
class MyElement extends Polymer.Element {
. . .
_formatText(obj, field) {
return obj[field];
}
. . .
}
</script>
While it works as I wanted, all text returned by the _formatText function will be rendered as an HTML-safe string outside of the square brackets. No chance of emitting tags recognized by the browser. :(
If anyone knows how to get over that hurdle, please let me know.

Polymer 2.0 iron-localstorage two arrays

I'm trying to make a shopping cart in polymer And I do not have much knowledge
How do I insert a selected data in template dom-repeat to an array binding to iron localsotage e.model.item it does not work.
<dom-module id="shop-cart">
<template>
<iron-ajax url="list.json" last-response="{{ListProducts}}" auto>
</iron-ajax>
<template is="dom-repeat" items="{{ListProducts}}">
<p style="display:block;width:400px">
<span>{{item.code}}</span>
<span>{{item.title}}</span>
<paper-button raised class="indigo" on-
click="addProduct">Add</paper-button>
<br/>
</p>
</template>
<iron-localstorage name="my-app-storage"
value="{{Orders}}"
on-iron-localstorage-load-empty="initializeDefaultOrders"
></iron-localstorage>
<template is="dom-repeat" items="Orders" as="order">
<div>
<p>{{order.code}}</p>
<p>{{order.title}}</p>
</div>
</template>
</template>
<script>
class ShopCart extends Polymer.Element {
static get is() {
return 'shop-cart';
}
static get properties() {
return {
Product: {
type: String
},
Orders: {
type: Array,
value() {
return [
{
code:'',
title:'',
}
];
},
},
ListProducts: {
type: Array,
value() {
return [];
},
}
}
}
initializeDefaultOrders() {
this.Orders = {
code:'',
title:''
}
};
addProduct(e) {
this.Product= e.model.item.title;
this.push('Orders',this.Product);
this.set('Product','');
}
deleteProduct(e) {
this.splice('Orders', e.model.index, 1);
}
}
window.customElements.define(ShopCart.is, ShopCart);
</script>
</dom-module>
<shop-cart></shop-cart>
The value passed to your method, addProduct(e), has nothing to do with the data model of the item of ListProducts.
Here is an example of shopping cart that binds the selection (a checkbox being checked) to a property of the item, item.selected.
https://github.com/renfeng/android-repository/blob/master/elements/android-sdk-manager.html#L267-L297
If checkboxes are not desirable, you can add a custom attribute to your button. e.g. selected
The following works only for Polymer 1.
<paper-button raised class="indigo" on-click="addProduct" selected="[[item.title]]">Add</paper-button>
And, have the following line to retrieve the title of the item selected.
this.Product= e.target.getAttribute("selected");
For Polymer 2, here is your fix.
https://github.com/renfeng/stackoverflow-question-44534326/commit/b2a4226bd5a1f5da7fa2d5a8819c53c65df7c412
Custom attribute has been proposed for Polymer 2, but not seem to be accepted for this moment. See https://github.com/Polymer/polymer/issues/4457

Event Handling between parent and child page in polymer 1.0

I have a parent polymer element called parent-page and a child element called child-page.
parent-page calls child page and passes an array with it. for e.g, in parent page:
<child-page items={{itemsArray}}></child-page>
Now, on the basis of certain activity child page fires an event with a new array.
eg, in child page:
this.fire('eventPerformed', newArray);
This array is being listened by the parent page and received with expected values.
Now, I want to pass that new array to the child page such that the child-page is rendered according to the new array.
How to achieve it?
Edit: my child page looks like this.
<dom-module id="child-page">
<style>
</style>
<template>
<template is="dom-repeat" items="{{itemArray}}" as="fooditem">
<div class="horizontal layout">
<div>{{fooditem.quantity}}</div>
<div>{{fooditem.name}}</div>
</div>
</template>
<paper-button on-click"changeArray"> ChangeArray</paper-button>
</template>
<script type="text/javascript">
Polymer({
is:'child-page',
properties:{
itemArray:Array
},
changeArray:function(){
this.itemArray=<<Some new Array>>
this.fire('eventPerformed',newArray);
}
});
</script>
</dom-module>
Is there any way I can call the template repeat with the new array in the same child page? Or do I have to fire an event to the parent-page and call the child page again? How to achieve it either way?
The child-page re-renders its template is="dom-repeat" items="[[itemArray]]" automatically whenever its itemArray property was updated.
Just add notify: true to the itemArray property in child-page to enable two-way-binding with the parent-page element. Then the parent-page is also notified whenever the item-array of child-page has changed (see the Polymer documentation on this topic).
Here is a small complete example:
<dom-module id="child-page">
<template>
<template is="dom-repeat" items="[[itemArray]]">
<div>[[item]]</div>
</template>
<div on-click="_changeArray">Change</div>
</template>
<script>
Polymer({
is: 'child-page',
properties: {
itemArray: {type: Array, notify: true}
},
_changeArray: function() {
this.itemArray = [4,5,6,7,8,9];
}
})
</script>
</dom-module>
<dom-module id="parent-page">
<template>
<span>Item count: </span><span>[[itemArray.length]]</span>
<child-page item-array="{{itemArray}}"></child-page>
</template>
<script>
Polymer({
is: 'parent-page',
properties: {
itemArray: {type: Array, value: [1,2,3]}
}
})
</script>
</dom-module>
<parent-page></parent-page>
Btw. note my usage of {{...}} and [[...]]. Use curly braces for two-way bindings and square brackets for one-way bindings.

Categories

Resources