Change Computed Property on Click - arrays

Is it possible to add/change the computed property inside the "v-for" with a click event?
I would like to be able to display the list of food based on their category when I click on the proper button.
If I click on the "fruit" button it will be
<div v-for="food in fruitCategory" :key="food.name" class="card">
<p>{{ food.name }}</p>
</div>
and "candy" button it would be
<div v-for="food in candyCategory" :key="food.name" class="card">
<p>{{ food.name }}</p>
</div>
Is this a good approach?
Actual code below
<template>
<div class="layout">
<button>all</button>
<button>fruit</button>
<button>candy</button>
<div v-for="food in foods" :key="food.name" class="card">
<p>{{ food.name }}</p>
</div>
</div>
</template>
export default {
name: 'Food',
data() {
return {
foods: [
{ name: 'banana', category: 'fruit' },
{ name: 'orange', category: 'fruit' },
{ name: 'strawberry', category: 'fruit' },
{ name: 'gum', category: 'candy' },
{ name: 'fuzzy peach', category: 'candy' },
]
}
},
computed: {
fruitCategory: function() {
return this.foods.filter(function(food) {
return food.category === 'fruit'
})
}
},
candyCategory: function() {
return this.foods.filter(function(food) {
return food.category === 'candy'
})
}
}

You just need to store the category in data and then you can use the filter dynamically.
here as a working example with a cat array that checks if the category is included.
new Vue({
el: "#app",
name: 'Food',
data() {
return {
cat: ['fruit','candy'],
foods: [
{ name: 'banana', category: 'fruit' },
{ name: 'orange', category: 'fruit' },
{ name: 'strawberry', category: 'fruit' },
{ name: 'gum', category: 'candy' },
{ name: 'fuzzy peach', category: 'candy' },
]
}
},
computed: {
filtered: function() {
var cat = this.cat;
return this.foods.filter(function(food) {
return cat.indexOf(food.category) >= 0;
})
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<div class="layout">
<button #click="cat=['fruit', 'candy']">all</button>
<button #click="cat=['fruit']">fruit</button>
<button #click="cat=['candy']">candy</button>
<div v-for="food in filtered" :key="food.name" class="card">
<p>{{ food.name }}</p>
</div>
</div>
</div>

Related

Simple List Rendering in Vue with finding Index and passing props

so I do the beginning todo list stuff. I have this array
state() {
return {
news: [
{
id: 1,
title: "Titel 1",
text: "Beispieltext 1"
},
{
id: 2,
title: "Titel 2",
text: "Beispieltext 2"
}
]
}
},
I want to list items (NewsItem) in a list (NewsItemList) for every entry in the news-array. As simple as that.
This is my NewsItem
<template>
<div class="newsitem">
<h1
v-for="nachricht in news"
:key="nachricht.id"
>{{nachricht.title}}</h1>
<p
v-for="nachricht in news"
:key="nachricht.id"
>{{nachricht.text}}</p>
</div>
</template>
<script>
export default {
data() {
return {};
}
};
</script>
And this is my NewsItemList
<template>
<ul>
<li
v-for="nachricht in news"
:key="nachricht.id"
>
<NewsItem />
</li>
</ul>
</template>
<script>
import NewsItem from "#/components/NewsItem";
export default {
components: {
NewsItem,
},
computed: {
news() {
return this.$store.getters.getNewsList;
}
}
};
</script>
I want to map through my array in NewsItemList and give the information as props to my NewsItem. What is the simplest way?
In React, I needed to find the index with the findIndex() function. How can I do this in vue?
As I am just beginning, could you help me to find a simple way? Thank you!
Props
NewsItem
<template>
<div class="newsitem">
<h1>{{ title }}</h1>
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
props: {
title: String,
text: String,
},
data() {
return {}
},
}
</script>
Now you can use that in your NewsItemList
<template>
<ul>
<li v-for="nachricht in news" :key="nachricht.id">
<NewsItem :title="nachricht.title" :text="nachricht.text"/>
</li>
</ul>
</template>
If I understood you correctly, you just need to pass prop with news item object :
Vue.component('NewsItem', {
template: `
<div class="newsitem">
<h1 >{{item.title}}</h1>
<p>{{item.text}}</p>
</div>
`,
props: ['item']
})
new Vue({
el: "#demo",
data() {
return {
news: [
{
id: 1,
title: "Titel 1",
text: "Beispieltext 1"
},
{
id: 2,
title: "Titel 2",
text: "Beispieltext 2"
}
]
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<ul>
<li
v-for="nachricht in news"
:key="nachricht.id"
>
<news-item :item="nachricht"></news-item>
</li>
</ul>
</div>

arrange search filters using angular js

Problem: when i input "K", it filters both name and country that contain character "K".
Question: How can i filter the input characters only in "names.name"?
var app = angular.module("myApp", []);
app.controller("namesCtrl", function($scope) {
$scope.names = [
{ name:'Jani', country:'Norway' },
{ name:'Carl', country:'Sweden' },
{ name:'Margareth', country:'England' },
{ name:'Hege', country:'Norway' },
{ name:'Joe', country:'Denmark' },
{ name:'Gustav', country:'Sweden' },
{ name:'Birgit', country:'Denmark' },
{ name:'Mary', country:'England' },
{ name:'Kai', country:'Norway' }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="namesCtrl">
<p>
<input type="text" ng-model="test">
</p>
<ul>
<li ng-repeat="name in names | filter:test">
{{ name.name }}
</li>
</ul>
</div>
Try this
var app = angular.module("myApp", []);
app.controller("namesCtrl", function($scope) {
$scope.names = [
{ name:'Jani', country:'Norway' },
{ name:'Carl', country:'Sweden' },
{ name:'Margareth', country:'England' },
{ name:'Hege', country:'Norway' },
{ name:'Joe', country:'Denmark' },
{ name:'Gustav', country:'Sweden' },
{ name:'Birgit', country:'Denmark' },
{ name:'Mary', country:'England' },
{ name:'Kai', country:'Norway' }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="namesCtrl">
<p>
<input type="text" ng-model="test">
</p>
<ul>
<li ng-repeat="name in names | filter:{'name':test}">
{{ name.name }}
</li>
</ul>
</div>
Could you please use custom filter like below.
var app = angular.module("myApp", []);
app.controller("namesCtrl", function($scope) {
$scope.names = [{
name: 'Jani',
country: 'Norway'
},
{
name: 'Carl',
country: 'Sweden'
},
{
name: 'Margareth',
country: 'England'
},
{
name: 'Hege',
country: 'Norway'
},
{
name: 'Joe',
country: 'Denmark'
},
{
name: 'Gustav',
country: 'Sweden'
},
{
name: 'Birgit',
country: 'Denmark'
},
{
name: 'Mary',
country: 'England'
},
{
name: 'Kai',
country: 'Norway'
}
];
});
app.filter('searchTerm', function() {
return function(items, text) {
if (text) {
return items.filter(item => {
return item.name.toLowerCase().includes(text)
})
}
return items;
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="namesCtrl">
<p>
<input type="text" ng-model="test">
</p>
<ul>
<li ng-repeat="name in names | searchTerm:test">
{{ name.name }}
</li>
</ul>
</div>

How do you bind to name of array in object array?

I have an object with an array:
{
People: [
{
label: 'label1',
type: 'type1'
},
{
label: 'label2',
type: 'type2'
}],
Places: [
{
label: 'label1',
type: 'type1'
},
{
label: 'label2',
type: 'type2'
}]
}
I have an ng-repeat to create a list. I can bind to the properties inside People and Places but cannot bind to the name 'People' and 'Places'.
My html is something like this:
<div ng-repeat="category in vm.categories">
<button>{{category}}</button>
<ul>
<li ng-repeat="subcategory in category">
{{subcategory.label}}
</li>
</ul>
</button>
</div>
so subcategories are all fine but {{category}} doesn't return People/Places. How do I bind to the name of the array in the object?
Try this by using iterate over the keys and values with ng-repeat in AngularJS?
angular.module("test",[]).controller("testc",function($scope) {
$scope.categories = {
People: [
{
label: 'label1',
type: 'type1'
},
{
label: 'label2',
type: 'type2'
}],
Places: [
{
label: 'label1',
type: 'type1'
},
{
label: 'label2',
type: 'type2'
}]
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="testc">
<div ng-repeat="(key, value) in categories">
<button>{{key}}</button>
<ul>
<li ng-repeat="subcategory in value">
{{subcategory.label}}
</li>
</ul>
</button>
</div>
</div>

Dynamic Value Checkbox Vuejs 2

I can't get the value of the checkbox.
<li v-for="mainCat in mainCategories">
<input type="checkbox" :value="mainCat.merchantId" v-model="mainCategories.merchantId" id="mainCat.merchantId" #click="merchantCategoryId">
</li>
My Methods:
methods: {
merchantCategoryId: function() {
console.log(this.mainCategories.merchantId)
}
}
When it clicks I only get true and false for uncheck. TY
<div id="demo" >
<ul>
<li v-for="mainCat in mainCategories">
<input type="checkbox" :value="mainCat.merchantId" :id="mainCat.merchantId" v-model="checkedCategories" #click="check($event)"> {{mainCat.merchantId}}
</li>
</ul>
{{ checkedCategories }}
</div>
And in your script:
var demo = new Vue({
el: '#demo',
data: {
checkedCategories: [],
mainCategories: [{
merchantId: '1'
}, {
merchantId: '2'
}]
},
methods: {
check: function(e) {
if (e.target.checked) {
console.log(e.target.value)
}
}
}
})
Check this: https://v2.vuejs.org/v2/guide/forms.html#Checkbox
Working fiddle: http://jsfiddle.net/yMv7y/9206/
new Vue({
el: '#app',
data() {
return {
mainCategory: {
merchantIds: []
},
mainCategories: [{
merchantId: 1,
category: 'first category'
},
{
merchantId: 2,
category: 'second category'
}]
}
},
methods: {
merchantCategoryId: function() {
console.log(this.mainCategory.merchantIds)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<li v-for="mainCat in mainCategories">
<input type="checkbox"
:value="mainCat.merchantId"
v-model="mainCategory.merchantIds"
id="mainCat.merchantId"
#click="merchantCategoryId">
</li>
</div>
OR
new Vue({
el: '#app',
data() {
return {
mainCategories: [{
merchantId: 1,
category: 'first category'
},
{
merchantId: 2,
category: 'second category'
}]
}
},
methods: {
merchantCategoryId: function(event) {
console.log(event.target.value, event.target.checked)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<li v-for="mainCat in mainCategories">
<input type="checkbox"
:value="mainCat.merchantId"
id="mainCat.merchantId"
#change="merchantCategoryId($event)">
</li>
</div>
1.I observed both the mainCategories and v-model value v-model="mainCategories.merchantId" are the same.
You cannot access the marchantId of mainCategories, this is the mistake what you did apart from that nothing is wrong in the code sample to get the value of marchantId.
2 When your using $event in the click or change event function no need to use the v-model value.

AngularJS filter items by array of properties (checkbox)

I would like to filter the results by multiple properties.
My code:
(function () {
'use strict';
angular.
module('myApp', []).
filter('byFeatures', byFeatures).
controller('MyCtrl', MyCtrl);
function byFeatures() {
return function (items, conditions) {
if (Object.getOwnPropertyNames(conditions).length === 0) {
return items;
}
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
angular.forEach(item.features, function (feature) {
if (conditions[feature.name] !== undefined && conditions[feature.name][feature.value] !== undefined) {
if (conditions[feature.name][feature.value]) {
//filtered.push(item);
filtered[item.id] = item;
}
}
});
}
//console.log(filtered);
return filtered;
};
};
function MyCtrl($scope, $filter) {
$scope.allProducts = [{
id: 0,
name: "Product A",
features: [{
name: "Brand",
value: "Apple"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 1,
name: "Product B",
features: [{
name: "Brand",
value: "Apple"
},
{
name: "Memory",
value: "32"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 2,
name: "Product C",
features: [{
name: "Brand",
value: "Nokia"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 3,
name: "Product A",
features: [{
name: "Brand",
value: "Samsung"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
];
$scope.filters = [{
name: "Brand",
values: [
"Apple",
"Nokia",
"Samsung",
]
},
{
name: "Memory",
values: [
"16",
"32",
]
},
];
$scope.currentFilter = {};
$scope.$watch('currentFilter', function (newValue, oldValue, scope) {
//console.log(newValue);
$scope.products = $filter('byFeatures')($scope.allProducts, newValue);
}, true);
};
}());
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<title></title>
</head>
<body ng-app="myApp" class="ng-scope">
<div ng-controller="MyCtrl" style="width: 100%;">
<div style="width: 50%; float: left;">
<h2>Available Phones</h2>
<div ng-repeat="product in products">
<h3>
{{ product.name }}
</h3>
<ul>
<li ng-repeat="feature in product.features">
{{feature.name}} : {{feature.value}}
</li>
</ul>
</div>
</div>
<div style="width: 50%; float: left;">
<h2>Filters</h2>
<pre>{{currentFilter|json}}</pre>
<div ng-repeat="filter in filters">
<span>{{filter.name}}</span>
<ul>
<li ng-repeat="value in filter.values">
<input type="checkbox" ng-model="currentFilter[filter.name][value]"> {{value}}<br>
</li>
</ul>
</div>
</div>
</div>
</body></html>
If i filter by brand "Apple" are displayed 2 phones with brand "apple" (16 and 32 memory) - its ok. But if i add second filter by memory "16" - will must display only 1 phone apple with memory "16".
How to do it? . Link to JSFiddle
The problem is that you are doing the opposite from what you want: You are checking that the product contains a valid property for one of the items (Brand or Memory). What we need to do is check if the product has a valid property for all the items (Brand and Memory).
It would be enough to change the loop inside the function byFeatures in order to find every relevant condition (When its value is true!) and make sure that our product has one of the selected properties for each, Brand and Memory. Here you can see the right snippet:
(function () {
'use strict';
angular.
module('myApp', []).
filter('byFeatures', byFeatures).
controller('MyCtrl', MyCtrl);
function byFeatures() {
return function (items, conditions) {
if (Object.getOwnPropertyNames(conditions).length === 0) {
return items;
}
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i],
hasProperties = true;
angular.forEach(conditions, function (value, key) {
for (var i = 0; i < item.features.length; i++) {
if (item.features[i].name === key && (!value.hasOwnProperty(item.features[i].value) || !value[item.features[i].value])) {
for (var j in value) {
if (value[j]) {
hasProperties = false;
}
}
}
}
});
if (hasProperties) {
filtered.push(item);
}
}
//console.log(filtered);
return filtered;
};
};
function MyCtrl($scope, $filter) {
$scope.allProducts = [{
id: 0,
name: "Product A",
features: [{
name: "Brand",
value: "Apple"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 1,
name: "Product B",
features: [{
name: "Brand",
value: "Apple"
},
{
name: "Memory",
value: "32"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 2,
name: "Product C",
features: [{
name: "Brand",
value: "Nokia"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
{
id: 3,
name: "Product A",
features: [{
name: "Brand",
value: "Samsung"
},
{
name: "Memory",
value: "16"
},
{
name: "Color",
value: "Black"
}
]
},
];
$scope.filters = [{
name: "Brand",
values: [
"Apple",
"Nokia",
"Samsung",
]
},
{
name: "Memory",
values: [
"16",
"32",
]
},
];
$scope.currentFilter = {}; //$scope.filters;
$scope.$watch('currentFilter', function (newValue, oldValue, scope) {
$scope.products = $filter('byFeatures')($scope.allProducts, newValue);
}, true);
};
}());
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/script.js"></script>
<title></title>
</head>
<body ng-app="myApp" class="ng-scope">
<div ng-controller="MyCtrl" style="width: 100%;">
<div style="width: 50%; float: left;">
<h2>Available Phones</h2>
<div ng-repeat="product in products">
<h3>
{{ product.name }}
</h3>
<ul>
<li ng-repeat="feature in product.features">
{{feature.name}} : {{feature.value}}
</li>
</ul>
</div>
</div>
<div style="width: 50%; float: left;">
<h2>Filters</h2>
<pre>{{currentFilter|json}}</pre>
<div ng-repeat="filter in filters">
<span>{{filter.name}}</span>
<ul>
<li ng-repeat="value in filter.values">
<input type="checkbox" ng-model="currentFilter[filter.name][value]"> {{value}}<br>
</li>
</ul>
</div>
</div>
</div>
</body>
</html>
I also changed the way you were adding the new product to the filtered array. Otherwise, if the ID of the only item is 2, the array would keep the first 2 positions as 'undefined' and this would cause troubles through the ngRepeat iterations

Resources