Vuejs generating click event in next button after pressing enter input - javascript

I'm encountering a very strange case.
I've build a very simple example in order to present my problem.
I've 3 files : App.vue, todo2.vue, todoI.vue.
App.vue has 1 component (todo2.vue). todo2.vue has 1 component (todoI.vue).
You'll find under the code of todo2 and todoI.
The problem I'm facing is that when i press enter in the input text id #checkboxAdd, it triggers an event on the next button.
In the code below when pressing enter in the input text #checkboxAdd, it triggers the click event on the first iteration of my todoI button, which in my example calls the function del (#click="del()"), which console.log(this), logging the first iteration of the component todoI.
What is even stranger is that when I add a button just after the input text, add a #click to console.log the event, it is indeed called (instead of calling the button of the first iteration of todoI).
Does anyone understand why this happens ? Is this something I'm doing wrong ?
todo2.vue:
<template>
<div class="d-flex flex-column">
<div>
<form #submit.prevent="">
<div class="mb-3 input-group">
<div class="input-group-text">
<input type="checkbox" class="form-check-input" id="checkboxAdd" aria-describedby="checkboxAdd">
</div>
<input type="text" class="form-control" id="inputAdd" aria-describedby="inputAdd" v-model="tempI">
</div>
<ul class="list-group">
<todoI v-for="(it, k) in todos" v-model="it.v" :key="k" #delItem="del(it)"></todoI>
</ul>
<br>
</form>
</div>
</div>
</template>
<script>
import todoI from './todoI.vue'
export default {
name:"todo2",
components: {todoI},
data: function(){
return {
todos: [
{v:{
val: "Bread",
checked: false
}},
{v:{
val: "Fruits",
checked: false
}},
{v:{
val: "Ironing",
checked: false
}}
],
tempI: ''
}
},
methods:{
del (it){
this.todos = this.todos.filter(i => i!==it)
}
}
}
</script>
todoI.vue:
<template>
<li class="list-group-item d-flex align-items-center" #mouseover="btnShow=true" #mouseleave="btnShow=false">
<input type="checkbox" class="me-4" v-model="value.checked">
<div class="w-100" :class="value.checked ? checkedClass : '' ">{{ value.val }}</div>
<div class="flex-shrink-1">
<button class="btn btn-sm btn-close" v-show="btnShow" #click="del()"></button>
</div>
</li>
</template>
<script>
export default {
name:"todoI",
props:{
value: Object
},
data: function(){
return {
checkedClass:['text-decoration-line-through', 'text-muted'],
btnShow: false,
}
},
methods:{
del(){
console.log(this)
}
}
}
</script>

you can simple use #keypress or #keydown
<input type="text" class="form-control" id="inputAdd" v-model="tempI" #keypress.enter.prevent />
or
<input type="text" class="form-control" id="inputAdd" v-model="tempI" #keydown.enter.prevent = "">

Related

(Vuejs) Property or method is not defined on the instance but referenced during render

I have a simple button suppose to add an item in a list:
<label for="numit">item number:</label>
<input type="text" id="numit" :value="idxItemBuy">
<button id="buyitem" #click="buy($event.target.value)">Buy</button>
buy() {
console.log("buy fonction")
this.currentPlayer.buy(this.idxItemBuy)
}
but it's acctualy not calling the method buy
( and i don't know when i'm suppose to use $event.target.value)
You can read more about v-model => bind input with a data (https://v2.vuejs.org/v2/guide/forms.html or https://v3.vuejs.org/guide/forms.html#text)
I write you a code that works
<template>
<div>
<label>item number:</label>
<input type="text" v-model="idxItemBuy" />
<button #click="buy">Buy</button>
<ul>
<li v-for="item in items" :key="item">
{{ item }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
idxItemBuy: "",
items: [],
};
},
methods: {
buy() {
console.log("buy fonction", this.idxItemBuy);
this.items.push(this.idxItemBuy);
},
},
};
</script>

pass an object as props

