Filtering a simple number array on vue - vue.js

I have a simple number array generated at random that is rendered by a v-for, I also want to be able to filter it by writing the desired numbers in a input, I do this by using the vanilla JS filter() method. However it returns the error
TypeError: "num.includes is not a function"
I don't know what am I doing wrong, here's the html:
new Vue({
el: "#app",
data: {
numberArray: [],
searching: ''
},
methods: {
random() {
this.numberArray = Array.from({
length: 40
}, () => Math.floor(Math.random() * 40));
},
search(){
return this.numberArray.filter((num) => num.includes(this.searching));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="random()">
Generate
</button>
<hr>
<input type="search" v-model="searching" placeholder="search">
<ul>
<li v-for="num in search">
{{ num }}
</li>
</ul>
</div>

includes() is a function defined on strings and arrays, not numbers.
Also search should be a computed property instead of a method.
Did you mean to do this:
computed: {
search() {
return this.numberArray.filter(num => String(num).includes(this.searching));
}
}

Related

display data set based on string content using vuejs

I want to display the designated data that is found for a particular code match. I have a data set that will come in model. I want if the data-set, subject property has the first 2-3 characters found in it, to display the corresponding name. Based on the first 3 characters begins with LA_, which is found in the first index, only the first set of content should appear (Name: Library Arts Department: ACSF-LA Identifier: 6774). I know i would need to slice the character off, with string slice, but what if sometimes the name has like LAX_ (SO I want to be sure to check if the subjects have any that match--). So basically to check everything before the first "_"
new Vue({
el: "#app",
data: {
Name:"LA_123_cc",
todos: [{"Name":"Library Arts","Identifier":"6774","Code":"AACSF-LA","Subjects":["LA_","AEL","APC","GAP","FAC","GLM","GS","MPT","PRO","WNM"]},
{"Name":"Violin Dance","Identifier":"6169","Code":"Avvv-VA","Subjects":["VA","VL","VPC","AAP","YAC","XLM","GXS","XPT","IRO","CNM"]}
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Name: {{Name}}</h2>
<ol>
<li v-for="todo in todos">
Name: {{todo.Name}} <br>
Department: {{todo.Code}}<br>
Identifier: {{todo.Identifier}}
</li>
</ol>
</div>
Create a computed property that uses Array.prototype.filter on the todos[]. The callback to filter() receives each array item, and returns true if the item should be in the result. In this callback, you can check if each item contains the leading characters (before the underscore) in the search string (LA in your example):
export default {
computed: {
computedTodos() {
const searchLetters = this.Name.split('_')[0].split('') /* get characters of first part of string before underscore */
.filter(x => /\w/.test(x)) /* keep only letters */
return this.todos.filter(item => {
/* check if each letter appears in order within the item's name */
let i = 0
return searchLetters.every(letter => {
i = item.Name.indexOf(letter, i)
return i > -1
})
})
}
}
}
Then update the template to use the computed prop instead of todos[]:
<!-- <li v-for="todo in todos"> -->
<li v-for="todo in computedTodos">
new Vue({
el: "#app",
data: {
Name:"LA_123_cc",
todos: [{"Name":"Library Arts","Identifier":"6774","Code":"AACSF-LA","Subjects":["LA_","AEL","APC","GAP","FAC","GLM","GS","MPT","PRO","WNM"]},
{"Name":"Violin Dance","Identifier":"6169","Code":"Avvv-VA","Subjects":["VA","VL","VPC","AAP","YAC","XLM","GXS","XPT","IRO","CNM"]}
]
},
computed: {
computedTodos() {
const searchLetters = this.Name.split('_')[0].split('').filter(x => /\w/.test(x))
return this.todos.filter(item => {
let i = 0
return searchLetters.every(letter => {
i = item.Name.indexOf(letter, i)
return i > -1
})
})
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input v-model="Name">
<h2>Name: {{Name}}</h2>
<ol>
<li v-for="todo in computedTodos">
Name: {{todo.Name}} <br>
Department: {{todo.Code}}<br>
Identifier: {{todo.Identifier}}
</li>
</ol>
</div>

How to use Vue computed setters with checkbox?

I have a list of checkboxes:
<ul>
<li v-for="system in payment_systems">
<input type="checkbox" :id="'ps-' + system.id" v-bind:value="system" v-model="checked_payment_systems">
<label :for="'ps-' + system.id">{{ system.translated.name }}</label>
</li>
</ul>
And I need to store checked items to Vuex so I use computed properties like this:
computed: {
checked_payment_systems: {
get() {
return this.$store.state.program.payment_systems;
},
set(payment_systems) {
console.log(payment_systems)
}
}
},
The problem is that in setter I get only true/false instead of object or array of objects.
the computed property you defined v-models with an input value. the set property will be called on with the input value.
in your example, you are binding the same get-set to all of your checkboxes. it should be done differently.
if i where you, i would remove the v-model and manually declare a function to happen onchange and a value, and pass them the a key, yo get the specific value in my object.
i made for you an example: https://jsfiddle.net/efrat19/p87ag0w3/1/
const store = new Vuex.Store({
state: {
program:{
payment_systems:{'paypal':false,'tranzila':false},
}
},
mutations:{
setPayment(state,{system,value}){
state.program.payment_systems[system]=value;
}
},
actions:{
setPayment({commit},{system,value}){
commit('setPayment',{system,value})
}
}
})
const app = new Vue({
store,
el: '#app',
data() {
},
computed: {
checked_payment_systems(){
return system=>
this.$store.state.program.payment_systems[system]
}
},
methods:{
setValue(system,value){
this.$store.dispatch('setPayment',{system,value})
}
}});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="
https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.0/vuex.js"></script>
<div id="app">
<li v-for="(value,system) in $store.state.program.payment_systems">
<input type="checkbox" :id="'ps-' + system.id" :checked="checked_payment_systems(system)" #change="setValue(system,$event.target.checked)">
<label :for="'ps-' + system.id" >{{system}}</label>
</li>
<br>
values in the store:
<br>
<br>
{{$store.state.program.payment_systems}}
</div>

VueJS: Why v-model does not work with a vuejs filter

Why v-model does not work with a filter getUppercase in <input v-model="filterText | getUppercase">
HTML
<template>
<div class="wrapper">
Check if fruit exist: <input v-model="filterText | getUppercase">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit }} </li>
</ul>
</div>
</template>
VueJS
export default {
name: "filterText",
data() {
return {
msg: "Welcome to Your Vue.js App",
filterText: "",
fruits: ["Apple", "Banana", "Orange", "PineApple", 'Pina Colada']
};
},
computed: {
filteredFruits: function() {
var vm = this;
return vm.fruits.filter(function(item) {
return item.match(vm.filterText)
});
}
},
filters: {
getUppercase: function(obj) {
return this.obj.toUpperCase();
}
}
};
I can see what you are trying to do, however, because of the two way binding when using v-model, it will be better to just apply the getUppercase filter when displaying.
Your template would be something like this:
<template>
<div class="wrapper">
Check if fruit exist: <input v-model="filterText">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit | getUppercase}} </li>
</ul>
</div>
</template>
But if you still wish to transform the filterText model value, you can use a directive. In that case, your VueJS code will be something like :
Vue.directive('getUppercase', {
twoWay: true, // this transformation applies back to the filterText
bind: function () {
var self = this;
self.handler = function () {
self.set(self.el.value.toUpperCase());
}
self.el.addEventListener('input', self.handler);
},
unbind: function () {
this.el.removeEventListener('input', this.handler);
}
});
Now use this directive in your template like :
<input v-model="filterText" v-get-uppercase="filterText">
It will do the same thing as <input v-model="filterText | getUppercase">
Two ways filters are replaced in vue.js please read the docs for more information.It is good to know.
However,as i understood you want to implement a search in array.See it in action here, or take a look below
<div id="app">
Check if fruit exist: <input v-model="filterText">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit }} </li>
</ul>
</div>
new Vue({
el: "#app",
data: {
filterText: "",
fruits: ["Apple", "Banana", "Orange", "PineApple", 'Pina Colada']
},
computed: {
filteredFruits() {
return this.fruits.filter(item => item.toLowerCase().match(this.filterText.toLowerCase()))
}
}
})

Vuejs 2.1.10 method passed as prop not a function

I'm very new to Vuejs and JS frameworks in general, so bear with me. I'm trying to call a method that resides in my root component from a child component (2 levels deep) by passing it as a prop, but I get the error:
Uncaught TypeError: this.onChange is not a function
at VueComponent._onChange (category.js:8)
at boundFn (vendor.js?okqp5g:361)
at HTMLInputElement.invoker (vendor.js?okqp5g:2179)
I'm not sure if I'm on the right track by assigning the prop to a method inside the child component, but see what you think:
index.js
var app = new Vue({
el: '#app',
data: function () {
return {
categories: [],
articles: []
}
},
methods: {
onChange: function () {
console.log('first one');
return function () {
console.log('second one');
}
}
},
});
The html:
<div id="app">
<sidebar :onChange=onChange :categories=categories></sidebar>
<varticles :articles=articles></varticles>
</div>
sidebar.js:
Vue.component('sidebar', {
props: ['onChange', 'categories'],
methods: {
_onChange: function () {
this.onChange();
}
},
template: `
<div class="sidebar">
<category v-for="item in categories" :onChange="_onChange" v-bind:category="item"></category>
</div>
`
});
category.js:
Vue.component('category', {
props: ['category', 'onChange'],
methods: {
_onChange: function () {
this.onChange();
}
},
template: `
<div class="category">
<h2>{{ category.name }}</h2>
<ul>
<li v-for="option in category.options">
<input v-on:change="_onChange" v-bind:id="option.tid" type="checkbox" v-model="option.checked">
<label v-bind:for="option.tid">{{ option.name }}</label>
</li>
</ul>
</div>
`
});
There's got to be simpler way to do this!
I'd suggest taking a look at this https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case. A simplified version of your code is in this fiddle https://jsfiddle.net/z11fe07p/641/
When writing props in your templates declare them without Capital letters.
A prop declared as onChange in your props is equivalent to on-change in your html.
<sidebar :on-change=onChange :categories=categories></sidebar>
Also I would suggest looking at events and non parent-child communication if you want a link between components that are more than 1 level deep. https://v2.vuejs.org/v2/guide/components.html?#Non-Parent-Child-Communication

How to handle getting new data even?

I have got Vue-JS app. After use click variable rasters_previews_list get new data. I would like to generate list with them. I can't understand which directive I should use to handle this even.
Here is my code:
var userContent = Vue.extend({
template: `
<div class="LayersMenuSectionContent" v-if="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li> // generate list here
<ul>
</div>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function()
{
},
methods:
{
}
});
Should I use v-on or v-if?
When rasters_previews_list is changed, list is autorendered in v-for.
new Vue({
el: '#app',
template: `
<div class="LayersMenuSectionContent" v-show="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li>
<ul>
</div>
<button #click="add">Add</button>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function(){ },
methods: {
add(){
this.rasters_previews_list.push({id: 'hello'},{id: 'world'});
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="app"></div>
Extra: You must use v-show instead of v-if for this case