How can I update value in input type text on vue.js 2? - vue.js

My view blade laravel like this :
<form slot="search" class="navbar-search" action="{{url('search')}}">
<search-header-view></search-header-view>
</form>
The view blade laravel call vue component (search-header-view component)
My vue component(search-header-view component) like this :
<template>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search" name="q" autofocus v-model="keyword" :value="keyword">
<span class="input-group-btn">
<button class="btn btn-default" type="submit" ref="submitButton"><span class="fa fa-search"></span></button>
</span>
<ul v-if="!selected && keyword">
<li v-for="state in filteredStates" #click="select(state.name)">{{ state.name }}</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'SearchHeaderView',
components: { DropdownCategory },
data() {
return {
baseUrl: window.Laravel.baseUrl,
keyword: null,
selected: null,
filteredStates: []
}
},
watch: {
keyword(value) {
this.$store.dispatch('getProducts', { q: value })
.then(res => {
this.filteredStates = res.data;
})
}
},
methods: {
select: function(state) {
this.keyword = state
this.selected = state
this.$refs.submitButton.click();
},
input: function() {
this.selected = null
}
}
}
</script>
If I input keyword "product" in input text, it will show autocomplete : "product chelsea", "product liverpool", "product arsenal"
If I click "product chelsea", the url like this : http://myshop.dev/search?q=product
Should the url like this : http://myshop.dev/search?q=product+chelsea
I had add :value="keyword" in input type text to udpate value of input type text, but it does not work
How can I solve this problem?
Update
I had find the solution like this :
methods: {
select: function(state) {
this.keyword = state
this.selected = state
const self = this
setTimeout(function () {
self.$refs.submitButton.click()
}, 1500)
},
...
}
It works. But is this solution the best solution? or there is another better solution?

Instead of timeout you can use vue's nextTick function.
I didn't checked your code by executing but seems its problem regarding timings as when submit is pressed your value isn't updated.
so setTimeout is helping js to buy some time to update value, but its 1500 so its 1.5 second and its little longer and yes we can not identify how much time it will take each time so we tempted to put max possible time, still its not perfect solution
you can do something like this. replace your setTimeout with this one
const self = this
Vue.nextTick(function () {
// DOM updated
self.$refs.submitButton.click()
})
nextTick will let DOM updated and set values then it will execute your code.
It should work, let me know if it works or not.

Related

How to use parameters in Axios (vuejs)?

