Vue search while typing - vue.js

I have search field and I wish to have the results in real-time,
I have no issue with returning data or showing data but I need a way to send input value to back-end while user is typing it.
Code
HTML
<el-input placeholder="Type something" v-model="search">
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
Script
data() {
return {
search: '' // getting data of input field
}
},
I've tried to compute it but it didn't return data
computed : {
searchSubmit: {
get: function () {
console.log(this.search);
}
}
},
Any idea?

For side effects as calling backend you can use Watchers.
watch: {
search(value) {
yourApiCall(value)
}
}

Related

Able to display the result of a promise but length of the result appears as undefined

I'm new to vue/promise and I am struggling to understand why when I try to display the result of a promise I end up with the expected data but when I try to find out its length, it says undefined
When I try to display the alerts from displayAlerts() , I can see a list of alerts, 2 in total. However in computed within the title function ${this.displayAlerts.length} appears as undefined, I was expecting to see 2.
Does it have something to do with displayAlerts() resulting in a promise? How do I fix the code such that I get 2 instead of undefined?
The code is below:
<template>
<div>
{{displayAlerts}}
<li v-for="alert in alerts" class="alert">
{{alert['name']}}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null,
alert: new Alert(),
updatedAlert: new Alert(),
deletedAlert: new Alert(),
};
},
computed: {
...mapGetters("authentication",['token']),
...mapGetters("user",['profile']),
displayAlerts() {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
},
title () {
return `My Alerts (${this.displayAlerts.length})`
},
test2() {
return [1,2,3]
},
}
};
</script>
Something like this should work:
<template>
<div v-if="alerts">
<h4>{{ title }}</h4>
<li v-for="alert in alerts" class="alert">
{{ alert.name }}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null
}
},
computed: {
...mapGetters('authentication', ['token']),
...mapGetters('user', ['profile']),
title () {
// Handle the null case
const alerts = this.alerts || []
return `My Alerts (${alerts.length})`
}
},
methods: {
// This needs to be in the methods, not a computed property
displayAlerts () {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
}
},
// Initiate loading in a hook, not via the template
created () {
this.displayAlerts()
}
}
</script>
Notes:
Computed properties shouldn't have side-effects. Anything asynchronous falls into that category. I've moved displayAlerts to a method instead.
Templates shouldn't have side-effects. The call to load the data should be in a hook such as created or mounted instead.
title needs to access this.alerts rather than trying to manipulate the promise.
While the data is loading the value of alerts will be null. You need to handle that in some way. I've included a v-if in the template and some extra handling in title. You may choose to handle it differently.
I've added title to the template but that's just for demonstration purposes. You can, of course, do whatever you want with it.
I've assumed that your original displayAlerts function was working correctly and successfully populates alerts. You may want to rename it to something more appropriate, like loadAlerts.

NuxtJs where to declare a computed property

How can i declare a computed property using Nuxt ? or the equivalent ?
I am using NuxtJs and trying to use a category filter.
I want to filter by unique categories, and i am getting this error message:
Cannot read property 'filter' of undefined
I trying to adapt to Nuxtjs the exemple i found in this pen : https://codepen.io/blakewatson/pen/xEXApK
I declare this computed property below, first at pages/index.vue and after into .nuxt/App.js
filteredStore: function() {
var vm = this;
var category = vm.selectedCategory;
if(category=== "All") {
return vm.stores;
} else {
return vm.stores.filter(function(stores) {
return stores.category === category;
});
}
}
And i try to apply the filter into this list of checkboxes :
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStore" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="''+store.category">
{{store.category}}
</label>
</div>
</div>
I'm going to do some guessing at your code situation (based on the example you noted), so just let me know where I make an incorrect assumption. I would guess that something like the following could work for you... maybe you could provide additional details where I'm missing them.
With regards to your error Cannot read property 'filter' of undefined, that probably means your array of stores is undefined. I believe if you create the stores array as empty in the data section, you should at least have it available before your async call returns any results.
One possible thing to you can do to test if your filtering logic is working... is to uncomment the manually created data array that I've created below. It's like an inline test for your data structure and logic, removing the asynchronous retrieval of your data. This basically can check if the filter works without your API call. It would narrow down your issue at least.
export default {
data() {
return {
stores: [
// Let's assume you don't have any static stores to start on page load
// I've commented out what I'm guessing a possible data structure is
//
// Example possible stores in pre-created array
// { name: 'Zales', category: 'Jewelry', id: 1 },
// { name: 'Petco', category: 'Pet Shop', id: 2 },
// { name: 'Trip Advisor', category: 'Tourism', id: 3 },
// { name: 'Old Navy', category: 'Clothes', id: 4 }
],
selectedCategory: 'All'
}
},
computed: {
// Going to make some small js tweaks
filteredStores: () {
const vm = this;
const category = vm.selectedCategory;
if (category === "All") {
return vm.stores;
} else {
return vm.stores.filter(store => {
return store.category === category;
});
}
}
},
async asyncData({ $axios }) {
$axios
.$get('https://yourdomain.com/api/stores/some-criteria')
.then(response => {
this.stores = response.data;
})
.catch(err => {
// eslint-disable-next-line no-console
console.error('ERROR', err);
});
}
};
And then your HTML
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStores" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="`${store.category || ''}`">
{{store.category}}
</label>
</div>
</div>
ANYWAY This is all just a big guess and what your scenario is, but I figured I'd try to help shape your question some so that you could get a more meaningful response. In general, I'd suggest trying to provide as much detail as you can about your question so that people really can see the bits and pieces where things might have gone astray.
Don't touch anything in .nuxt Someone noted that above in a comment, and it's very important. Essentially that whole directory is generated and any changes you make in it can be easily overwritten.

