How to detect wheter search input focused or not in vue-instantsearch? - vue.js

In my component Search.vue I need to detect whether search input focused or not in order to hide search results if cursor is elsewhere
I used vue-instantsearch
Here is the code of my custome component's template section
<template>
<ais-index index-name="getstarted_actors" :search-store="searchStore">
<div class="col-md-10 col-sm-9">
<ais-search-box :autofocus="true">
<div class="input-group" ref="searchInputGroup">
<ais-input placeholder="Find books..."
:class-names="{'ais-input': 'form-control'}" autofocus="true" >
</ais-input>
<span class="input-group-btn">
<ais-clear :class-names="{'ais-clear': 'btn btn-default'}">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</ais-clear>
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
</span>
</div>
</ais-search-box>
<ais-results v-show="searchStore.query.length > 0">
<template scope="{ result }">
<div v-on:click="searchResultClick(result)" class="found-item">
<a> <span>{{ result.name }}</span> <span>{{ result.rating }}</span></a><br/>
</div>
</template>
</ais-results>
</div>
</ais-index>
</template>

You can try:
<ais-input placeholder="Find books..."
:class-names="{'ais-input': 'form-control'}" autofocus="true"
#focus="onFocus"
>
</ais-input>
and your methods:
methods: {
onFocus() { console.log('Focused') }
}

Related

vuejs handle input change in loop

My question is if I am doing the below code correctly or is there a better way? I want to handle the change in any input values.
I have an object of options:
customOptions: {
1:"test 1",
2:"test 2",
3:"test 3",
}
and I am showing them in the template like this:
<div class="custom_options">
<div
class="row-fluid flex form-row"
v-for="(option, index) in customOptions"
:key="index"
>
<span>{{ index }}</span>
<span>
<input :value="option" :id="index" #change="handleChange" />
</span>
</div>
</div>
and finally my method:
handleChange(event) {
Vue.set(this.customOptions, event.target.id, event.target.value)
},
You could just use v-model like <input v-model="customOptions[index]"/> :
<div
class="row-fluid flex form-row"
v-for="(option, index) in customOptions"
:key="index"
>
<span>{{ index }}</span>
<span>
<input v-model="customOptions[index]"/>
</span>
</div>

VUEJS: Model not changing in for loop

