Vue.js - Search function for JSON Object - html

I am new to Vue.js, and I want to add a search function for my site. The data is from an API Call and is displayed using vue.js too.
Display HTML Code:
<div class="row" v-for="items in data">
<div class="col-lg-4 col-md-6" data-toggle="modal" data-target="#exampleModal" user="'items'" #click="sendInfo(items)">
<a href="#" class="latest-product__item">
<div class="latest-product__item__pic">
<img src="img/item_image_placeholder.jpg" alt="">
</div>
<div class="latest-product__item__text">
<h6>{{items.item_name}}</h6>
<div v-for="variant in items.variants">
<div v-for="store in variant.stores">
<span>{{store.default_price}}</span>
</div>
</div>
</div>
</a>
</div>
And here's my Vue.js:
window.onload = function () {
const access_token = "";
new Vue({
el: '#item-data',
data () {
return {
data:[],
selectedUser:'',
itemCart: [],
search:'',
quantity: '',
cartCheckout: []
}
},
mounted () {
axios.get('**api call here**', {
headers : {
Authorization: 'Bearer ' + access_token
},
params: {
limit: 250
}
})
.then((response) => {
// handle success
this.data = response.data.items
console.log(response);
removeLoader();
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
});
},
computed:{
cartItem(){
return store.getters.printCart;
},
count(){
return store.state.cartCount;
},
},
methods:{
sendInfo(items) {
this.selectedUser = items;
},
addCart: function(cartdets){
store.commit('addCart', cartdets);
store.commit('addCount', 1);
}
}
})
}
What I want now is to add a search function to my displayed items. I already added v-model to my input tag. The items are dynamically displayed using vue and I want a search function for specific items.

You could create a computed property, maybe name it something like filteredItems, and make it loop through all of your items and save the items you want to display into an array and then return that array.
Then in your html use a v-for to display the items from filteredItems.

Related

On button click clear displayed text and call another function in VueJs

I'm fairly new to web development and vue.js.
I have an app where I enter an Id in and on button(search) click it is calling a method. This method makes an axios call to the controller and retrieves data as an object.
This data is displayed in tag (not sure if this approach is correct).
After this data is displayed, when the second time I enter another Id in the field and hit the button, it still displays the old text till it fetches the new data. Once new data is retrieved, it displays the new one.
I want to clear this data everytime I hit the button for search as well as call the vue function to fetch data.
I have tried clearing the data at the beginning of the vue function call but that didn't work.
<input type="text" placeholder="Enter the ID" v-model="mId" />
<button type="button" class="searchgray" v-on:click="SubmitId">Search</button>
<h4 style="display: inline">ID: {{queryData.Id}}</h4>
<strong>Device Status: </strong><span>{{queryData.deviceStatus}}</span>
<script>
export default {
components: {
'slider': Slider,
Slide
},
props:['showMod'],
data() {
return {
mId '',
queryData: {},
}
},
methods: {
SubmitId: function () {
this.queryData = {}
axios.get('/Home/SearchId?Id=' + this.mId)
.then(response => response.data).then(data => {
this.queryData = data
}).catch(err => {
this.queryData = {}
this.mId = ''
alert(`No records found anywhere for the given mId`)
});
}
}
</script>
So in the above code, when I hit the Search button, it calls the SubmitId function and returns queryData. Now when I enter a new mId in input field and hit serach button it continues to display the querydata associated with the old mId till the fetching of data is completed and new query data for the new mId is returned.
I was looking for a way to clear the screen text everytime I hit the button. So I also tried doing queryData={} before the axios call, but it didn't help.
Help appreciated.
new Vue({
el: '#app',
props: [
'showMod'
],
data() {
return {
mId: '',
queryData: {}
}
},
methods: {
async SubmitId () {
const axiosRequest = () => new Promise((resolve, reject) => {
const obj = {
Id: Math.random(),
deviceStatus: Math.random()
}
setTimeout(() => {
resolve(obj)
// reject('Not Found')
}, 2000)
})
try {
this.queryData = {}
this.queryData = await axiosRequest()
} catch (err) {
this.mId = ''
alert('No records found anywhere for the given mId')
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
v-model="mId"
type="text"
placeholder="Enter the ID"
/>
<button
v-on:click="SubmitId"
type="button"
class="searchgray"
>
Search
</button>
</br>
<h4 style="display: inline">
ID: {{ queryData.Id }}
</h4>
</br>
<strong>Device Status: </strong>
<span>{{ queryData.deviceStatus }}</span>
</div>

How to use Filter with ReactJS to prevent duplicates in an array from being displayed

I have a ReactJS page with three dropdown list, two of the dropdown list are displaying duplicate values. The values are being consumed from a json file. I researched using filter to remove the duplicates, but I'm unsure as to how I'm to apply it to my array when using React JS along with Fetch.
I created a function which employs the filter method, but I'm uncertain as to how I'm to implement it onto data: [], which contains the data consumed from the json file. This is the sample json file: https://api.myjson.com/bins/b1i6q
This is my code:
import React, { Component } from "react";
class Ast extends Component {
constructor() {
super();
this.state = {
data: [],
cfmRateFactor: "10"
};
} //end constructor
change = e => {
this.setState({
[e.target.name]: e.target.value
});
}; //end change
removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.clientName === elem.clientName)) {
result.push(elem);
}
return result;
} , []);
}
componentWillMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
/*body: JSON.stringify({
username: '{userName}',
password: '{password}'
})*/
}) /*end fetch */
.then(results => results.json())
.then(data => this.setState({ data: data }));
} //end life cycle
render() {
console.log(this.state.data);
return (
<div>
<div className="container">
<div className="astContainer">
<form>
<div>
<h2>Memeber Selection:</h2>
{["clientName", "siteName", "segmentName"].map(key => (
<div className="dropdown-padding">
<select key={key} className="custom-select">
{this.state.data.map(({ [key]: value }) => (
<option key={value}>{value}</option>
))}
</select>
</div>
))}
</div>
<div className="txt_cfm">
<label for="example-text-input">Modify CFM Rate Factor:</label>
<input
class="form-control"
type="textbox"
id="cfmRateFactor"
name="cfmRateFactor"
value={this.state.cfmRateFactor}
onChange={e => this.change(e)}
/>
</div>
<div>
<div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
export default Ast;
Could I please get some help with this? I'm still very new to using React JS.
You could use Map, it's a data structure for keeping key-value pairs. It will give you best performance for large data.
removeDuplicates(arr) {
const map = new Map();
arr.forEach(v => map.set(v.abc_buildingid, v)) // having `abc_buildingid` is always unique
return [...map.values()];
}
// this hook is better to start fetching data than componentWillMount
componentDidMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
})
.then(results => results.json())
.then(data => this.setState({ data: this.removeDuplicates(data) })); // use the defined method
} //end life cycle
filter won't solve your problem. But reduce will.
You could have the following :
function removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.abc_buildingid === element.abc_buildingid)) {
result.push(elem);
}
return result;
} , []);
}