I'm working on a little project using VueJS, and I would like to know how can I print my props (label) that I'm receiving
this is my code :
<div class="form-group">
<auto-complete :path="'/api/accounts/autoComplete/'" :label="'item.account_name'"></auto-complete>
</div>
this is my component HTML :
<template>
<div class="autocomplete">
<input autocomplete="off" type="text" class="form-control form-control-border" placeholder="query" v-model="query" #input="autoComplete" #focus="suggestion = true" />
<div v-if="data && suggestion">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li #click="selected(item.account_name)" v-for="item in data" :key="item.id">
<a class="dropdown-item" href="#">{{ label }}</a>
</li>
</ul>
</div>
</div>
</template>
<script>
import {getAPI} from "../axios-api"
export default {
props: {
label: Object,
path: String
},
data() {
return {
suggestion: false,
query: '',
data: [],
}
},
methods: {
autoComplete(){
if(/\S/.test(this.query) && this.query.length >= 3){
getAPI.get(this.path + '?query=' + this.query).then((response) => {
this.data = response.data
})
}
},
selected(account){
this.query = account
this.suggestion = false
}
}
}
</script>
as you can see I'm sending an object in :label that i want to print here ( since i have this object in my component data )
Assuming that you want a specific key of item as the label, you can just pass that key string then use it in your dropdown item. Make sure that the label prop accepts only String.
<div class="form-group">
<auto-complete path="/api/accounts/autoComplete/" label="account_name" placeholder="My PlaceHolder"></auto-complete>
</div>
<template>
<input autocomplete="off" type="text" class="form-control form-control-border" :placeholder="placeholder" v-model="query" #input="autoComplete" #focus="suggestion = true" />
<li #click="selected(item.account_name)" v-for="item in data" :key="item.id">
<a class="dropdown-item" href="#">{{ item[label] }}</a>
</li>
</template>
<script>
export default {
props: {
label: String,
placeholder: String
}
}
</script>
You are sending string, not object.
You should do:
:label="item.account_name"
Instead of
:label="'item.account_name'"

How to append input elements dynamically in vue