Good morning Folks,
I got an API from where I am getting the data from.
I am trying to filter that with Axios but I don`t get the result that I am expecting.
I created a search box. I created a computed filter and that I applied on the Axios.
I would like to see only the searched results in my flexboxes (apart from the last three articles as a start)
<template>
<div id="app">
<div class="search-wrapper">
<input
type="text"
class="search-bar"
v-model="search"
placeholder="Search in the titles"
/>
</div>
<paginate
ref="paginator"
class="flex-container"
name="items"
:list="filteredArticles"
>
<li
v-for="(item, index) in paginated('items')"
:key="index"
class="flex-item"
>
<div id="image"><img :src="item.image && item.image.file" /></div>
<div id="date">{{ formatDate(item.pub_date) }}</div>
<div id="title">{{ item.title }}</div>
<div id="article" v-html="item.details_en" target="blank">
Explore More
</div>
</li>
</paginate>
<paginate-links
for="items"
:limit="2"
:show-step-links="true"
></paginate-links>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
items: [],
paginate: ["items"],
search: "",
};
},
created() {
this.loadPressRelease();
},
methods: {
loadPressRelease() {
axios
.get(
`https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5`,
{ params }
)
.then((response) => {
this.items = response.data.results;
});
},
formatDate(date) {
return moment(date).format("ll");
},
openArticle() {
window.open(this.items.details_en, "blank");
},
},
computed: {
axiosParameters() {
const params = new SearchParams();
if (!this.search) {
return this.items;
}
return this.items.filter((item) => {
return item.title.includes(this.search);
});
},
},
};
</script>
Here is the basic code for implementing vue watcher along with the debounce for search functionality.
import _ from "lodash" // need to install lodash library
data() {
return {
search: "",
};
},
watch:{
search: _.debounce(function (newVal) {
if (newVal) {
// place your search logic here
} else{
// show the data you want to show when the search input is blank
}
}, 1000),
}
Explanation:
We have placed a watcher on search variable. Whenever it detects any change in search variable, it will execute the if block of code if it's value is not empty. If the value of search variable goes empty, it will execute else block.
The role of adding debounce here is, it will put a delay of 1 sec in executing the block of code, as we don't want to execute the same code on every single character input in the search box. Make sure you install and import lodash library. For more info on Lodash - Debounce, please refer here.
Note: This is not the exact answer for this question, but as it is asked by the question owner in the comment section, here is the basic example with code.

Retrieve data attribute value of clicked element with v-for

I've made a datalist which is filled dynamically and it works correctly.
Now, I need listen the click event on the options to retrieve the data-id value and put it as value in the input hidden.
I already tried with v-on:click.native and #click but there is no response in the console.
Any idea? I'm just starting at Vue, hope you can help me.
Edit:
Looks like it doesn't even fire the function. I've tried v-on:click="console.log('Clicked')" but nothing happens.
<input type="hidden" name="id_discipline" id="id_discipline">
<input list="disciplines" id="disciplines-list">
<datalist id="disciplines">
<option
v-for="discipline in disciplines"
:key="discipline.id_discipline"
:data-id="discipline.id_discipline"
v-on:click="updateDisciplineId($event)"
>{{discipline.name}}</option>
</datalist>
methods: {
updateDisciplineId(event) {
console.log('clicked!);
}
},
Using datalist is not suited for what you want to acheive, however there's a workaround with a limitation.
Template:
<template>
<div>
<input
type="text"
name="id_discipline"
v-model="selectedID"
placeholder="Data id value of clicked"
/>
<input
#input="onChange"
list="disciplines"
id="disciplines-list"
class="form-control"
placeholder="Seleccionar disciplina"
/>
<datalist id="disciplines">
<option
v-for="discipline in disciplines"
:key="discipline.id_discipline"
:data-value="discipline.id_discipline"
>{{ discipline.name }}</option
>
</datalist>
</div>
</template>
Script Part:
<script>
export default {
data() {
return {
selectedID: "",
id_discipline: "",
disciplines: [
{
id_discipline: 1,
name: "Yoga"
},
{
id_discipline: 2,
name: "Functional"
}
]
};
},
methods: {
onChange(e) {
this.getID(e.target.value).then(
resposnse => (this.selectedID = resposnse)
);
},
async getID(value) {
let promise = new Promise((resolve, reject) => {
this.disciplines.forEach(item => {
if (item.name === value) resolve(item.id_discipline);
});
});
return await promise;
}
}
};
</script>
Here's a working Sandbox demo.
**Limitation: Discipline name (Yoga, functional) should be unique.

Vue.js - v-model not tracking changes with dynamic data?

I have the following form where the input fields are dynamically generated however when I update the fields the two way binding isn't happening - nothing is changing when i view the results in dev tools?
<template v-for="field in formFields" :key="field.name">
<div class="form-group" v-if="field.type == text'">
<label class="h4" :for="field.label" v-text="field.label"></label>
<span class="required-asterisk" v-if="field.required"> *</span>
<input :class="field.className"
:id="field.name"
:name="field.name"
type="text"
:maxlength="!!field.maxLength ? field.maxLength : false"
v-validate="{ required: field.required}"
:data-vv-as="field.label"
v-model="form[field.name]"/>
<span class="field-validation-error" v-show="errors.has(field.name)" v-text="errors.first(field.name)"></span>
</div>
</template>
And the following vue instance:
export default {
props: ['formFields'],
data: function () {
return {
form: {},
}
},
created: function() {
this.resetForm();
},
methods: {
resetForm: function() {
this.form = {
'loading': false
}
_.each(this.formFields, (field) => {
this.form[field.name] = field.value;
});
$('#editModal').modal('hide');
this.errors.clear();
}
}
}
When I hard code the values in the form it seems to work:
this.form = {
'loading': false,
'Subject': 'Test',
'Author': 'Roald Dahl'
}
So it seems like something to with the following which it doesn't like:
_.each(this.formFields, (field) => {
this.form[field.name] = field.value;
});
Could it be something to do with the arrow function. Any ideas chaps?
You're running into a limitation of Vue's reactivity, which is spelled out in the documentation
Instead of
this.form[field.name] = field.value;
use
this.$set(this.form, field.name, field.value);
Trying changing the following:
<div class="form-group" v-if="field.type 'text'"> ->
<div class="form-group" v-if="field.type == 'text'">
and the model data object like this
data: {
form: {},
},
https://jsfiddle.net/Jubels/eywraw8t/373132/ Example here. For testing purposes I removed the validation
Instead of
this.form[field.name] = field.value;
use
this.$set(this.form, field.name, field.value);
this.form.splice(field.name, 1, field.value)
or
Vue.set(this.form, field.name, field.value);
this.form.splice(field.name, 1, field.value)
More information in : https://v2.vuejs.org/v2/guide/list.html#Caveats

how to pass value in v-select in vue

i m new to vue (version 2.5) in my project i had install v-select i go through document and got confuse on few thing
here is my code
<template>
<div class="wrapper">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="name">Category</label>
<v-select label="category_desc" options="category"></v-select>
</div>
</div>
</div>
<button type="button" variant="primary" class="px-4" #click.prevent="next()">next</button>
</div>
</template>
<script>
export default {
name: 'Addproduct',
data () {
return {
category:[]
}
},
mounted() {
this.$http.get('http://localhost:3000/api/categories') .then(function (response) {
console.log(response.data);
this.category=response.data
})
.catch(function (error) {
console.log("error.response");
});
},
method:{
next(){
// console.log('value of v-selection not option' ) eg id 1 has 'country' so i want id 1 in method next() i.e in console.log
}
}
now my problem is that how i can pass this axios responded success value to v-select option and second this how i can get selected value of v-select for eg;- when user click on next button how i can get which value is selected in v-select
You need to bind options to category. i.e. v-bind:options or short hand :options I would also suggest you use a method to make your ajax call, and then call the method in mounted() instead. Also you probably want a v-model on that select so I added that in the example.
First in your template...
<v-select v-model="selectedCategory" label="category_desc" :options="category"></v-select>
Then in your script definition...
data(){
return{
category:[],
selectedCategory: null,
}
},
methods:{
getCategories(){
this.$http.get('http://localhost:3000/api/categories')
.then(function (response) {
this.category=response.data
}.bind(this))
.catch(function (error) {
console.log("error.response");
});
}
},
mounted(){
this.getCategories();
}
Here is a working jfiddle https://jsfiddle.net/skribe/mghbLyva/3/
Are we talking about this select component? The simplest usage is to put a v-model attribute on your v-select. Then this variable will automatically reflect the user selected value.
If you need to specify options, which you might, then you also need to provide a value prop and listen for #change.

this.$nextTick not working the way expected

I populate a dropdown, based on the result of another dropdown. And if i got a default value i want to set the second dropdown.
select country so i get al the country regions.
If i am on my edit page i already have the country id, so i trigger the ajax request on created() and populate the regions select.Ofc i have the region id and i would like to set it.
getRegions() {
let countryId = this.form.country_id;
if (countryId) {
axios.get('/getRegion/' + countryId)
.then(response => {
this.regions = response.data;
if (this.regions && this.form.country_region_id) {
this.$nextTick(() => {
$(".country_region").dropdown("set selected",
this.form.country_region_id).dropdown("refresh");
});
/*
setTimeout(() => {
$(".country_region").dropdown("set selected",
this.form.country_region_id).dropdown("refresh");
}, 1000);
*/
}
})
.catch(error => {
this.errors.push(error)
});
}
},
The code segment with the setTimeout is working 1sec later the correct value is selected.
Edit:
My dropdown actually got a wrapper component, so i can use v-model on it.
But the nextTick still doesnt seem to work.
<sm-dropdown v-model="form.country_region_id" class="country_region">
<input type="hidden" :value="form.country_region_id" id="country_region_id">
<div class="default text">Gebiet</div>
<i class="dropdown icon"></i>
<div class="menu">
<div v-for="region in regions" class="item" :data-value="region.country_region_id"
:key="region.country_region_id" >
{{ region.internal_name }}
</div>
</div>
</sm-dropdown>
Dropdown component:
<template>
<div class="ui fluid search selection dropdown" ref="input">
<slot></slot>
</div>
</template>
<script>
export default {
props: ['value'],
mounted() {
let self = this;
$(this.$el)
.dropdown()
.dropdown({
forceSelection: false,
onChange: function(value) {
self.$emit('input', value);
self.$emit('change');
}
}).dropdown("refresh")
;
}
}
</script>