Vue js dynamic update set/unset class

I have few inputs with submit button. Have some validation logic that adds 'has-error' class to input. How can i unset this class on focus?
Template:
<div class="input-styled badge-icon" :class="{ 'has-error': errors.email}">
<input type="text" #focus="delete errors.email" v-model="email" placeholder="example#gmail.com">
</div>
<button #click="submit">Submit</button>
JS
data() {
return {
errors: {},
email: ''
}
},
methods: {
submit(){
this.errors = {};
if(!this.email){
this.errors.email = 'Something';
}
}
}
I'm trying delete error property, trying #focus='errors.email="" ', but class 'has-error' disappears only when i'm typing something on inputs. #focus event works and i think that i should call some function that will update my DOM?
It is a good practice to move operations on component's data to functions. You can achieve desired validation reset, by creating a resetValidation function and binding it to focus event on input field.
Method itself should reset errors field to falsy values. Example below assumes, there are multiple input fields in the form. Each field should call resetVlidation method with corresponding error field name. If no field is provided, we can reset validation as whole:
resetValidation (field) {
if (field) {
this.errors = {
...this.errors,
[field]: ''
}
} else {
this.errors = {}
}
Please, check the working example below:
codesandbox

How to directly modify v-model value using directives?

I've got form with dynamic number of input fields and i need to transliterate data, passed to this fields in 'live'. I wrote custom directive which do all job, but there is an a error -> it converts all chars except last one (should be привет->privet, while привет->priveт). This is my source code
directives: {
transliterate: {
update(element, binding) {
element.value = tr(element.value)
}
}
}
This is PUG (Jade)
input(v-model='requestHotels.travellers[index].first_name', v-transliterate='true')
tr - just function, which transliterate from ru to en
I knew why this happening, but i can't solve it by myself. Any ideas?
1) Consider using computed property instead of directive. Personally, I don't like directives because they can add alot of useless complexity to your code. But there are some complex cases where they can be really useful. But this one is not one of them.
export default {
data: () => ({
tranliteratedValue: ""
}),
computed: {
vModelValue: {
get() {
return this.tranliteratedValue;
},
set(value) {
this.tranliteratedValue = transl.transform(value);
}
}
}
};
Full example: https://codesandbox.io/s/039vvo13yv?module=%2Fsrc%2Fcomponents%2FComputedProperty.vue
2) You can use filter and transliterate during render
filters: {
transliterate(value) {
return transl.transform(value);
}
}
Then in your template:
<p>{{ value | transliterate }}</p>
Full example: https://codesandbox.io/s/039vvo13yv?module=%2Fsrc%2Fcomponents%2FFilter.vue
3) Transparent wrapper technique (using custom component)
The idea behind transparent wrapper is that you should create custom component that behave as build-in input (and accepts the same arguments) but you can intercept events and change behaviour as you'd like. In your example - tranliterate input text.
<textarea
v-bind="$attrs"
:value="value"
v-on="listeners"
/>
computed: {
listeners() {
return {
...this.$listeners,
input: event => {
const value = transl.transform(event.target.value + "");
this.$emit("input", value);
}
};
}
}
Full example: https://codesandbox.io/s/039vvo13yv?module=%2Fsrc%2Fcomponents%2Finc%2FTransliteratedInput.vue
Read more about Transparent wrapper technique here https://github.com/chrisvfritz/7-secret-patterns/blob/master/slides-2018-03-03-spotlight-export.pdf
You can check all 3 working approaches here https://codesandbox.io/s/039vvo13yv

Vue.js - v-model with a predefined text

I have an input attribute that I want to have text from a source and is two-way binded
// messages.html
<input type="textarea" v-model="newMessage">
// messages.js
data () {
newMessage: ''
},
props: {
message: {
type: Object,
required: true,
default () {
return {};
}
}
// the message object has keys of id, text, and hashtag
I would like the initial value of input to be message.text. Would it be appropriate to do something like newMessage: this.message.text?
EDIT
I tried adding :value="message.text" in input but that didn't really show anything
Yes, you can reference the props in the data function.
data(){
return {
newMessage: this.message.text
}
}