The V-model:"question.answer" is the same for each loop.
The content of rating_questions is:
rating_question = [
{
"id":1,
"question":"How did you like this?",
"amount_of_stars":8,
"answer":0
},
{
"id":2,
"question":"Second question?",
"amount_of_stars":3,
"answer":0
}]
When I select an answer for the first question, the answer is saved in rating_question[0].answer but if I select an answer for the second question, it is also saved in rating_question[0].answer and not in rating_questions[1].answer as I would expect.
<template>
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="i" name="rating" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="i" >☆</label>
</span>
{{ rating_questions[index]['answer'] }}
{{index}}
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user', 'event', 'rating_questions'],
methods: {
sendRating() {
this.$emit('ratingsent', {
rating_questions: this.rating_questions
});
}
}
}
</script>
Your problem is not in Vue usage but how you use <input> and <label> HTML elements...
<input> id and <label> for attributes are assigned with simple number
1..question.amount_of_stars...which means first combo for every question will have id = 1, second 2 etc. Moreover you are using same name for every combo!
Now if you click on the label (star) in second question, browser just switch active combo on 1st question.
Try this:
<input :id="`rating-${question.id}-${i}`" :name="`rating-${question.id}`" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="`rating-${question.id}-${i}`" >☆</label>
Now:
every combo in the group (single question) will have same name (OK!)
every combo (and it's corresponding label) will have different id (OK!)
Also it's usually better to use :key together with v-for
new Vue({
data() {
return {
rating_questions: [
{
"id":1,
"question":"How did you like this?",
"amount_of_stars":8,
"answer":0
},
{
"id":2,
"question":"Second question?",
"amount_of_stars":3,
"answer":0
}]
}
}
}).$mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions" :key="question.id">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="`rating-${question.id}-${i}`" :name="`rating-${question.id}`" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="`rating-${question.id}-${i}`" >☆</label>
</span>
{{ question.answer }}
<div class="clear"></div>
</div>
</div>
</div>
</div>
</div>
The error was in my input id's...
Each new question had the same id's.
<template>
<div class="ratings">
<div class="rating" v-for="(question, index) in rating_questions">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars">
<input :id="'rating' + index + i" name="rating" v-model="question.answer" type="radio" :value="i" class="radio-btn hide" />
<label :for="'rating' + index + i" >☆</label>
</span>
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user', 'event', 'rating_questions'],
methods: {
sendRating() {
this.$emit('ratingsent', {
rating_questions: this.rating_questions
});
}
}
}
</script>
There is very trivial fix of this problem.
See you are modifying the props. In vuejs, props are not supposed to be updated. I hope you might have encountered some error in the console (not sure though, as sometimes in my case also it doesn't appear)
Please use this SFC file
<template>
<div class="ratings">
<!-- using the data variable rather than props -->
<div class="rating" v-for="(question, index) in questions" :key="index">
<div class="question">
{{ question.question }}
</div>
<div class="answer">
<div class="rating-stars">
<span v-for="i in question.amount_of_stars" :key="i">
<input
:id="i"
name="rating"
v-model="question.answer"
type="radio"
:value="i"
class="radio-btn hide"
/>
<label :for="i">☆</label>
</span>
{{ questions[index]["answer"] }}
{{ index }}
<div class="clear"></div>
</div>
</div>
</div>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendRating">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ["user", "event", "rating_questions"],
data() {
return {
questions: this.rating_questions, // because you can not change props in vuejs
};
},
methods: {
sendRating() {
this.$emit("ratingsent", {
rating_questions: this.questions,
});
},
},
};
</script>

VueJS v-model in v-for not reactive

Consider the following:
<ul class="park-list row row-pd">
<li class="col-12" v-for="(item, index) in list.items" v-bind:key="index">
<div class="park-note px-3 py-2">
<p class="font-italic" >
{{ item.notes }} <a v-bind:href="'#collapseNoteTest'+item.id"
data-toggle="collapse" role="button" aria-expanded="false"
v-bind:aria-controls="'#collapseNoteTest'+item.id">
<i class="svg-12 ic-cyan-path" v-html="icons['ic-edit']"></i></a>
</p>
<div class="collapse" v-bind:id="'collapseNoteTest'+item.id">
<div class="form-group">
<label for="exampleFormControlTextarea1">Note:</label>
<textarea class="form-control" v-model="item.notes" rows="3"></textarea>
</div>
<div class="form-row">
<div class="col-auto ml-auto">
<button type="button" class="btn btn-outline-primary" v-bind:href="'#collapseNoteTest'+item.id" data-toggle="collapse">Cancel</button>
</div>
<div class="col-auto">
<button class="btn btn-success mb-2" v-bind:href="'#collapseNoteTest'+item.id" data-toggle="collapse">Save</button>
</div>
</div>
</div>
</div>
</li>
</ul>
No matter what I do here, item.notes does not update when I enter text into the textarea. What am I doing wrong?

How to toggle nested checkboxes (options) on check parent checkbox in Vue Js

