Dynamically apply search filter on js data using vuejs - vue.js

I have a array list which contains column names. I want to write a search filter which will dynamically pick the value from the array and display all the rows and column. Search Filter should be with array contains column names.
Column name can be set dynamically
I have written code like below
Inside script tag
Its not working.. udata value is comming as array
export default {
el: '#apicall',
mixins: [Vue2Filters.mixin],
data()
{
return {
toggle: false,
userData: [],
search: "",
apidata: ['Id', 'Name', 'Version'],
currentvalue: '',
}
computed:
{
filteruserData: function(){
var self = this;
var list =[];
return this.userData.filter((udata) => {
for(var i in self.apidata)
{
list.push(udata[self.apidata[i]])
}
return list.toLowerCase().indexOf(self.search.toLowerCase()) != -1
});
},

I didn't really get exactly what you need. From what I understood you need to search for column name in apidata array using a filter. If your search filter find an element of your apidata array, you want to diplay the row values corresponding to column name your search filter found.
From elements you gave in your post, I don't understand what value you need to diplay and where are they supposed to come from.
Anyway, here is my try to help you.
Lets suppose that you have a data object that contains the row value to display.
The code below search inside the apidata array and diplay the value of the corrsponding attribute of the data object if anything has been found.
App.vue
<template>
<div id="app"><searchCompoenent :data="data"></searchCompoenent></div>
</template>
<script>
import searchCompoenent from "./components/searchComponent.vue";
export default {
name: "App",
data() {
return {
data: {
Id: [1, 9, 2, 3, 4, 5],
Name: ["name1", "name2"],
Version: ["2.0", "1.0.0", "1.1-beta"]
}
};
},
components: {
searchCompoenent
}
};
</script>
searchComponent.vue
<template>
<div>
<input v-model="search" placeholder="Search..." type="text" />
<button type="button" #click="searchColumn">Search!</button>
</div>
</template>
<script>
export default {
data() {
return {
search: "",
apidata: ["Id", "Name", "Version"]
};
},
props: ["data"],
methods: {
searchColumn() {
let result = this.apidata.find(element => {
return element === this.search;
});
if (result !== undefined) {
console.log(result);
console.log(this.data);
}
}
}
};
</script>

Related

Return model value formatted with Vue.js

I have a table in Vue.js application, listing a URL and an Id. This URL is defined by the user, so I created and input component, with a input text, using the URL as value and the Id as parameter. The v-model of this component is an array, where I need to store data as JSON objects like this:
{
"id": 1,
"url": "www.some-url.com"
}
How can I catch changes in the url field and return for its parent to append in an array?
Component:
<template>
<div class="row">
<div class="col-md-12">
<input type="text"
class="form-control"
v-model="value.url">
</div>
</div>
</template>
<script>
export default {
name: 'inputUrl',
props: {
url: {
type: [String],
description: 'URL'
},
id: {
type: Number,
description: 'Id'
}
},
components: {
}
data() {
return {
value: {
id: this.id,
url: this.default
}
};
},
methods: {
},
mounted() {
},
watch: {
}
}
</script>
Usage:
<inputUrl
:id="1"
url="www.some-url.com"
v-model="array">
</inputUrl>
I passed the array variable to the InputUrl component then used v-on directive to passing the current input value to a custom function for appending the new values to the array variable.
Here an example.

How to pass dynamic props with Vue

I need to pass props using Vue, I thought of JSON with object that includes name and value. I need to pass data to a different component but it changes as in each event the names and values change.
So for example I might have name: 'a' value: 'b', name: 'f' value: 'k' and in anorher event name: 'c' value: 'd'
my code that works but it work because i return hard coded data
data() {
return {
params: {
name:'bill',
value:'jones'
},
in child
#Component({
props:
{
urls: {
type: Object,
default: () => { return {name:'', value: ''} }
},
}
function with object params that i need to get the data from
getParams(url) {
paramsData[key] = value;
//console.log(key,value);
}
return params;
console.log(params)
You can use computed property names
emitEvent(name, value) {
let objectToEmit = {
[name]: value,
};
this.$emit("event-name", objectToEmit);
}
Now name and value will be set according to whatever you pass in emitEvent function.
You can read more about computed property names on below link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
You can pretty much pass anything through and you can do it in many ways. Here are 4 examples:
Note: for all options we are assuming you have a parent component that is using the following syntax
<example-component :name="somename" :value="somevalue"></example-component>
Option1: props as a list of array of strings. The values can be anything in JS i.e. numbers, strings, objects, functions
<template>
<div>
<p v-text="example"></p>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
prop: ['name','value']
}
</script>
Option 2: most common approach. Every prop to be a specific type of value. In these cases, you can list props as an object, where the properties’ names and values contain the prop names and types, respectively
<template>
<div>
<p v-text="example"></p>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
props: {
name: {
type: String,
required: false,
default: 'something'
},
value: {
type: Number,
required: true
}
},
}
</script>
Option 3: you can validate or in this case pass in an Object and defaults returned from a factory function so you will always have some value. You can even return validation validator: function (value) {...}
<template>
<div>
<!-- some value from EventServiceClass-->
<p v-text="example.name"></p>
</div>
</template>
<script>
import EventServiceClass from "./EventServiceClass";
export default {
name: "ExampleComponent",
props: {
example: {
type: Object,
default: function () {
return {name:'a', value: 'b'}
}
},
},
}
</script>
Option 4: a little more advanced but in this example we are bind get and set to input properties on a form, which we would use to create factory form components
<template>
<div>
<input
id="name"
type="text"
v-model="name"
class="form--input light"/>
</div>
</template>
<script>
export default {
name: "ExampleComponent",
props: {
name: {
type: String,
default: ""
}
},
computed: {
name: {
get() {
return this.value;
},
set(value) {
this.$emit("input", value);
}
}
}
}
</script>

Replace tag dynamically returns the object instead of the contents

I'm building an chat client and I want to scan the messages for a specific tag, in this case [item:42]
I'm passing the messages one by one to the following component:
<script>
import ChatItem from './ChatItem'
export default {
props :[
'chat'
],
name: 'chat-parser',
data() {
return {
testData: []
}
},
methods : {
parseMessage(msg, createElement){
const regex = /(?:\[\[item:([0-9]+)\]\])+/gm;
let m;
while ((m = regex.exec(msg)) !== null) {
msg = msg.replace(m[0],
createElement(ChatItem, {
props : {
"id" : m[1],
},
}))
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
}
return msg
},
},
render(createElement) {
let user = "";
let msg = this.parseMessage(this.$props.chat.Message, createElement)
return createElement(
'div',
{
},
[
// "hello",// createElement("render function")
createElement('span', '['+ this.$props.chat.Time+'] '),
user,
msg,
]
)
}
};
</script>
I thought passing createElement to the parseMessage method would be a good idea, but it itsn't working properly as it replaces the tag with [object object]
The chatItem looks like this :
<template>
<div>
<span v-model="item">chatITem : {{ id }}</span>
</div>
</template>
<script>
export default {
data: function () {
return {
item : [],
}
},
props :['id'],
created() {
// this.getItem()
},
methods: {
getItem: function(){
obj.item = ["id" : "42", "name": "some name"]
},
},
}
</script>
Example :
if the message looks like this : what about [item:42] OR [item:24] both need to be replaced with the chatItem component
While you can do it using a render function that isn't really necessary if you just parse the text into a format that can be consumed by the template.
In this case I've kept the parser very primitive. It yields an array of values. If a value is a string then the template just dumps it out. If the value is a number it's assumed to be the number pulled out of [item:24] and passed to a <chat-item>. I've used a dummy version of <chat-item> that just outputs the number in a <strong> tag.
new Vue({
el: '#app',
components: {
ChatItem: {
props: ['id'],
template: '<strong>{{ id }}</strong>'
}
},
data () {
return {
text: 'Some text with [item:24] and [item:42]'
}
},
computed: {
richText () {
const text = this.text
// The parentheses ensure that split doesn't throw anything away
const re = /(\[item:\d+\])/g
// The filter gets rid of any empty strings
const parts = text.split(re).filter(item => item)
return parts.map(part => {
if (part.match(re)) {
// This just converts '[item:24]' to the number 24
return +part.slice(6, -1)
}
return part
})
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<template v-for="part in richText">
<chat-item v-if="typeof part === 'number'" :id="part"></chat-item>
<template v-else>{{ part }}</template>
</template>
</div>
If I were going to do it with a render function I'd do it pretty much the same way, just replacing the template with a render function.
If the text parsing requirements were a little more complicated then I wouldn't just return strings and numbers. Instead I'd use objects to describe each part. The core ideas remain the same though.

Filtering a list of objects in Vue without altering the original data

I am diving into Vue for the first time and trying to make a simple filter component that takes a data object from an API and filters it.
The code below works but i cant find a way to "reset" the filter without doing another API call, making me think im approaching this wrong.
Is a Show/hide in the DOM better than altering the data object?
HTML
<button v-on:click="filterCats('Print')">Print</button>
<div class="list-item" v-for="asset in filteredData">
<a>{{ asset.title.rendered }}</a>
</div>
Javascript
export default {
data() {
return {
assets: {}
}
},
methods: {
filterCats: function (cat) {
var items = this.assets
var result = {}
Object.keys(items).forEach(key => {
const item = items[key]
if (item.cat_names.some(cat_names => cat_names === cat)) {
result[key] = item
}
})
this.assets = result
}
},
computed: {
filteredData: function () {
return this.assets
}
},
}
Is a Show/hide in the DOM better than altering the data object?
Not at all. Altering the data is the "Vue way".
You don't need to modify assets to filter it.
The recommended way of doing that is using a computed property: you would create a filteredData computed property that depends on the cat data property. Whenever you change the value of cat, the filteredData will be recalculated automatically (filtering this.assets using the current content of cat).
Something like below:
new Vue({
el: '#app',
data() {
return {
cat: null,
assets: {
one: {cat_names: ['Print'], title: {rendered: 'one'}},
two: {cat_names: ['Two'], title: {rendered: 'two'}},
three: {cat_names: ['Three'], title: {rendered: 'three'}}
}
}
},
computed: {
filteredData: function () {
if (this.cat == null) { return this.assets; } // no filtering
var items = this.assets;
var result = {}
Object.keys(items).forEach(key => {
const item = items[key]
if (item.cat_names.some(cat_names => cat_names === this.cat)) {
result[key] = item
}
})
return result;
}
},
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<button v-on:click="cat = 'Print'">Print</button>
<div class="list-item" v-for="asset in filteredData">
<a>{{ asset.title.rendered }}</a>
</div>
</div>

vue.js: Tracking currently selected row

I have a simple table where I would like to handle click elements:
<div class="row"
v-bind:class="{selected: isSelected}"
v-for="scanner in scanners"
v-on:click="scannerFilter">
{{scanner.id}} ...
</div>
JS:
new Vue({
el: "#checkInScannersHolder",
data: {
scanners: [],
loading: true
},
methods: {
scannerFilter: function(event) {
// isSelected for current row
this.isSelected = true;
// unselecting all other rows?
}
}
});
My problem is unselecting all other rows when some row is clicked and selected.
Also, I would be interested to know, it it is possible accessing the scanner via some variable of the callback function instead of using this as I might need to access the current context.
The problem is you have only one variable isSelected using which you want to control all the rows. a better approach will be to have variable: selectedScanner, and set it to selected scanner and use this in v-bind:class like this:
<div class="row"
v-bind:class="{selected: selectedScanner === scanner}"
v-for="scanner in scanners"
v-on:click="scannerFilter(scanner)">
{{scanner.id}} ...
</div>
JS
new Vue({
el: "#checkInScannersHolder",
data: {
scanners: [],
selectedScanner: null,
loading: true
},
methods: {
scannerFilter: function(scanner) {
this.selectedScanner = scanner;
}
}
});
I was under the impression you wanted to be able to selected multiple rows. So here's an answer for that.
this.isSelected isn't tied to just a single scanner here. It is tied to your entire Vue instance.
If you were to make each scanner it's own component your code could pretty much work.
Vue.component('scanner', {
template: '<div class="{ selected: isSelected }" #click="toggle">...</div>',
data: function () {
return {
isSelected: false,
}
},
methods: {
toggle () {
this.isSelected = !this.isSelected
},
},
})
// Your Code without the scannerFilter method...
Then, you can do:
<scanner v-for="scanner in scanners"></scanner>
If you wanted to keep it to a single VM you can keep the selected scanners in an array and toggle the class based on if that element is in the array or not you can add something like this to your Vue instance.
<div
:class="['row', { selected: selectedScanners.indexOf(scanner) !== 1 }]"
v-for="scanner in scanners"
#click="toggle(scanner)">
...
</div>
...
data: {
return {
selectedScanners: [],
...
}
},
methods: {
toggle (scanner) {
var scannerIndex = selectedScanners.indexOf(scanner);
if (scannerIndex !== -1) {
selectedScanners.splice(scannerIndex, 1)
} else {
selectedScanners.push(scanner)
}
},
},
...