I am using Polymer 1.0 to create a shopping/checkout cart. I have customers who may want to ship their order to multiple addresses. In the receipt, I need to list all the addresses with an index:
Address 1
John Doe
1234 Main St
...
Address 2
Jane Smith
999 Broadway
...
How do I get the index to start at 1 instead of 0?
<template is="dom-repeat" items="{{shipping_details}}" as="address">
<div>Address <span>{{index}}</span></div>
<div>{{address.name}}</div>
<div>{{address.line1}}</div>
</template>
This is a simplification of my actual code, but the principle is the same. I have tried to make a js function that takes the index as a parameter and sets the innerHTML to index++, but I don't know what event it should fire on or how to get it to call the function.
<div>Address <span on-some-event="displayIndex(index)"></span></div>
I am new to all of this, so you can't go in to too much detail about how to make this work. Thank you for your help in advance!
You can use a computed binding for this.
Instead of this:
<span on-some-event="displayIndex(index)"></span>
Do this:
<span>{{displayIndex(index)}}</span>
When displayIndex is this:
function (index) {
return index + 1;
}
Note:
displayIndex can be
a method on the element prototype
<dom-module id="cart-addresses">
<template is="dom-repeat" items="{{shipping_details}}" as="address">
<div>Address <span>{{displayIndex(index)}}</span></div>
<div>{{address.name}}</div>
<div>{{address.line1}}</div>
</template>
<script>
Polymer({
is: 'cart-addresses',
...
displayIndex: function(index) {
return index + 1;
}
...
});
</script>
</dom-module>
a method attached to an auto-binding template
<template is="dom-bind">
...
<template is="dom-repeat" items="{{shipping_details}}" as="address">
<div>Address <span>{{displayIndex(index)}}</span></div>
<div>{{address.name}}</div>
<div>{{address.line1}}</div>
</template>
</template>
<script>
var template = document.querySelector('template[is="dom-bind"]');
...
template.displayIndex = function (index) {
return index + 1;
};
</script>
Related
I have a part of the structure:
....
<template v-for="(item, INDEX) in someList">
<template v-if="thisIsArrayList(item)">
<template v-for="(_item) in item">
<Component
:item="_item"
:key="_item.id"
:myprop="checkIndex(INDEX)" - makes here some manipulation with prev and current INDEX and return iterration++ 0, 1
></Component>
</template>
</template>
<template v-else>
....
</template>
</template>
....
The INDEX can be couple times with the same value like (22, 22, 22) the next step like (25, 25) and so on ..
so I tried in props:arrayId to compare prevINDEX with the currentIndex for passing it in child like new value with iterations++
for example:
INDEX couple times equal 22 --> change it on 0 and return this value --> the next INDEX couple time equal 55 --> change it on 1 and return this value --> and so on ...
How can I do it in Vue?
Or maybe there is another solution for this logic?
Thanks.
You don't need to use an explicit variable infact v-for itself provides you the ability to extract index during iteration
<template v-for="(item, index) in items">
<Component
:item="item"
:key="item.id"
></Component>
</template>
As per the above code, the arrayId prop is not necessary, since you are no longer going to compare the indexes [since you won't have redundant values]
In my polymer dom, each data object todo has multiple items and it also has a todo.idx. I would like to order the items according to its todo.idx, instead of their (random) ordering in the data. How can I do it with polymer?
In the polymer document, it mentions a sort function, but I couldn't find examples there. My current code is as follows.
<ol>
<template is="dom-repeat" items="{{todos}}" as="todo">
<li><span> {{todo.item}} </span> </li>
</template>
</ol>
You can sort items in polymer using the sort attribute, and in your case you would want to use nested templates so you can sort on the dom-repeat for a given todo's items:
<template is="dom-repeat" items="{{todos}}" as="todo">
<template is="dom-repeat" items="{{todo.items}}" as="item" sort="_sortItems">
<li><span>{{item}}</span></li>
</template>
</template>
You can then define your _sortItems function in same fashion as you would for a compare function in Array.prototype.sort():
_sortItems: function(a, b) {
if (a.idx < b.idx) { return -1; }
if (a.idx > b.idx) { return 1; }
return 0;
}
I am using polymer.I have array of objects it looks
[{
name:xxx,
address:yyy,
times:[
{start:12,
End:5
},
{start:2,
End:4
}
]
},
{//same format repeats
}
]
I used nested dom-repeat,
<template is="dom-repeat" items="{{pList}}" as="list">
<paper-item>
<paper-item-body two-line>
<div>[[list.address]]</div>
<div secondary>[[list.name]]</div>
</paper-item-body>
<template is="dom-repeat" items={{list.times}} as="time">
<paper-item-body on-tap="_handleTime" two-line>
<div>[[time.start]]</div>
<div>[[time.end)]]</div>
</paper-item-body>
</template>
</paper-item>
</template>
I have on tap function in second dom-repeat,so on taping below function is called,here I can access time object.
how can I access name and address which is in first dom-repeat using with 'e' reference as bellow?
I tried parentElement but its not working!
_handleTime:function(e) {
console.log(e.model.time); //displays time obj i.e {start:12,End:5} but I'm trying to get {name,address,{start,end}}
console.log(e.parentElement);//gives error
//I'm trying to get entire object like {name:xxx,address:yyy,times:[]}
}
var item = this.$.firstRepeat.itemForElement(e.target);
where firstRepeat is the id of the first dom-repeat,
check this example
I have a Polymer dom-repeat list where the children get sorted o.k. on the initial value.
When I change the a value inside of the child, the depending sort order of the list is not updated. How can I best achieve that?
<body>
<list-records></list-records>
<dom-module id="list-records">
<template>
<template is="dom-repeat"
items="{{records}}"
sort="sortByValue">
<single-record record="{{item}}"
base="{{base}}">
</single-record>
</template>
</template>
<script>
Polymer({
is: 'list-records',
properties: {
records: {
type: Array,
value: [
{number:1, value:4},
{number:2, value:2},
{number:3, value:3}]
}
},
sortByValue: function(a, b) {
if (a.value < b.value) return -1;
if (a.value > b.value) return 1;
return 0;
}
});
</script>
</dom-module>
<dom-module id="single-record">
<template>
<div>
Number: <span>{{record.number}}</span>
Value: <span>{{record.value}}</span>
<button on-tap="_add">+</button>
</div>
</template>
<script>
Polymer({
is: 'single-record',
properties: {
record: Object,
},
_add: function() {
this.set('record.value', this.record.value + 1);
}
});
</script>
</dom-module>
</body>
Background: In the real location based application I have a center location (lat, lng) and get a list of keys for locations around the center. I create a child for each key. The child uses the key to get lat,lng information from a database (async). Using the lat lng information from center and from the location, I can calculate the distance inside the child. The list should be ordered by the calculated distance.
In your single-record component, your record property does not allow two-way data binding, hence it won't change that record back to the list-records element. To enable two-way data binding, you must declare record property with notify:true.
properties: {
record: {
type: Object,
notify: true
}
}
Source: https://www.polymer-project.org/1.0/docs/devguide/properties
I had to add the notify parameter as pointed out by Neil and also 'observe' to the template (source: How to re run dom-repeat with sort when bool property changed in Polymer element).
<template id="list"
is="dom-repeat"
items="{{records}}"
sort="sortByValue"
observe="value">
Then it works as expected in the sample code above as well as in the real geo-location application :)
The following code is taken from a tutorial in tutsplus.
if (Meteor.isClient) {
var Products = new Array(
{ Name: "Screw Driver",
Price: "1.50",
InStock: true},
{ Name: "Hammer",
Price: "2.50",
InStock: false}
);
Template.Products.ProductArr = function () {
return Products;
};
Template.Products.events = {
"click .Product": function () {
if (this.InStock)
confirm("Would you like to buy a " + this.Name + " for " + this.Price + "$");
else
alert("That item is not in stock");
}
};
}
Here is the template:
<template name="Products">
{{#each ProductArr}}
<div class="Product">
<h2>{{Name}}</h2>
<p>Price: ${{Price}}</p>
{{#if this.InStock}}
<p>This is in stock</p>
{{else}}
<p>This is sold out</p>
{{/if}}
</div>
{{/each}}
</template>
I wonder how this get bound to the model object product? This looks like magic to me.
The expression "click .Product" specifies that the click event on HTML elements having class Product should trigger the specified function. I understand it. But I don't understand why this is bound to an element of the Products array.
This is how Handlebars (which Meteor builds on) works. What you're seeing in the template isn't pure JS, but syntax specific to Handlebars.
Inside the each block helper, the context is to set each element of the array you're iterating over. So if you use InStock, it will look for it on the element of the current iteration.
The this keyword is used for disambiguation. This comes in handy if you have a general helper registered with the name InStock, like this, for example:
Template.Products.InStock = function (){
//...
};
But you want to make sure you're referring to the property of the element from the array, so you can use this to access its context explicitly.