I'm trying to append new input fields based on a condition, I will describe the workflow to help you understand
First stage is to press this button to implement 2 functions(1 is to move to other fieldset in the staged form, second function is to append the inputs:
<input type="button" name="secondBtn" class="next action-button" value="Next" id="secondBtn" #click="nextPlusappend"/>
nextPlusappend:
nextPlusappend() {
this.isNextClicked();
this.appendFields();
}
appendFields:
//this.platform initllized as 'one' so the condition is true.
if(this.platform === 'one'){
this.inputFields.push({
Username: '',
Password: '',
AffiliateID: '',
CI: '',
GI: '',
})
}
And I want to append all the fields from the function to this fieldset:
<div v-if="currentPage === 2">
<fieldset id="fieldset3" v-for="(param, index) in inputFields" :key="index">
<h2 class="fs-title">API Credentials</h2>
<h3 class="fs-subtitle">Step 3- Add any parameter for the integration</h3>
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
<input type="button" name="previous" class="previous action-button" value="Previous" #click="isPreviousClicked"/>
<input type="submit" name="submit" class="submit action-button" value="Create a Ticket" id="excel"/>
</fieldset>
</div>
How can I append this without hard code all the input fields as I did here:?
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
This is designated to be dynamic, what do i mean?
I mean that if the this.platform is equal to "one" there will be a unique fields, and if this.platform equal to "two" for example there will be other unique fields.
Don't think like "pushing a form field", rather think like "adding a new item to the dataset" (and of course, its displayed UI is a form field).
Let me give an example:
Vue.component("FormField", {
props: ["label", "value"],
computed: {
val: {
get() {
return this.value
},
set(val) {
this.$emit("update:value", val)
}
},
},
methods: {
handleClickAdd() {
this.$emit("click-add-field")
}
},
template: `
<div>
<label>
{{ label }}: <input type="text" v-model="val" />
</label>
<button
#click="handleClickAdd"
>
+ ADD
</button>
</div>
`,
})
new Vue({
el: "#app",
data() {
return {
formFields: [{
label: "Field 1",
value: null,
}],
}
},
methods: {
handleClickAddField() {
const item = {
label: `Field ${ this.formFields.length + 1 }`,
value: null,
}
this.formFields = [...this.formFields, item]
},
},
template: `
<div
class="container"
>
<div
class="col"
>
<h4>FIELDS:</h4>
<hr>
<form-field
v-for="(field, i) in formFields"
:key="i"
:label="field.label"
:value.sync="field.value"
#click-add-field="handleClickAddField"
/>
</div>
<div
class="col"
>
<h4>FIELD VALUES:</h4>
<hr>
<div
v-for="(field, i) in formFields"
:key="i"
>{{ field.label }}: {{ field.value }}</div>
</div>
</div>
`,
})
.container {
display: flex;
}
.col {
padding: 0 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
You can see, that on ADD I just added a new item in the formFields - the values are bound in the template to a child-component, that handles the actual representation of the fields.
On the right side of the snippet, you can see another benefit of decoupling data from UI: I created another representation of the same data source - that immediately reacts to any changes!

Prevent on click on parent A tag when clicking button inside

I have problems with product cards on index page.
Inside product card I have Vue component to render form (quantity and add to cart button).
When I click on add to cart button I get expected result. Response is sent to root vue component and then I see toast notification that product is added to cart.
But when I click on plus, minus buttons or input field then href link is triggered from parent A tag.
How to disable it?
I found this Prevent on click on parent when clicking button inside div
But it works only if I put A tag inside vue component. I don't want to put too much html into vue.
#foreach ($products as $product)
<a href="{{ $category->fullpath.'/'.$product->sef }}" class="catalog__card">
<div class="catalog__card-img"><img src="/storage/img/products/{{ $product->mediumpic }}" alt="{{ $product->title }}"></div>
<div class="card__properties">
<div class="card__price"><span>{{ $product->price }}<span class="currencySymbol">₽</span></span></div>
<div class="card__stock">
#if ( $product->stock > 0 )
<i class="far fa-check-circle text-success"></i><span class="text-success"><strong> on stock</strong></span>
#else
<span><strong> on request</strong></span>
#endif
</div>
<addtocart #added_to_cart="updateCart"></addtocart>
</div>
<div class="catalog__card-title"><span>{{ $product->title }}</span></div>
</a>
#endforeach
in Vue component I have following
<template>
<div class="cart">
<form method="POST" id="add_to_cart" action="/add_to_cart" #submit.prevent="onSubmit">
<input type="hidden" name="_token" :value="csrf">
<div class="quantity">
<button type="button" class="minus_quantity" v-on:click="minus_quantity" v-long-press="300" #long-press-start="longMinusStart" #long-press-stop="longMinusStop">-</button>
<input type="number" class="input-text qty text" step="1" min="1" max="9999" name="quantity" value="1" title="Qty" v-model.number="quantity">
<button type="button" class="plus_quantity" v-on:click="plus_quantity" v-long-press="300" #long-press-start="longPlusStart" #long-press-stop="longPlusStop">+</button>
</div>
<button type="submit" name="add-to-cart" class="button-cart"><i class="fas fa-cart-plus"></i><span> order</span></button>
</form>
</div>
</template>
<script>
import LongPress from 'vue-directive-long-press';
export default {
name: "addtocart",
data: function () {
return {
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
quantity: 1,
plusInterval: null,
minusInterval: null,
success: false,
errors: []
}
},
directives: {
'long-press': LongPress,
},
props: [],
computed: {
getName(){
return this.$store.getters.Name
}
},
methods: {
// add to cart quantity plus and minus buttons
// short mouse click event
parent() { alert('you clicked the parent') },
minus_quantity() {
if (this.quantity > 0) {this.quantity -= 1}
},
plus_quantity() {this.quantity += 1},
// long press buttons
longPlusStart() {
this.plusInterval = setInterval(() => {
this.quantity += 1
}, 100)
},
longPlusStop() {
clearInterval(this.plusInterval)
},
longMinusStart() {
this.minusInterval = setInterval(() => {
if (this.quantity > 0) {this.quantity -= 1}
}, 100)
},
longMinusStop() {
clearInterval(this.minusInterval)
},
onSubmit() {
axios.post('/add_to_cart', this.$data)
.then(this.onSuccess)
.catch(error => this.errors = error.response.data);
},
onSuccess(response) {
this.success = true;
this.$emit('added_to_cart', response);
},
},
mounted() {
},
}
</script>
You can use "v-on:click.stop" directive for your plus, minus buttons instead of "v-on:click"
Read this for more information https://v2.vuejs.org/v2/guide/events.html
using v-on:click.prevent instead v-on:click I fixed this issue
With a <a href="..."> tag parent component an <button #click="someAction"> tag inside, you have to replace #click="someAction" by #click.prevent="someAction".
It works like a charm for m !

How to reload page after pressing enter in chat

So here is my code. When I press the button with mouse it reloads page but, when I press enter key its not refreshing. Any ideas how to do it?
<template lang="html">
<div class="chat-composer">
<input maxlength="180" type="text" placeholder="mesajınızı yazınız" v-model="messageText" #keyup.enter="sendMessage">i
<button class="btn btn-primary" #click="sendMessage" onClick="window.location.reload();>Gönder</button>
</div>
</template>
here is full the code I use. So im not the expert.. I need help about it
<template lang="html">
<div class="chat-composer">
<input maxlength="180" type="text" placeholder="mesajınızı yazınız" v-model="messageText"
#keyup.enter="sendMessage">
<button class="btn btn-primary" #click="sendMessage" onClick="window.location.reload();"
>Gönder</button>
</div>
</template>
<script>
export default {
data() {
return {
messageText: ''
}
},
methods: {
sendMessage(){
this.$emit('messagesent',{
message: this.messageText,
user: {
name: $('.navbar-right .dropdown-toggle').text()
}
});
this.messageText = '';
},
},
}
</script>
You are using Vue.js, if so you can do something like this
<button class="btn btn-primary" v-on:keyup.enter="window.location.reload()"
#click="sendMessage" onClick="window.location.reload();>Gönder</button>
You can check the Key Modifiers here the https://v2.vuejs.org/v2/guide/events.html

Categories