Polymer 1.1 binding to array values - polymer

I have a form like this
<div class="warranty-part">
<paper-input maxlength="4" name="warranty[0]" no-label-float label="1111" value="{{warranty0::input}}"></paper-input>
</div>
<div class="warranty-part">
<paper-input maxlength="4" name="warranty[1]" no-label-float label="1111" value="{{warranty1::input}}"></paper-input>
</div>
<div class="warranty-part">
<paper-input maxlength="4" name="warranty[2]" no-label-float label="1111" value="{{warranty2::input}}"></paper-input>
</div>
<div class="warranty-part">
<paper-input maxlength="4" name="warranty[3]" no-label-float label="1111" value="{{warranty3::input}}"></paper-input>
</div>
With four different fields. Each of these input values is bound to one property defined like...
properties: {
warranty0: {
type: String,
observer: 'onWarrantyChange0'
},
warranty1: {
type: String,
observer: 'onWarrantyChange1'
},
warranty2: {
type: String,
observer: 'onWarrantyChange2'
},
warranty3: {
type: String,
observer: 'onWarrantyChange3'
}
}
This works... but what would be tidier is to be able to bind to array values for each of the fields to tidy things up.
Like
properties: {
warranty: {
type: Array,
value: ['','','',''],
observer: 'onWarrantyChange'
}
}
But I just can't work out how to bind to an index of an array with polymer. From reading the docs I got the impression that binding to the input value like this would work...
value="{{warranty.0::input}}"
But it doesn't.
Is there any way to do this?

Try {{warranty.0}}, {{warranty.1}}, etc..
But if you update any of the paper-input's value, the onWarrantyChange observer won't be called as you will need a special * syntax for property change notification inside an array (See this).
properties: {
warranty: {
type: Array,
value: ['111','222','333','444']
}
},
observers: ['onWarrantyChange(warranty.*)'],
onWarrantyChange: function (changedWarranty) {
console.log(changedWarranty);
}
See this plunker for reference.
Update
Looks like the Polymer could be confused by bindings of valued type string literals. So a simple workaround would be to define an array with 4 objects like this -
value: [ { value: '' }, { value: '' }, { value: '' }, { value: '' } ]
And the bindings will become -
value="{{warranty.0.value}}", value="{{warranty.1.value}}", etc..
See this new plunker.

Related

How to bind a value in json object in vue js

I'd used vuetify component to make todo app using vuejs with firebase DB.I want to bind title from json object. but I haven't idea to bind any particular value or attribute in from obeject
<v-text-field
v-model="title"
outlined
full-width
label="Another input"
></v-text-field>
todo: {
id: this.id,
title: "Welcome to vue js",
date: new Date().toISOString().substr(0, 10),
},
you can use computed https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter
Something like this:
computed: {
title: {
set: function(value){
this.todo.title = value
},
get: function() {
return this.todo.title
}
}
}
Then bind computed property with input
<v-text-field
v-model="title"
outlined
full-width
label="Another input"
></v-text-field>

How to pass vue component props array of object?