How to add two methods on a #click event using vue.js?

This is my code and i basically want to add CHANGEBUTTONS to the on click event that looks like #click.
<button #click="enviarform2" value="Delete from favorites" style="font-weight: 700;color:#428bca;margin-left:30px;height:30px;border-radius:4px" name="delete" v-else>Delete from favorites</button>
<script>
new Vue({
el:'#app',
data:{
show: true,
paletteid : <?=$palette_id;?>,
action: "add",
action2: "delete",
number: ""
},
methods: {
enviarform: function() {
axios.post('/validarfavorite.php', {
paletteid: this.paletteid,
action: this.action
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
this.number = "Yours plus ";
},
enviarform2: function() {
axios.post('/validarfavorite.php', {
paletteid: this.paletteid,
action2: this.action2
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
this.number = "Minus yours plus ";
},
changebuttons: function() {
this.show = !this.show;
}
}
});
</script>
I have tried with method 1 and method 2 and handler but it didnt work. Hope you know!
You can separate the calls using a ; (or the comma operator):
<button #click="#click="m1(); m2()">my button</button>
<button #click="#click="m1(), m2()">my button</button>
But if your code is used in more than one place, though, the best practice (the "cleanest approach") is to create a third method and use it instead:
<button #click="mOneAndTwo">my button</button>
Demo:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
methods: {
m1: function() { this.message += "m1"; },
m2: function() { this.message += "m2"; },
mOneAndTwo: function() {
/* call two methods. */
this.m1();
this.m2();
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ message }}</p>
<button #click="m1(); m2()">call two methods using ;</button><br>
<button #click="m1(), m2()">call two methods using ,</button><br>
<button #click="mOneAndTwo">call two methods using a third method</button><br>
</div>
The easiest way to do it is:
<button v-on:click="method1(); method2();">Continue</button>
Cant you simply call the methods inside the functions?

Vuejs component does not render immediately

I have a vue app and a component. The app simply takes input and changes a name displayed below, and when someone changes the name, the previous name is saved in an array. I have a custom component to display the different list items. However, the component list items do not render immediately. Instead, the component otems render as soon as I type a letter into the input. What gives? Why would this not render the list items immediately?
(function(){
var app = new Vue({
el: '#app',
components: ['name-list-item'],
data: {
input: '',
person: undefined,
previousNames: ['Ian Smith', 'Adam Smith', 'Felicia Jones']
},
computed: {
politePerson: function(){
if(!this.person) {
return 'Input name here';
}
return "Hello! To The Venerable " + this.person +", Esq."
}
},
methods: {
saveInput: function(event){
event.preventDefault();
if(this.person && this.previousNames.indexOf(this.person) === -1) {
this.previousNames.push(this.person);
}
this.setPerson(this.input);
this.clearInput();
},
returnKey: function(key) {
return (key + 1) + ". ";
},
clearInput: function() {
this.input = '';
},
setPerson: function(person) {
this.person = person;
}
}
});
Vue.component('name-list-item', {
props: ['theKey', 'theValue'],
template: '<span>{{theKey}} {{theValue}}</span>'
});
})()
And here is my HTML.
<div id="app">
<div class="panel-one">
<span>Enter your name:</span>
<form v-on:submit="saveInput">
<input v-model="input"/>
<button #click="saveInput">Save</button>
</form>
<h1>{{politePerson}}</h1>
</div>
<div class="panel-two">
<h3>Previous Names</h3>
<div>
<div v-for="person, key in previousNames" #click='setPerson(person)'><name-list-item v-bind:the-key="key" v-bind:the-value="person" /></div>
</div>
</div>
</div>
You are not defining your component until after you have instantiated your Vue, so it doesn't apply the component until the first update.

Re-initialise directive on controller

I have a carousel that loads a bunch of items from an array, but a directive is being used to show the carousel.
I want to remove an item from a list such as "street parties" if something gets selected, but as the list of items seems to binded to a directive how can reload the directive? I have seen similar questions but I cant seem to get anything to work yet.. Thank you.
In my controller I have the various items like this
this.eventProducts.push({
link: "/quote/bar-and-bat-mitzvah-insurance",
image: "/Content/Images/policies/bar-mitzvah.jpg",
name: "Bar and Bat Mitzvahs"
});
this.eventProducts.push({
link: "/quote/street-party-insurance",
image: "/Content/Images/policies/street-party.jpg",
name: "Street Parties"
});
this.eventProducts.push({
link: "/quote/conference-and-meetings-insurance",
image: "/Content/Images/policies/conference.jpg",
name: "Conferences and Meetings"
});
Then I have this directive which sets the carousel
angular.module("App")
.controller("HomepageController", HomepageController)
.config(["$routeProvider", HomepageController.routing])
.directive("owlCarousel", () => {
return {
restrict: "E",
transclude: false,
link: (scope:any) => {
scope.initCarousel = (element) => {
// provide any default options you want
var defaultOptions = {
};
var customOptions = scope.$eval($(element).attr("data-options"));
// combine the two options objects
for (var key in customOptions) {
defaultOptions[key] = customOptions[key];
}
// init carousel
(<any>$(element)).owlCarousel(defaultOptions);
};
}
};
})
.directive("owlCarouselItem", [() => {
return {
restrict: "A",
transclude: false,
link: (scope, element) => {
// wait for the last item in the ng-repeat then call init
if (scope.$last) {
scope.initCarousel(element.parent());
}
}
};
}]);
And in the HTML the items are being loaded like this
<div class="row homepage-events">
<div class="homepage-heading"><h2 class="text-center">A Selection of our Most Popular Event Insurance Policies</h2></div>
<data-owl-carousel class="owl-carousel" data-options="{navigation: false, pagination: true, rewindNav : true}">
<div class="carousel-item" owl-carousel-item="" data-ng-repeat="product in ::homepageController.eventProducts">
<div class="">
<div class="thumbnails thumbnail-style thumbnail-kenburn">
<div class="thumbnail-img">
<div class="overflow-hidden">
<a class="" href="{{::product.link}}">
<img data-ng-src="{{::product.image}}" alt="{{::product.altText}}" />
</a>
</div>
<a class="btn-more2 hover-effect">Insurance for</a>
<a class="btn-more hover-effect" data-ng-href="{{::product.link}}">{{::product.name}}</a>
</div>
</div>
</div>
</div>
</data-owl-carousel>
</div>