I've been learning Polymer since 3 days ago and I'm stucked with Polymer Behaviours.
I've defined a Behaviour as you can see in the following code:
<script>
BSM._TestBehaviour = {
properties: {
language: {
value: document.documentElement.lang
},
/*GetCountries: {
type: Function,
computed: '_computeCountries'
},*/
fcountries: function () {
return function(){
return ['Catalunya','Andorra'];
}.bind(this);
}
}
};
BSM.TestBehaviour = [BSM._TestBehaviour];
</script>
And in the following snippet it can be seen a component that uses that behaviour:
<link rel="import" href="test-behaviour.html">
<dom-module id="test-apps">
<style>
</style>
<template>
<div id="container">
<paper-input value="{{_defaultUser.FirstName}}"></paper-input>
<paper-input value="{{_defaultUser.LastName}}"></paper-input>
<div></div>
<paper-dropdown-menu class="p50" label="Countries" >
<paper-listbox class="dropdown-content" id="countries">
<template is="dom-repeat" items="{{fcountries()}}">
<paper-item name="[[item]]">[[item]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
<div></div>
</div>
<iron-data-table id="idt" items="{{GetCountries}}" selection-enabled multi-selection>
<data-table-column name="Id" >
<template> {{item.Id}}</template>
</data-table-column>
<data-table-column name="FirstName" >
<template> {{item.FirstName}}</template>
</data-table-column>
<data-table-column name="LastName" >
<template> {{item.LastName}}</template>
</data-table-column>
<data-table-column name="FullName" >
<template> [[_computeFullName(item)]]</template>
</data-table-column>
<data-table-column name="Country" >
<template> [[item.Country]]</template>
</data-table-column>
</iron-data-table>
</template>
<script>
BSM.TestApps = Polymer({
is: 'test-apps',
behaviours: [BSM.TestBehaviour],
properties: {
items: {
type: Array,
value: function () { return []; }
},
_defaultUser: {
type: Object
},
defaultSelected: {
type: Object
},
selectedIdCountry: {
type: Number
},
_newItemlabel: {
type: String
},
_itemsselected:{
type: Array,
value: function () {return [];}
},
countries:{
type: Array,
notify: true,
//value: function() {return ["Alemanya", "Dinamarca", "Canada"];}
//value: MyBehaviors.TestBehaviour.GetCountries
}
},
ready: function () {
var countries = this.behaviours[0].properties.GetCountries;
var users = [
{Id:1, FirstName: "Aleix", LastName: "Trasserra", Country: "EEUU"},
{Id:2, FirstName: "Maria", LastName: "Garcia", Country: "EEUU"},
{Id:3, FirstName: "Anna", LastName: "Tous", Country: "EEUU"},
{Id:4, FirstName: "Manel", LastName: "Rodriguez", Country: "EEUU"},
];
this.items = users;
var defaultUser = {
Id: null,
FirstName:"",
LastName: "",
Country:null
};
this._defaultUser = defaultUser;
this.$.idt.addEventListener('selecting-item',this._selectedItem.bind(this));
},
_selectedItem: function (e) {
this.set('_itemsselected', this.$.idt.selectedItems);
},
_onAddItem: function () {
//this.push('items',{Id: 4, text: this._newItemlabel});
//this.set('_newItemlabel',"");
},
_onRemoveSeletedItems: function () {
this._itemsselected.forEach(e => {
var index = this.items.indexOf(e);
this.splice('items',index,1);
})
},
_computeFullName: function (item) {
return item.FirstName + " " + item.LastName;
}
})
</script>
</dom-module>
The problem is that the component does not found the function "fcountries" defined in the behaviour.
Anyone can help me with this issue?
Thanks a lot!
Behavior:
/* #polymerBehavior BSM.TestBehaviourImp */
BSM.TestBehaviourImp = {
// implementation here
};
/* #polymerBehavior BSM.TestBehaviour */
BSM.TestBehaviour = [
BSM.TestBehaviourImp
// , other included base behaviors
];
Element:
...
<iron-data-table id="idt" items="{{items}}" selection-enabled multi-selection>
...
The table lists the users, which are stored in property items.
It looks like you want do do something with countries (like showing a filtered table of users)?
In that case, bind the selected item of <paper-dropdown-menu> to a property, i.e. selectedCountry: {type: String}.
Add a function which returns an Array of users, filtered to the selected country:
usersInSelectedCountry(): {
return this.items.filter(user => user.Country === this.selectedCountry || this.selectedCountry == null);
}
and use that function's return value as the data set for the table.
Related
I just got started with Vue.js and here is what I'm doing: I am rendering a list of products, and each product has a name, a gender and a size. I'd like users to be able to filter products by gender, by using an input to type the gender.
var vm = new Vue({
el: '#product_index',
data: {
gender: "",
products: [{name: "jean1", gender: "women", size: "S"}, {name: "jean2", gender: "men", size: "S"}]
},
methods:{
updateGender: function(event){
this.gender = $(event.target).val()
}
}
}
)
<div v-for="product in products" v-if="...">
<p>{{product.name}}<p>
</div>
<input v-on:change="updateGender">
I managed to get the gender updated, but I have an issue with the filtering part. When the page loads, I don't want any filtering. In the documentation, they advise to use v-if but it doesn't seem compatible with this configuration.
If I use v-if, I could do:
v-if="product.gender == gender"
But again, this doesn't work when the page load because gender is empty.
I couldn't find a workaround for this.
How should I approach this issue ?
Use computed properties - something like this (Example bellow filter items by type)
const app = new Vue({
el: '#app',
data: {
search: '',
items: [
{name: 'Stackoverflow', type: 'development'},
{name: 'Game of Thrones', type: 'serie'},
{name: 'Jon Snow', type: 'actor'}
]
},
computed: {
filteredItems() {
return this.items.filter(item => {
return item.type.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
}
})
Template:
<div id="app">
<div v-for="item in filteredItems" >
<p>{{item.name}}</p>
</div>
<input type="text" v-model="search">
</div>
Demo: http://jsbin.com/dezokiwowu/edit?html,js,console,output
You can try v-if="!gender || product.gender == gender"
Just modified #Nora's answer.
You need to change in the template as:
<div id="product_index">
<div v-for="product in products" v-if="!gender || product.gender===gender">
<p>{{product.name}}<p>
</div>
<input v-on:change="updateGender">
</div>
and in JS file as:
var vm = new Vue({
el: '#product_index',
data: {
gender: "",
products: [{name: "jean1", gender: "women", size: "S"}, {name: "jean2", gender: "men", size: "S"}]
},
methods:{
updateGender: function(event){
this.gender = event.target.value
}
}
}
);
Working Demo: https://jsbin.com/qocuraquki/edit?html,js,console,output
computed: {
filteredItems() {
return this.allStartupData.filter(item => {
let byName =
item.name.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
let byDescription =
item.description.toLowerCase().indexOf(this.search.toLowerCase()) >
-1;
if (byName === true) {
return byName;
} else if (byDescription === true) {
return byDescription;
}
});
}
}
and then u can iterate through filteredItems like e.g
<v-flex v-for="(obj,index) in filteredItems" :key="index" xs12 md4>
computed: {
filteredItems() {
return myObject.filter((val) => {
return val.some((val) => val.toString().toLowerCase().includes(this.searchString))
})
}}
Iterate over the Object as already described above
HelloWorld.vue
<template>
<div>
<div v-for="box in boxes" :key="box.sname">
<BaseAccordian>
<template v-slot:title>{{ box.sname }}</template>
<template v-slot:content>
<div v-for="paint in paints" :key="paint.tname" class="line">
<List :content="matchingdata" :sname="box.sname" />
</div>
</template>
</BaseAccordian>
</div>
</div>
</template>
<script>
import BaseAccordian from "./BaseAccordian.vue";
import List from "./List.vue";
export default {
name: "HelloWorld",
components: {
BaseAccordian,
List,
},
data() {
return {
boxes: [
{
sname: "apple",
},
{
sname: "bananna",
},
{
sname: "grapes",
},
{
sname: "choc",
},
],
paints: [
{
tname: "a",
},
{
tname: "b",
},
{
tname: "c",
},
{
tname: "d",
},
{
tname: "e",
},
],
matchingdata: [
{
matchid: "1",
OverallStatus: "ok",
sname: "choc",
},
{
matchid: "2",
OverallStatus: "notok",
sname: "grapes",
},
],
};
},
};
</script>
BaseAccordion.vue
<template>
<div class="wrapper">
<div class="accordion">
<input type="checkbox" #click="toggleItem" />
<h2 class="title">
<slot name="title"></slot>
</h2>
</div>
<div v-show="show" class="content">
<slot name="content"></slot>
</div>
</div>
</template>
<script>
export default {
components: {},
data: function () {
return {
show: false,
};
},
methods: {
toggleItem: function () {
this.show = !this.show;
},
},
};
</script>
List.vue
<template>
<div class="">
<div
v-for="match in matchingData"
:key="match.matchid"
:class="{
green: match.OverallStatus === 'ok',
red: match.OverallStatus === 'notok',
}"
>
{{ match.OverallStatus }}
</div>
</div>
</template>
<script>
export default {
components: {},
props: {
content: {
type: Array,
required: true,
},
sname: {
type: String,
required: true,
},
},
data: function () {
return {};
},
methods: {},
computed: {
matchingData() {
return this.content.filter((a) => {
if (a.sname === this.sname) {
return true;
} else {
return false;
}
});
},
},
};
</script>
<style scoped>
</style>
I three arrays called matchingdata,boxes,paints array based on this three arrays, i am trying to filter the array.(nested v-for)
Now, I want to iterate the matchingdata array by comparing it with sname in boxes array. and Common value between matchingdata and boxes array is ""sname""
I tried above logic, and struck with computed property.
Expected Output:-
In List.vue component , i have
{{ match.OverallStatus }} where that field , i want to show,(from the matchingdata array) when user clicked on checkbox.
Taking the ""sname"" the common value from the matchingdata array and the boxes array
code:- https://codesandbox.io/s/damp-pine-27s2kn?file=/src/components/List.vue
As you're passing the sname property as a string via a prop to your List.vue component, you'll just need to use that string in your filter function.
matchingData() {
return this.content.filter((a) => a.sname === this.sname)
},
I've tried this in your codesandbox link and it is giving some output - but I'm not clear enough on what you're trying to achieve to know if this is the intended outcome.
Just incase you're not aware the 'filter' function returns a new array. It's not going to return a 'true/false' which I feel you may be trying to do.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
My component state has an array named concessions with 35 objects, here's the structure of one of those objects:
{
address:"Some street"
brands: [{
id: 1,
name: 'fiat'
}]
city:"Paris"
contact_name:""
email:""
id:1
latitude:"11.11111"
longitude:"22.22222"
name:"AGORA Cars"
opening_hours:"something"
phone:"969396973"
phone2:""
zipcode:"19100"
}
Now, I have a list rendered with all car brands and a checkbox for each one like this:
<div class="brands-filter col-10">
<span v-for="brand in brands" :key="brand.key" class="brand-card">
<div>
<input
type="checkbox"
:value="brand.name"
v-model="search_filters"
#click="filterConcessions()"
/>
<label class="form-check-label">{{brand.name}}</label>
</div>
</span>
</div>
Basically, for each clicked checkbox, I'm adding the brand to searched_filters and after that I want to filter the concessions array based on those filters.
In that click method, #click="filterConcessions()", I'm doing this:
filterConcessions: function () {
let concessions = this.concessions;
let search_filters = this.search_filters;
let filteredConcessions = [];
filteredConcessions = concessions.filter((concession) =>
concession.brands.some((brand) => search_filters.includes(brand.name))
);
this.concessions = filteredConcessions;
}
But, no matter what, it gives me an empty array.
Any advice?
It's because you need to use the #change event instead of #click.
Otherwise, search_filters isn't populated before filterConcessions is run:
new Vue({
el: "#app",
data: {
search_filters: [],
concessions: [{
address: "Some street",
brands: [{
id: 1,
name: 'fiat'
}],
city: "Paris",
contact_name: "",
email: "",
id: 1,
latitude: "11.11111",
longitude: "22.22222",
name: "AGORA Cars",
opening_hours: "something",
phone: "969396973",
phone2: "",
zipcode: "19100"
}]
},
methods: {
filterConcessions: function() {
let concessions = this.concessions;
let search_filters = this.search_filters;
let filteredConcessions = concessions.filter((concession) =>
concession.brands.some((brand) => search_filters.includes(brand.name))
);
console.log(filteredConcessions)
this.concessions = filteredConcessions;
}
}
});
Vue.config.productionTip = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="brands-filter col-10" v-if="concessions[0]">
<span v-for="brand in concessions[0].brands" :key="brand.key" class="brand-card">
<div>
<input type="checkbox" :value="brand.name" v-model="search_filters" #change="filterConcessions()" />
<label class="form-check-label">{{brand.name}}</label>
</div>
</span>
</div>
</div>
After some search i figure how to solve this.
I've created a computed method:
computed: {
filteredConcessions() {
if (!this.search_filters.length) {
return this.concessions;
} else {
return this.concessions.filter((concession) =>
concession.brands.some((brand) =>
this.search_filters.includes(brand.name)
)
);
}
},
}
and at the for loop i iterate throw the "filteredConcessions":
<li v-for="concession in filteredConcessions" :key="concession.id" class="p-2">
And that solved my case!
I'd like to create a control that converts the data into something I need.
At the moment, I solve this with a global variable. The code looks something like this:
(The lowercase functionality is only to demonstrate it in a simple way. Usually I want to use it for arrays of objects. e.g. to get distinct values of certain names and ids)
<dom-module id="my-tolower">
<script>
"use strict";
Polymer({
is: 'my-tolower',
properties: {
input: {
type: String,
value: "",
},
output:{
type: String,
value: "",
notify: true,
}
},
observers:[
"_inputChanged(input)",
],
_inputChanged: function(newInput, oldInput){
this.set("output", newInput.toLowerCase());
}
});
</script>
</dom-module>
Usage:
<my-tolower input="[[output.name]]" output="{{lower}}">[[lower]]</my-tolower>
This solution works great if I am only using the variable lower only once. Inside of a <dom-repeat>, I get a problem.
How can I easily make a custom variable that is only available inside of my-tolower? Exactly the same way as Polymer's dom-repeat does?
I took a look at the code at Polymer's <dom-repeat> sources, but I have no idea how that works. Is this even possible in a custom element? Do I need to create a custom template?
To explain my problem better I have added a bigger Example that explains my problem in detail.
HTMLImports.whenReady(() => {
Polymer({
is: 'my-app',
ready: function(){
//In my real Problem this value comes from a websocket...
this.devices = [{
name: "PC 1",
components: [
{
name: "HDD1",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor1", usage: "DontKnow2"},
{ type: "Processor2", usage: "DontKnow3"}
]
},
{
name: "Another Piece Of Hardware",
processors: [
{
type: "Processor4",
usage: "Dont Know 1"
},
{ type: "Processor3", usage: "DontKnow2"},
{ type: "Processor4", usage: "DontKnow3"}
]
}
]
},
{
name: "PC 2",
components: [
{
name: "My third piece of hardware",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor2", usage: "DontKnow2"},
{ type: "Processor3", usage: "DontKnow3"}
]
}
]
}];
//this.devices must not be changed!
}
});
Polymer({
is: 'my-distinct',
properties: {
inputs: {
type: String
},
outputs:{
computed: '_getDistincts(inputs, path)',
notify: true
},
path: {
type: String,
value: ""
}
},
_getDistincts(inputs, path){
let result = [];
for(let key in inputs){
if(inputs.hasOwnProperty(key)){
let x = inputs[key];
if(path && path != ""){
x = x[path];
}
if(result.indexOf(x) < 0){
result.push(x);
}
else{
//Already Exists
}
}
}
return result;
}
});
});
<head>
<base href="https://polygit.org/polymer+1.8.1/components/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<my-app></my-app>
As you can see, there is always "Processor1", "Processor2" and "Pocessor3" available although this is only the result of the last computers component. You can see the right result (but with duplicates) if you use the comment I made instead.
<dom-module id="my-app">
<template>
<ul>
<template is="dom-repeat" items="[[devices]]" as="device">
<li>[[device.name]]
<ul>
<template is="dom-repeat" items="[[device.components]]" as="component">
<li>[[component.name]]
<ul>
<!-- This is my code with using distinct -->
<my-distinct inputs="[[component.processors]]"
outputs="{{distinctProcessorNames}}"
path="type">
<template is="dom-repeat" items="[[distinctProcessorNames]]" as="processorName">
<li>[[processorName]]
<!-- Here I could iterate over all processors (filtered) and list their usages-->
</li>
</template>
</my-distinct>
<!-- This is my code without using distinct. -->
<!--template is="dom-repeat" items="[[component.processors]]" as="processor">
<li>[[processor.type]]
<ul>
<li>Used for [[processor.usage]]</li>
</ul>
</li>
</template-->
</ul>
</li>
</template>
</ul>
</li>
</template>
</ul>
</template>
</dom-module>
</body>
Demo
You are using 2 different Polymer custom elements <my-app> and <my-distinct>.
Therefore you should declare the second one with its proper <dom-module> statement:
<dom-module id="my-distinct">
<template>
<template is="dom-repeat" items="[[outputs]]" as="processorName">
<li>[[processorName]]
</template>
</template>
</dom-module>
Then use your computed property (based on the attribute value) outputs as the items value of <template is="dom-repeat">.
Demo below:
HTMLImports.whenReady(() => {
Polymer({
is: 'my-app',
ready: function(){
//In my real Problem this value comes from a websocket...
this.devices = [{
name: "PC 1",
components: [
{
name: "HDD1",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor1", usage: "DontKnow2"},
{ type: "Processor2", usage: "DontKnow3"}
]
},
{
name: "Another Piece Of Hardware",
processors: [
{
type: "Processor4",
usage: "Dont Know 1"
},
{ type: "Processor3", usage: "DontKnow2"},
{ type: "Processor4", usage: "DontKnow3"}
]
}
]
},
{
name: "PC 2",
components: [
{
name: "My third piece of hardware",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor2", usage: "DontKnow2"},
{ type: "Processor3", usage: "DontKnow3"}
]
}
]
}];
//this.devices must not be changed!
}
});
Polymer({
is: 'my-distinct',
properties: {
inputs: {
type: String
},
outputs:{
computed: '_getDistincts(inputs, path)', notify: true
},
path: {
type: String,
value: ""
}
},
_getDistincts(inputs, path){
let result = [];
for(let key in inputs){
if(inputs.hasOwnProperty(key)){
let x = inputs[key];
if(path && path != ""){
x = x[path];
}
if(result.indexOf(x) < 0){
result.push(x);
}
}
}
//console.log( result )
return result;
}
});
});
<head>
<base href="https://polygit.org/polymer+1.8.1/components/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<my-app></my-app>
<dom-module id="my-app">
<template>
<ul>
<template is="dom-repeat" items="[[devices]]" as="device">
<li>[[device.name]]
<ul>
<template is="dom-repeat" items="[[device.components]]" as="component">
<li>[[component.name]]
<ul>
<my-distinct inputs="[[component.processors]]" path="type">
</my-distinct>
</ul>
</li>
</template>
</ul>
</li>
</template>
</ul>
</template>
</dom-module>
<dom-module id="my-distinct">
<template>
<template is="dom-repeat" items="[[outputs]]" as="processorName">
<li>[[processorName]]
</template>
</template>
</dom-module>
</body>
As you discovered, properties declared inside a <dom-repeat> (i.e., lower in this case) are not scoped exclusively to the <dom-repeat> or its iterations. Thus, each iteration is overwriting the previous lower value, and lower remains available outside the <dom-repeat>.
However, you could achieve a similar scoping effect by attaching an output property to each item iterator in the <dom-repeat> if item is an Object.
For example, consider an <x-foo> element that takes an input array of Objects and passes each input to <my-tolower>, which writes a new value into _output (an attached property on the iterator):
<template is="dom-repeat" items="[[inputs]]" as="x">
<!-- Attach output to a new property on item (i.e., "_output") -->
<my-tolower input="[[x.input]]" output="{{x._output}}"></my-tolower>
</template>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
properties: {
inputs: Array
},
_toObjArray: function(inputs) {
// Map inputs into objects so that we can attach properties to each iterator in a dom-repeat
return inputs.map(input => ({input}));
}
});
Polymer({
is: 'my-tolower',
properties: {
input: {
type: String,
value: "",
},
output: {
computed: '_computeOutput(input)',
notify: true,
}
},
_computeOutput: function(input) {
return input.toLowerCase();
}
});
});
<head>
<base href="https://polygit.org/polymer+1.8.1/components/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo inputs='["aLPha", "brAVo", "CHarLiE", "DelTA", "epSiLoN"]'></x-foo>
<dom-module id="x-foo">
<template>
<template is="dom-repeat" items="[[_toObjArray(inputs)]]">
<!-- Attach output to a new property on item (i.e., "_output") -->
<my-tolower input="[[item.input]]" output="{{item._output}}"></my-tolower>
<div>
<span>[[item.input]] -> [[item._output]]</span>
</div>
</template>
</template>
</dom-module>
</body>
demo
In your code, you have a nested object, used in nested dom-repeats. The same technique from above can be applied at each nesting level, but your example only needs it at the innermost level. You could give <my-distinct>.outputs its own "local" variable by attaching the output to the iterator (i.e., component):
<my-distinct outputs="{{component.distinctProcessorNames}}" ...>
Then, you'd use that in your inner dom-repeat like this:
<template is="dom-repeat" items="[[component.distinctProcessorNames]]" ...>
HTMLImports.whenReady(() => {
Polymer({
is: 'my-app',
ready: function(){
this.devices = [{
name: "PC 1",
components: [
{
name: "HDD1",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor1", usage: "DontKnow2"},
{ type: "Processor2", usage: "DontKnow3"}
]
},
{
name: "Another Piece Of Hardware",
processors: [
{
type: "Processor4",
usage: "Dont Know 1"
},
{ type: "Processor3", usage: "DontKnow2"},
{ type: "Processor4", usage: "DontKnow3"}
]
}
]
},
{
name: "PC 2",
components: [
{
name: "My third piece of hardware",
processors: [
{
type: "Processor1",
usage: "Dont Know 1"
},
{ type: "Processor2", usage: "DontKnow2"},
{ type: "Processor3", usage: "DontKnow3"}
]
}
]
}];
}
});
Polymer({
is: 'my-distinct',
properties: {
inputs: {
type: String
},
outputs:{
computed: '_getDistincts(inputs, path)',
notify: true
},
path: {
type: String,
value: ""
}
},
_getDistincts(inputs, path){
let result = [];
for(let key in inputs){
if(inputs.hasOwnProperty(key)){
let x = inputs[key];
if(path && path != ""){
x = x[path];
}
if(result.indexOf(x) < 0){
result.push(x);
}
else {
//Already Exists
}
}
}
return result;
}
});
});
<head>
<base href="https://polygit.org/polymer+1.8.1/components/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<my-app></my-app>
<dom-module id="my-app">
<template>
<ul>
<template is="dom-repeat" items="[[devices]]" as="device">
<li>[[device.name]]
<ul>
<template is="dom-repeat" items="[[device.components]]" as="component">
<li>[[component.name]]
<ul>
<my-distinct inputs="[[component.processors]]" outputs="{{component.distinctProcessorNames}}" path="type">
</my-distinct>
<template is="dom-repeat" items="[[component.distinctProcessorNames]]" as="processorName">
<li>[[processorName]]</li>
</template>
</ul>
</li>
</template>
</ul>
</li>
</template>
</ul>
</template>
</dom-module>
</body>
your demo with updates
You commented that you don't want to clone any objects or modify the input. That's unfortunately not possible with the iterator-property technique described above. The better option in that case is to provide a template for <my-distinct>, which would encapsulate any transformations without affecting the input.
I just got started with Vue.js and here is what I'm doing: I am rendering a list of products, and each product has a name, a gender and a size. I'd like users to be able to filter products by gender, by using an input to type the gender.
var vm = new Vue({
el: '#product_index',
data: {
gender: "",
products: [{name: "jean1", gender: "women", size: "S"}, {name: "jean2", gender: "men", size: "S"}]
},
methods:{
updateGender: function(event){
this.gender = $(event.target).val()
}
}
}
)
<div v-for="product in products" v-if="...">
<p>{{product.name}}<p>
</div>
<input v-on:change="updateGender">
I managed to get the gender updated, but I have an issue with the filtering part. When the page loads, I don't want any filtering. In the documentation, they advise to use v-if but it doesn't seem compatible with this configuration.
If I use v-if, I could do:
v-if="product.gender == gender"
But again, this doesn't work when the page load because gender is empty.
I couldn't find a workaround for this.
How should I approach this issue ?
Use computed properties - something like this (Example bellow filter items by type)
const app = new Vue({
el: '#app',
data: {
search: '',
items: [
{name: 'Stackoverflow', type: 'development'},
{name: 'Game of Thrones', type: 'serie'},
{name: 'Jon Snow', type: 'actor'}
]
},
computed: {
filteredItems() {
return this.items.filter(item => {
return item.type.toLowerCase().indexOf(this.search.toLowerCase()) > -1
})
}
}
})
Template:
<div id="app">
<div v-for="item in filteredItems" >
<p>{{item.name}}</p>
</div>
<input type="text" v-model="search">
</div>
Demo: http://jsbin.com/dezokiwowu/edit?html,js,console,output
You can try v-if="!gender || product.gender == gender"
Just modified #Nora's answer.
You need to change in the template as:
<div id="product_index">
<div v-for="product in products" v-if="!gender || product.gender===gender">
<p>{{product.name}}<p>
</div>
<input v-on:change="updateGender">
</div>
and in JS file as:
var vm = new Vue({
el: '#product_index',
data: {
gender: "",
products: [{name: "jean1", gender: "women", size: "S"}, {name: "jean2", gender: "men", size: "S"}]
},
methods:{
updateGender: function(event){
this.gender = event.target.value
}
}
}
);
Working Demo: https://jsbin.com/qocuraquki/edit?html,js,console,output
computed: {
filteredItems() {
return this.allStartupData.filter(item => {
let byName =
item.name.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
let byDescription =
item.description.toLowerCase().indexOf(this.search.toLowerCase()) >
-1;
if (byName === true) {
return byName;
} else if (byDescription === true) {
return byDescription;
}
});
}
}
and then u can iterate through filteredItems like e.g
<v-flex v-for="(obj,index) in filteredItems" :key="index" xs12 md4>
computed: {
filteredItems() {
return myObject.filter((val) => {
return val.some((val) => val.toString().toLowerCase().includes(this.searchString))
})
}}
Iterate over the Object as already described above