I have a dropdown in my component and here is a json file that comes from back:
items:[
{
name:"label",
value:"",
options:[
]
},
{
name:"hint_text",
value:"",
options:[
]
},
{
name:"icon",
value:"",
options:[
]
},
{
name:"selectableOptions",
value:[
{
id:"1",
text:"item1",
},
{
id:"2",
text:"item2",
image_url:null
},
{
id:"3",
text:"item3",
image_url:null
},
{
id:"4",
text:"item4",
image_url:null
},
{
id:"5",
text:"item5",
image_url:null
},
{
]
}
]
and this is how my component looks like:
<template>
<div class="dropdown">
<div class="field">
<v-select
label="Label" // label must be eqau to items[0].name
hint="hint"//hint must be equal items[1].name
persistent-hint
background-color=""
:items="['item1', 'item2', 'item3']"// must be equal to items[3].value.text
outlined
>
<span
class=""
style="font-size:16px; color:#000000;"
slot="prepend-inner"
>icon</span>// must be equal to item[2].name
</v-select>
</div>
<script>
export default {
props: {
items: {
type: Object;
},
};
</script>
I got an error that items is not Object and it's an array but if I change to an array still doesn't work. and would you please help me, How to pass properly the items' elements which I write in the comments part?
Your JSON is not fully correct and there's something wrong with template code, but I hope it's just typos.
You can just set correct type of your prop (it should be an Array) and you'll be able to pass array of props this way:
...
<div class="dropdown">
<div>
<v-select
:label="items[0].name"
:hint="items[1].name"
persistent-hint
background-color=""
:items="items[3].value"
item-value="id"
item-text="text"
outlined
>
<span
class=""
style="font-size:16px; color:#000000;"
slot="prepend-inner"
> {{ items[2].name }} </span>
</v-select>
</div>
</div>
...
<script>
export default {
props: {
items: {
type: Array
}
}
}
</script>

Creating a dynamic Vue list that can be updated via custom props in HTML

New to VueJS. I am trying to build a custom ul component for a webpage that can be populated and updated via custom props (preferably string, but doesn't have to be), specifically in the HTML so that any other dev can simply use/update/add to the custom component with said prop, and it will add a new li through the addition of a second, third, fourth, etc. prop, appending the previous li. I am also struggling to see if more than one input type can be used on a custom prop. For a better explanation heres a coded example of what I currently have and what I would like to do:
Vue.component('resources', {
template: `
<!-- Resources Component -->
<div class="resources">
<div class="heading">
<p>Resources</p>
</div>
<ul class="resource-list">
<li v-for="item in items">
<a :src="item[source]">{{ item.message }}</a>
</li>
</ul>
</div>
`,
props: {
source: {
type: String,
default: "."
},
message: {
type: String
}
},
data () {
return {
items: [
{
message: {
type: String
},
source: {
type: String,
default: "."
}
}
]
}
}
});
And in my HTML the component looks like this:
<helpful-resources
message="test"
source="."
></helpful-resources>
This 1000% has a lot of issues, but ideally I would like to have something along the lines of this:
<helpful-resources
item: src="example url 1" message="test message 1"
item: src="example url 2" message="test message 2"
></helpful-resources>
With every addition of a new 'item' appending the previous list item with a new one with the ability to change the src and the message over and over again as needed for however many items are needed in the list.
Any help/clarification would be greatly appreciated. Thanks!
In the parent component:
<template>
<div class="resources">
<div class="heading">
<p>Resources</p>
</div>
<Helpful-resources :listItems="listItems"></Helpful-resources>
</div>
</template>
<script>
#import HelpfulResources from '#/path/to/HelpfulResources';
export default {
name: 'Resource',
components: {
HelpfulResources
},
data() {
return {
listItems: [
{src: 'link to item', message: 'special message'},
{src: 'link to item2', message: 'special message2'},
// More items ...
]
}
}
}
</script>
<style lang="scss">
/* styles */
</style>
Your component could be structured like this:
Helpful-resources.vue
<template>
<ul class="resource-list">
<li v-for="(item, index) in listItems" :key="'listItem-'+index">
<a :href="item.src">{{ item.message }}</a>
</li>
</ul>
</template>
<script>
export default {
name: 'helpful-resource',
props: [ 'listItems'],
data() {
return {
// More data ...
}
}
}
</script>
<style lang="scss">
/* styles */
</style>
Note this is styled in the vue-cli fashion, but you can modify it to fit your needs.
EDIT
To include it within an html file you would place your Vue components within the body, script tags just below the body tag.
<div id="app">
<resources :source="someData" :message="message" id="r"></resources>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
<script>
let resources = Vue.component('resources', {
template: `<div class="resources">
<div class="heading"><p>Resources</p></div>
<ul class="resource-list">
<li v-for="(item, index) in items" :key="index"><a :href="source">{{ item.message }}</a></li>
</ul>
</div>`,
props: {
number: Number,
source: {
type: String,
default: "."
},
message: {
type: String,
default: 'No message'
},
// Example of multiple data types
propB: [String, Number]
},
data() {
return {
items: [
{
message: this.message,
source: this.source
}
]
}
}
});
new Vue({
el: '#app',
components: {
resources
},
data: {
someData: 'path/to/source',
message: 'Special Message'
},
});
</script>
Here's a link to the fiddle anyways...Fiddle
As far as updating the list goes, you could use an API call to get data asynchronously or allow users to add info via button or input and use a method. Or if you are talking strictly hardcoding extra values, other developers would add to your file...
Hopefully this helps. If not, please clarify.

Dynamically Generating Bind Variable Names

I have a data grid, in which I use dom-repeat to generate the columns.
<vaadin-grid-filter value=[[filterInput]] />
<input value={{filterInput::input}} />
</vaadin-grid-filter>
I bind the value used to filter a column with the value input into an input element.
My problem is each column binds to the same filterInput variable.
Is there any way I can bind using a variable for each specific column?
Could I somehow generate the binding variable for each column, e.g. filterInput[0], filterInput[1] etc. by using the index variable that comes with dom-repeat?
I make it working with an element.
HTML template
<template is="dom-repeat" items="{{technology}}">
<input type="text" value="{{item.label::input}}">[[item.label]]<br/>
</template>
Polymer Element
technology : {
type: Array,
value: [
{id:"php", label:"PHP", selected:false},
{id:"js", label:"Javascript", selected:false},
{id:"html", label:"HTML", selected:false},
{id:"css", label:"CSS", selected:false},
]
}
Full Polymer element
<dom-module id="input-array-element">
<template>
<h3>Inputs Array</h3>
<template is="dom-repeat" items="{{technology}}">
<input type="text" value="{{item.label::input}}">[[item.label]]<br/>
</template><br>
</template>
<script>
class InputArrayElement extends Polymer.Element {
static get is() { return 'input-array-element'; }
static get properties() {
return {
technology : {
type: Array,
value: [
{id:"php", label:"PHP", selected:false},
{id:"js", label:"Javascript", selected:false},
{id:"html", label:"HTML", selected:false},
{id:"css", label:"CSS", selected:false},
],
notify: true
}
}
}
ready() {
super.ready();
this.addEventListener("technology-changed", function(e){
console.log(e);
});
}
}
window.customElements.define(InputArrayElement.is, InputArrayElement);
</script>
</dom-module>

dom-repeat template fails to render array with error 'expected array for items'

I have a simple template that renders an array object. However, it fails with the following message:
[dom-repeat::dom-repeat]: expected array for `items`, found [{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
The array is passed in the attribute of the custom element in the following format:
[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
I have read the docs on template repeaters several times and still unable to find what I am doing wrong.
Any help would be much appreciated!
Here is my custom element:
<dom-module id="x-myelement">
<template>
<div>
<h1>{{title}}</h1>
<ul>
<template is="dom-repeat" as="menuitem" items="{{items}}">
<li><span>{{menuitem.code}}</span></li>
</template>
</ul>
</div>
</template>
<script>
(function() {
Polymer({
is: 'x-myelement',
title: String,
items: {
type: Array,
notify: true,
value: function(){ return []; }
}
});
})();
</script>
</dom-module>
And here is now I use it:
<x-myelement title="Hello Polymer"
items='[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]'>
</x-myelement>
You need to put your element properties into the properties object (see the Polymer documentation on properties):
Polymer({
is: 'x-myelement',
properties: {
title: String,
items: {
type: Array,
notify: true,
value: function() {return [];}
}
}
});
Otherwise Polymer has no information about your properties. It treated items as a string and didn't parse the attribute value as a JSON array. Eventually dom-repeat was passed a string for its items property as well, resulting in the error that you saw.