i have simple questions list. It has some options and those options has some nested suboptions.
So need to keep hidden all nested checkboxes until checks parent checkbox.
i tried to do it but could not get it work.
i have tried this so far:
For better understanding please have a look at this fiddle
<div id="app">
<h2>Questions:</h2>
<ul>
<li v-for="question in questions">
<div class="question">{{ question.question }}</div>
<div class="label__wrap" v-for="option in question.options">
<label>
<input type="checkbox" v-model="question.answer" :value="option.option">
<span>
{{ option.option }}
</span>
</label>
<div class="sub__label__wrap" v-for="opt in option.subOptions">
<label>
<input type="checkbox" v-model="option.subOptsAnswers" :value=" opt.option">
<span>
{{ opt.option }}
</span>
</label>
</div>
</div>
<br><br>
</li>
</ul>
</div>
Thanks.
Updated Fiddle : https://jsfiddle.net/rcam67b9/
check the answers array whether the selected answer exist
v-if="question.answer.indexOf(option.option) !== -1"
Final Code
<div id="app">
<h2>Questions:</h2>
<ul>
<li v-for="question in questions">
<div class="question">{{ question.question }}</div>
<div class="label__wrap" v-for="option in question.options">
<label>
<input type="checkbox" v-model="question.answer" :value="option.option">
<span>
{{ option.option }}
</span>
</label>
<div class="sub__label__wrap" v-for="opt in option.subOptions" v-if="question.answer.indexOf(option.option) !== -1">
<label>
<input type="checkbox" v-model="option.subOptsAnswers" :value=" opt.option">
<span>
{{ opt.option }}
</span>
</label>
</div>
</div>
<br><br>
</li>
</ul>
</div>

Using vue js with selectpicker

I'm using Vue.js to add multiple rows, each row contain two datetimepicker inputs and a bootstrap-select.
My problem is when I fill the inputs and click to add a new row the previous ones clear out, the reason is each time I add a new row I'm using setTimeout to referesh the selectpicker and the datetimepicker.
So I want to know if there is a way to trigger the last added element them without refreshing the previous ones.
Here is my code :
HTML
<div class="cols" id="app">
<ul style="list-style-type: none;">
<li>
<button style="float: right;margin-right: 20px;margin-top: 5px;" type="button" class="btn btn-success btn-xs" v-on:click="addRow()">
<i class="fa fa-plus"></i> Ajouter
</button>
</li>
<li v-for="(row, id) in rows">
<div class="form-inline cp-out" style="padding-bottom: 9px;border-radius:4px;background-color:white;margin-left:-20px;display:inline-block;width:100%;margin-top:10px;">
<div class="col-md-3">
<label :for="['time_start'+id]" class="control-label">start time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_start'+id]" data-link-format="hh:ii">
<input v-model="row.startTime" :name="'rows['+id+'][startTime]'" class="form-control" :id="['startTime' + id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-3">
<label :for="['time_end'+id]" class="control-label" style="margin-left:7px;">end time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_end'+id]" data-link-format="hh:ii">
<input v-model="row.endTime" :name="'rows['+id+'][endTime]'" class="form-control" :id="['endTime'+id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group select_group" style="margin-left:5px;">
<label :for="['status' + id]" class="control-label">Status</label>
<select data-width="100%" v-model="row.status" :name="'rows['+id+'][status]'" :id="['status' + id]" class="select_picker" data-live-search="true" multiple >
<option value="Status 1">Status 1</option>
<option value="Status 2">Status 2</option>
</select>
</div>
</div>
<div class="col-xs-1">
<button type="button" class="btn btn_delete btn-xs btn-danger" v-on:click="delRow(id)">
<i class="fa fa-remove"></i> delete
</button>
</div>
</div>
</li>
</ul>
</div>
JS
app = new Vue({
el: '#app',
data: {
rows: []
},
methods: {
addRow: function () {
this.rows.push({startTime: '', endTime: '', status: []});
setTimeout(function () {
$('.select_picker').selectpicker('refresh');
$('.form_time').datetimepicker({format: 'LT'});
}.bind(this), 10);
},
delRow: function (id) {
this.rows.splice(id, 1);
}
},created:function() {
this.addRow();
}
});
This is the example : https://jsfiddle.net/rypLz1qg/9/
You really need to write a wrapper component. Vue expects to control the DOM and not to have you making DOM-changing things like the *picker calls at arbitrary times. However, a component gives you the opportunity to tell your component how to interact with the DOM in each of its lifecycle hooks so that its behavior can be consistent. See the JavaScript tab on the wrapper component example page.