I have a text field with various events. All events are working, but not #keydown.esc.
I would like to differ between #blur and #keydown.esc. Escape should always do something and #blur only sometimes.
Found this code codepen.io/whitelynx/pen/wGvmdW
that shows the key code for every key, but not for escape.
Is there anything special with #keydown.esc in vue js 3? That was not an issue in version 2.
My element
<input type="text" v-model="searchQuery" #keyup="searchItems" #paste="searchItems" #keydown.down="arrowDown" #keydown.up="arrowUp" #keydown.enter="selectIndex"
#keyup.,="selectIndex" #keydown.esc="closeSearch" #blur="maybeCloseSearch"
#focus="initSearch" placeholder="Search …" autocomplete="off" \>
I tried to remove all the other events and only #keydown.esc, but that makes no difference
"Solution": I found out that my browser extension Vimium i causes this problem
Fix the error:
wrong end of the input tag
\>
Define all methods
It works!
Playground
const App = {
data() { return { searchQuery: null } },
methods: {
initSearch: () => console.log('initSearch'),
closeSearch: () => console.log('closeSearch'),
maybeCloseSearch: () => console.log('maybeCloseSearch'),
}
}
const app = Vue.createApp(App);
app.mount('#app');
#app { line-height: 2; }
[v-cloak] { display: none; }
<div id="app">
<input type="text" v-model="searchQuery" #keydown.esc="closeSearch" #blur="maybeCloseSearch" #focus="initSearch" placeholder="Search …" autocomplete="off" />
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
Related
I have a component, which is essentially an input/select hybrid field, which allows users to type in the input field, and select items from the dropdown, based on their query.
It works perfectly fine on most devices I've tried, i.e. as the user types something into the input field, the list of items updates and only shows those items which contain that piece of string.
Except the Chrome browser on my Android device - as you type, the list doesn't seem to update, unless I press the "space bar". Very strange. Anyone have any ideas why this might be?
Here is the code in <script setup>:
const props = defineProps([ 'items', 'searchBy' ])
const searchTerm = ref('')
const itemsToShow = computed(() => {
if (props.items) {
if (searchTerm.value) {
return props.items.filter(el => {
if (props.searchBy) {
return el[props.searchBy].toUpperCase().indexOf(searchTerm.value.toUpperCase()) > -1
}
return el.toUpperCase().indexOf(searchTerm.value.toUpperCase()) > -1
})
} else {
return props.items
}
} else {
return []
}
})
And the HTML:
<input
type="text"
class="input"
v-model="searchTerm"
placeholder=" "
/>
<div class="items-list">
<div
v-for="item in itemsToShow"
:key="item"
#click="() => handleAdd(item)"
class="item text"
>
{{ item }}
</div>
<div
v-if="!itemsToShow.length"
class="text"
>
No items match searched term
</div>
</div>
UPDATE:
I've investigated a little, and it seems the searchTerm ref, isn't updating properly, even though its bound using v-model... Still no idea why though.
I've ran into this issue before.
It seems that on certain devices, the v-model waits for a change event, instead of an input one.
Apparently, it's to do with the input method editor (IME) for the specific device.
You can check a discussion about this at https://github.com/vuejs/core/issues/5580
The workaround is to simply bind the input field with value and listen for the input event manually, e.g.
<input
type="text"
class="input"
:value="searchTerm"
#input="(e) => searchTerm = e.target.value"
placeholder=" "
/>
I am using the latest version of Alpine. I need to set focus on the input searchbox as soon as it become visible. Here is my code for reference.
<div x-data="{search: false}">
<button x-on:click="search = true">Click to open search box</button>
<div x-data="searchwidget" x-show="search">
<input type="search" x-model="term" x-ref="searchInput" />
</div>
</div>
Data handler for search input
document.addEventListener('alpine:init', () => {
Alpine.data('searchwidget', () => ({
term: "",
}));
});
I tried to put $refs.searchInput.focus() on button element, but its not working.
You have an error at the button: you need to use x-on:click="search = true" or the shorthand syntax: #click="search = true". Furthermore, Alpine.js have an official focus plugin. With this plugin it is very easy to set the focus based on some condition. In your case you just need to put x-trap="search" to the input element, so Alpine.js will set the focus to the input element when search becomes true.
<input type="search" x-model="term" x-trap="search" />
Edit:
Without the focus plugin, you need to create a watcher in the init() method and set focus on the input element in the $nextTick() magic property:
<div x-data="{search: false}">
<button #click="search = true">Click to open search box</button>
<div x-data="searchwidget" x-show="search">
<input type="search" x-model="term" x-ref="searchinput" />
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('searchwidget', () => ({
term: "",
init() {
this.$watch('search', (value) => {
this.$nextTick(() => {
if (value) {
this.$refs.searchinput.focus()
}
})
})
}
}));
})
</script>
How can I pass the input value from my html to my vue method called checkEx
ist() ? I would like to retrieve that value within my checkExist() method. Could any advice how I can do this? I am still new to vue.
HTML:
<input type="text" class="form-control" placeholder="Email*" v-model="form.email" v-validate="'required|email'" v-on:change="checkExist">
VUE ELEMENT:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
checkExist:function(){
}
}
})
First you need to define form:{email:"", ...} in the data as well.
Pass $event inside checkExist() .
Something like this,
function callMe() {
var vm = new Vue({
el: '#root',
data: {
form:{email:""},
email:""
},
methods: {
checkExist(event){
this.email=event.target.value;
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<input type="text" #input="checkExist($event)" class="form-control" placeholder="Email*" v-model="form.email">
<p>email: {{email}}</p>
</div>
The v-model should already bind that input event.
But you can pass the event to v-on:change like this:
v-on:change="event => checkExist(event)"
Check exist would need to accept the event as a parameter.
The value of the input will now be accessible inside the vue function via event.target.value.
checkExist: function(event){
let value = event.target.value
}
Simpler even more, you don't need to pass the entire event to your handler function.
#change="checkExist($event.target.value)"
.
checkExist: function(value){
}
We could do it in ES6 syntax without using 'v-model' as below
<input v-on:change="(event) => inputValue = event.target.value" :value="inputValue" type="text"/>
On Android the length of v-model is returning 0 on keyup unless its a number or the space bar key. Does anyone know why that is and how to make it fire the keyup event no matter what key it is and get the length? Here is a cleaned up version of what I have:
<template>
<div class="typeahead">
<input
v-model="query"
v-on:keyup="suggestTerms"
>
</div>
</template>
<script>
export default {
data () {
return {
query: '',
}
},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
}
</script>
P.S. This works on every browser and device except Android.
There have been instances when v-model didn't update on mobile in some cases. Issue on Forum (current), Another from Forum
You can also code the v-model explicitly, it works in both android and pc.
function callMe(){
var vm = new Vue({
el : '#root',
data : {query : ''},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<h3>Decomposed</h3>
<div>
<input type='text' :value='query' #input='evt=>query=evt.target.value' v-on:keyup="suggestTerms">
<b>{{query}}({{query.length}})</b>
</div>
</div>
I'm trying to figure out where is the best place to run a jQuery plugin that replaces a textarea (with a reactive value). It needs to be called after the textarea has been assigned the value.
I've tried various places. The most correct place I've tried seems to be in the templates onAfterAction callback, in a Meteor.defer. This works about 95% of the time.
Something like this:
MyController = RouteController.extend({
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
},
onAfterAction: function () {
Meteor.defer(function () {
$('.make-wysiwyg').wysiwyg();
});
}
});
However, occasionally it doesn't. If I start bouncing between posts really quick, occasionally one will apparently run before the textarea has data and fail to display property (it'll be empty, because it needs the value before wysiwyg() is called).
I've eliminated the wysiwyg() function itself as the culprit by replacing that line with:
$('.make-wysiwyg').each(function () {console.log($(this).val())});
And I can clearly see every so often it'll print empty value fields for no apparent reason.
I'm not sure if the template or publish() function could be a culprit, so I'll supply them as well.
Any ideas greatly appreciated.
Template:
<template name="adminPostsEdit">
<h1>Edit Post</h1>
<form id="edit-post" class="{{isNewClass}}" method="post">
<label for="post-title">Title</label>
<input id="post-title" value="{{post.title}}">
<label for="post-slug">Slug</label>
<input id="post-slug" value="{{post.slug}}">
<label for="post-content">Content</label>
<textarea id="post-content" class="make-wysiwyg">{{post.content}}</textarea>
<label for="post-excerpt">Excerpt</label>
<textarea id="post-excerpt" class="make-wysiwyg">{{post.excerpt}}</textarea>
{{#if post.published}}
<button value="save">Save</button>
<button value="unpublish">Unpublish</button>
{{else}}
<button value="save">Save Draft</button>
<button value="publish">Publish</button>
{{/if}}
<button value="cancel">Cancel</button>
</form>
</template>
publish():
Meteor.publish('post', function (id) {
return Posts.find({_id: id});
});
Helpers:
Template.adminPostsEdit.helpers({
post: function () {
return Posts.findOne();
},
isNewClass: function () {
return !this.id ? 'new' : '';
}
});
You should do that in the template's render function.
Template.adminPostsEdit.rendered = function() {
$('.make-wysiwyg').wysiwyg();
})