How can i make an input field not update all other instances of it? - vuejs2

i am strting to play with Vue and i was wondering how i can update only the current edited text input value instead of updating all instances of it? I know it must be about the v-model , but i am a bit lost here.
Here is my code for the component :
Vue.component('app-list', {
template: '<section id="app-item-field" class="columns is-multiline">' +
' <div class="column is-2" v-for="(list, index) in lists" >' +
' <h2>{{list.title}}</h2>' +
' <div class="field has-addons">' +
' <input class="input is-small is-info" type="text" v-model="inputVal" placeholder="Nom de l\'item à ajouter">' +
' <a class="button is-info is-small" :disabled="initValueIsSet === false" #click="addListItem(index)">Ajouter</a>' +
' </div>' +
' <app-list-items :items="list.items"></app-list-items>' +
' </div>' +
' </section>',
props: ['lists'],
data: function () {
return {
inputVal: null
}
},
computed: {
initValueIsSet: function () {
if (this.inputVal === null) {
return false;
} else {
return this.inputVal.length > 0;
}
}
},
methods: {
addListItem: function (index) {
if (this.initValueIsSet) {
this.$emit('new-list-item', index, this.inputVal, "http://www.google.ca");
this.inputVal = "";
}
}
}
});
Thank you in advance!

The simplest solution is to turn inputVal into an array:
data: function () {
return {
inputVal: []
}
},
And use index from v-for to access it in the v-model. Template:
<input class="input is-small is-info" type="text" v-model="inputVal[index]" placeholder="Nom de l\'item à ajouter">'
Also update the methods.
Demo:
Vue.component('app-list-items', {
template: '<span></span>'
});
Vue.component('app-list', {
template: '<section id="app-item-field" class="columns is-multiline">' +
' <div class="column is-2" v-for="(list, index) in lists" >' +
' <h2>{{list.title}}</h2>' +
' <div class="field has-addons">' +
' <input class="input is-small is-info" type="text" v-model="inputVal[index]" placeholder="Nom de l\'item à ajouter"> {{ inputVal[index] }}' +
' <a class="button is-info is-small" :disabled="initValueIsSet(index) === false" #click="addListItem(index)">Ajouter</a>' +
' </div>' +
' <app-list-items :items="list.items"></app-list-items>' +
' </div>' +
' </section>',
props: ['lists'],
data: function () {
return {
inputVal: []
}
},
methods: {
initValueIsSet: function (index) {
if (this.inputVal[index] === null || this.inputVal[index] === undefined) {
return false;
} else {
return this.inputVal[index].length > 0;
}
},
addListItem: function (index) {
if (this.initValueIsSet(index)) {
this.$emit('new-list-item', index, this.inputVal[index], "http://www.google.ca");
Vue.set(this.inputVal, index, ""); // https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
}
}
}
});
new Vue({
el: '#app',
data: {
lists: [{title: 'ana', items: []}, {title: 'bob', items: []}]
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<app-list :lists="lists"></app-list>
</div>
Since inputVal is now an array, the computed initValueIsSet is now parameterized by the index. As computeds don't take arguments, we turned it into a method.

Related

vuejs checkbox need to change method

I have a dropdown menu that triggers a method to get data based on what is selected in the dropdown. I would like to add a condition that changes the #change method if a checkbox is selected. The method would switch based on which checkbox is selected. I guess a v-if that runs a check somewhere--Im not sure.
new Vue({
el: "#app",
data: {
selection: 'Select a option',
todos: [{
name: 'apple'
}, {
name: 'oranges'
}, {
name: 'carrots'
}]
},
methods:{
changeP (event) {
this.getSetA();
// alert("this is set a");
},
changeP1 (event) {
this.getSetB();
alert("this is set b");
},
changeP2 (event) {
this.getSetC();
alert("this is set c");
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Fruit:</h2>
<select v-model="selection" #change="changeP($event)">
<option value="Select a option" disabled>Choose an fruit:</option>
<option v-for="(t, i) in todos" :key="i" :value="t.name">{{ t.name }}</option>
</select>
<br>
<input type="checkbox" id="vehicle1" name="vehicle1" value="apple"> Apples
<input type="checkbox" id="vehicle2" name="vehicle2" value=""> Oranges
<input type="checkbox" id="vehicle3" name="vehicle3" value="">pears
</div>
new Vue({
el: '#app',
data: {
selection: 'Select an option',
selectOptions: [ { name: 'apple' }, { name: 'oranges' }, { name: 'carrots' }],
checkboxOptions: [ 'vehicle1', 'vehicle2', 'vehicle3' ],
checkedItems: [],
message: '',
},
methods: {
onDropdownChange() {
this.message = '';
if (this.checkedItems.length) {
this.message = `You've selected: `;
for(let i = 0; i < this.checkedItems.length; i++) {
this.message += this.checkedItems[i] + ' ';
}
}
switch(this.selection) {
case 'apple':
return this.onAppleSelected();
case 'oranges':
return this.onOrangesSelected();
default:
return this.onCarrotsSelected();
}
},
onAppleSelected() {
if (this.message.length) {
this.message += 'and apple.';
return;
}
this.message = `You've selected apple`;
},
onCarrotsSelected() {
this.message += ' CARROT!'
},
onOrangesSelected() {
this.message += ' No Scurvy';
}
},
template: `
<div id="app">
<h2>Fruit:</h2>
<select v-model="selection" #change="onDropdownChange">
<option value="Select an option">Choose</option>
<option v-for="(o, i) in selectOptions" :key="o.name" :value="o.name">{{o.name}}</option>
</select>
<div style="display:block" v-for="(o, i) in checkboxOptions" :key="o">
<label :for="o">{{o}}</label>
<input type="checkbox" :id="o" :name="o" :value="o" v-model="checkedItems" />
</div>
<p>{{message}}</p>
</div>
`
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>
You should probably have a single method that decides which method to call based on the state of the component.

How to make disabled button after click in Vuejs

I have a button on my website that gives bonuses to the user. Button have several conditions in 1 button:
<button class="btn btn--small btn--purple" :disabled="isDisabled" #click="takeBonus">Take</button>
<script>
......
computed: {
isDisabled() {
return this.heal_used === 1 || this.diff < 10;
this.$forceUpdate();
},
},
.......
</script
But when user click Take button, and if all success, button is still active this.$forceUpdate(); not working. And i need make when user click Take button, and if all success, make this button disabled.
My full Bonus.vue:
<template>
<div class="inner-page">
<div class="account" v-if="loaded && !$root.isMobile">
<div class="page-header">
</div>
<div class="form-panels hide-below-m">
<div class="col-7" style="margin-top: 5rem;margin-right: 3rem;">
<div class="faucet-component mx-5" rv-class-boost="data.boostIsOpen">
<img src="https://dota2.skins1.games/src/img/components/shine.png?v=8ce59643e70cb2f8550deb6a249b5f29" class="faucet-component__shine-bg">
<div class="faucet-component__content d-flex justify-content-between align-items-center flex-column w-100" style="
height: 15rem;">
<div class="faucet-component__available-amount-block round-circle p-2">
<div class="faucet-component__availabe-amount-coins d-flex justify-content-center align-items-center round-circle h-100" rv-currency="model:amount">Спасение</div>
</div>
<!-- rivets: unless model:cnt | eq 0 --><div class="faucet-component__remaining">
<span rv-t="">Left</span>:
<span>{{ bonus_num }}</span><br>
<span rv-t=""></span>
<span>{{ diff }}</span>
</div>
<!-- rivets: if model:cnt | eq 0 -->
<div class="faucet-component__buttons-container d-flex align-items-center w-75 justify-content-around">
<button class="btn btn--small btn--purple" :disabled="isDisabled" #click="takeBonus">Take</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
loaded: false,
bonus: {},
diff: {},
user: {},
bonus_num: 0,
heal_used: {}
}
},
mounted() {
this.$root.isLoading = true;
if (!this.$cookie.get('token')) {
this.$root.isLoading = false;
this.$router.go(-1);
}
this.domain = window.location.protocol + '//' + window.location.hostname;
setTimeout(() => {
this.getUser();
}, 100);
},
computed: {
isDisabled() {
return this.heal_used === 1 || this.diff < 10;
this.$forceUpdate();
},
},
methods: {
getUser() {
this.$root.axios.post('/user/getProfile')
.then(res => {
const data = res.data;
console.log(data.heal_used);
console.log(data.diff);
this.loaded = true;
this.user = data.user;
this.bets = data.bets;
this.bonus = data.bonus;
this.diff = data.diff;
this.heal_used = data.heal_used;
this.new_day = data.new_day;
this.bonus_num = data.bonus_num;
this.$root.isLoading = false;
})
.catch(err => {
this.$root.isLoading = false;
this.$router.go(-1);
})
},
takeBonus() {
this.$root.axios.post('/user/takeBonus', {
value: this.user.cashback
})
.then(res => {
const data = res.data;
if (data.type === 'success') {
console.log(data.heal_used);
this.bonus_num = data.bonus_num;
this.$root.user.balance = data.newBalance;
this.heal_used = data.heal_used;
this.$forceUpdate();
}
this.$root.showNotify(data.type, this.$t(`index.${data.message}`));
})
},
}
}
How i can make it, when user click Take button, and if all success, so that the Take button becomes disabled?
I'm sorry but your code has no indentation, so I just did that on jsfiddler so you know "How to make disabled button after click in Vuejs". You can have a look on : https://jsfiddle.net/o81yvn05/1/
<div id="app">
<button :disabled="isDisabled" #click="disableButton()">Please click here</button>
</div>
<script>
new Vue({
el: "#app",
data: {
isDisabled: false,
},
methods: {
disableButton() {
this.isDisabled = true
}
}
})
</script>

input field value keeps getting reset #input?

I have created an custom reusable autocomplete component.The issue i am facing is whenever i start to type anything into the fields(#input) the value in the input field gets reset. I feel it has something to do within the code written in the debounce function but i am not sure.Plz help?
main.js
Vue.component('AutoComplete', {
props: ['list','value','title'],
data() {
return {
input: '',
}
},
template: `<template>
<div class="autocomplete">
<input style="font-size: 12pt; height: 36px; width:1800px; " type="text" v-model="input" #input="handleInput"/>
<ul v-if="input" >
<li v-for="(item, i) in list" :key="i" #click="setInput(item)" >
<template v-if="title!='manager'">
<div class="container">
<p>
<b>ID:</b>
{{item.id}}
</p>
<p>
<b>Description:</b>
{{item.description}}
</p>
</div>
</template>
<template v-else>
<div class="container">
<p>
<b>ID:</b>
{{item.id}}
</p>
<p>
<b>First Name:</b>
{{item.firstName}}
</p>
<p>
<b>Last Name:</b>
{{item.lastName}}
</p>
</div>
</template>
</li>
</ul>
</div>
</template>`,
methods: {
handleInput(e) {
console.log('inside handleInput')
this.$emit('input', e.target.value)
},
setInput(value) {
console.log('inside setInput')
this.input = value
this.$emit('click', value)
}
},
watch: {
$props: {
immediate: true,
deep: true,
handler(newValue, oldValue) {
console.log('new value is'+newValue)
console.log('old value is'+oldValue)
console.log('value inside handler'+this.value)
console.log('list inside handler'+this.list)
console.log('title inside handler'+this.title)
this.input=this.value
}
}
}
})
Currently i have called this component from JobDetail.vue page like this-
JobDetail.vue
<template>
<b-field label="Custom Action">
<AutoComplete v-on:input="getAsyncDataAction" v-on:click="(option) => {updateRowValue('records', props.index, 'action', option.id); props.row.action = option.id}" :value="props.row.action" :list="dataAction" title='action' >
</AutoComplete>
</b-field>
</template>
<script>
import { viewMixin } from "../viewMixin.js";
import debounce from "lodash/debounce";
import api from "../store/api";
const ViewName = "JobDetail";
export default {
name: "JobDetail",
mixins: [viewMixin(ViewName)],
data() {
return {
dataAction: [],
isFetching: false
};
},
methods: {
getAsyncDataAction: debounce(function(name) {
if (!name.length) {
this.dataAction = [];
return;
}
this.isFetching = true;
api
.getSearchData(`/action/?query=${name}`)
.then(response => {
this.dataAction = [];
response.forEach(item => {
this.dataAction.push(item);
});
})
.catch(error => {
this.dataAction = [];
throw error;
})
.finally(() => {
this.isFetching = false;
});
}, 500)
}
};
</script>
viewmixin.js
computed: {
viewData() {
return this.$store.getters.getViewData(viewName)
},
objectData() {
return this.$store.getters.getApiData(this.viewData.api_id).data
},
sessionData() {
return this.$store.getters.getSessionData()
},
isLoading() {
return this.$store.getters.getApiData(this.viewData.api_id).isLoading
},
newRecord() {
return this.$route.params.id === null;
}
},
I don't understand why the input fields value keeps resetting #input. Please help and also let me know if this is the correct approach?

Vue el-form dynamic validation

<template>
<div>
<el-form label-position="top" :model="notificationEmails" ref="emailForm">
<el-form-item
v-for="(item, index) in notificationEmails.emails"
:key="index"
:label="getLabel(index)"
:for="`${item.id}_${index}`"
:prop="'emails.' + index + '.id'"
:rules="{
required: true,
type: 'email',
message: 'Not valid email',
trigger: ['blur', 'change']
}"
>
<el-row>
<el-col :span="6">
<el-input v-model="item.id" type="email" :id="`${item.id}_${index}`" />
</el-col>
<el-col :span="2" style="padding-left: 18px">
<span v-if="index === 0" tabindex="0" #click="addEmail" #keyup.enter.stop="addEmail">
<i aria-hidden="true" class="icon-add-circle-outline" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.addEmail')}}</span>
</span>
<span
v-else
tabindex="0"
#click="deleteEmail(item.id)"
#keyup.enter.stop="deleteEmail(item.id)"
>
<i class="icon-subtract-circle-outline" aria-hidden="true" />
<span class="screen-reader">{{$t('a11y.settings.soldTo.notif.action.deleteEmail')}}</span>
</span>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'EmailWidget',
data() {
return {
notificationEmails: {
emails: []
}
};
},
props: ['passEmail'],
watch: {
passEmail: {
handler(newVal) {
this.notificationEmails.emails = newVal;
},
deep: true
},
notificationEmails: {
handler() {
this.$refs.emailForm.validate(async validate => {
if (validate) {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: true
});
} else {
await this.$store.dispatch('settings/GENERIC', {
module: 'common',
propKey: 'validEmail',
propValue: false
});
}
});
},
deep: true
}
},
methods: {
addEmail() {
this.notificationEmails.emails.push({
id: '',
priority: this.notificationEmails.emails.length + 1
});
// this.emails = [...this.emails, { id: '', priority: this.emails.length + 1 }];
},
deleteEmail(email) {
// this.emails = this.emails.filter(item => item.id !== email);
let index = 0;
for (let i = 0; i < this.notificationEmails.emails.length; i += 1) {
if (this.notificationEmails.emails[i].id === email) {
index = i;
break;
}
}
this.notificationEmails.emails.splice(index, 1);
},
getLabel(index) {
return index === 0 ? this.$t('settings.soldTo.notif.email') : '';
}
},
};
</script>
<style lang="scss">
i:hover {
cursor: pointer;
}
</style>
Some problems about the validation in dynamic add or delete the emails in el-form of Vue. When I add a new email, the validation cannot work. When I delete email. it shows
Error: please transfer a valid prop path to form item!
There is no issue when I edit the email.
I change the props according to enter code here the official document, but it still shows error.

Filtering with Vuejs w/ axios

Hoping someone can point me in the right direction - I'm fairly new to Vuejs and have taken over someone else's code, although I've managed to do a fair bit without any issues, i'm struggling to get the filtering to work.
Here is the majority of the code:
<template>
<div v-if="showProperties">
<div v-if="properties.length > 0">
<div class="row">
<div class="col-2 listings--filter">
<select v-model="filter" class="form-control listings--filter_select">
<option value="" disabled hidden>Filter</option>
<option value="price-lowest">Lowest Price First</option>
<option value="price-highest">Highest Price First</option>
<option value="listing-new">Newest Listing First</option>
<option value="listing-old">Oldest Listing First</option>
</select>
</div>
<div class="col-2 listings--filtersstc">
<toggle-button v-model="sstcBtn"
:value="true"
:labels="{checked: 'Show SSTC', unchecked: 'Hide SSTC'}"
:width="120"
:height="40"/>
</div>
</div>
<div class="row margin-bottom">
<div class="col listings--filter">
<small v-show="showRemoveFilter">Current filter: {{ selectedFilter }}</small>
</div>
<div class="col listings--filter">
<small v-show="showRemoveFilter" v-on:click="removeSortProperties" class="float-right">Remove filter</small>
</div>
</div>
<div class="row">
<property-listings v-for="(property, index) in properties" v-bind:property="property" v-bind:key="index"></property-listings>
</div>
</div>
<div v-else>
<div class="row">
<div class="col text-center">
<p class="dark-text">No properties match your search criteria. Please try again.</p>
</div>
</div>
</div>
</div>
</template>
<script>
import PropertyListings from './PropertyListings.vue'
import * as VueGoogleMaps from 'vue2-google-maps'
import ToggleButton from 'vue-js-toggle-button'
Vue.use(ToggleButton)
Vue.use(VueGoogleMaps, {
load: {
key: '-------------------',
libraries: 'places', // This is required if you use the Autocomplete plugin
// OR: libraries: 'places,drawing'
// OR: libraries: 'places,drawing,visualization'
// (as you require)
}
})
export default {
data () {
return {
showProperties: false,
properties: [],
filter: '',
sstcBtn: true,
selectedFilter: '',
showRemoveFilter: false,
center: {lat: 00000, lng: -000000},
propertyInfoName: '',
propertyInfoPrice: '',
propertyInfoLink: '',
propertyInfoType: '',
infoWindowPos: {
lat: 0,
lng: 0
},
infoWinOpen: false,
currentMidx: null
}
},
delimiters: ['<%', '%>'],
components: {
PropertyListings
},
watch: {
filter: function(newFilter, oldFilter) {
this.sortProperties(newFilter);
},
sstcBtn: function(newSstcBtn, oldSstcBtn) {
this.removeSstcProperties(newSstcBtn);
}
},
methods: {
sortProperties: _.debounce(
function(newFilter) {
if(newFilter === 'price-highest') {
this.properties = _.orderBy(this.properties, 'price', 'desc')
this.selectedFilter = 'Highest Price First'
} else if(newFilter === 'price-lowest') {
this.properties = _.orderBy(this.properties, 'price', 'asc')
this.selectedFilter = 'Lowest Price First'
} else if(newFilter === 'listing-new') {
this.properties = _.orderBy(this.properties, 'id', 'desc')
this.selectedFilter = 'Newest Listing First'
} else if(newFilter === 'listing-old') {
this.properties = _.orderBy(this.properties, 'id', 'asc')
this.selectedFilter = 'Oldest Listing First'
}
this.showRemoveFilter = true
},
500
),
removeSstcProperties: _.debounce(
function(newSstcBtn) {
if(newSstcBtn == true){
console.log('do not filter')
//this.properties = _.filterBy(this.properties, 'status_id', '1')
return this.properties.filter(function(property){
return property.status_id == "1"
}.bind(this))
} else if(newSstcBtn == false){
console.log('do filter')
}
},
500
),
removeSortProperties: function() {
this.properties = _.orderBy(this.properties, 'id', 'desc')
this.showRemoveFilter = false
},
toggleInfoWindow: function(property, idx) {
this.infoWindowPos = {lat: Number(property.latitude), lng: Number(property.longitude)}
this.propertyInfoName = property.display_address
this.propertyInfoPrice = property.price
if(property.let_type_id === '3') {
this.propertyInfoLink = '/properties/for-students/' + property.main_searchable_areas + '/' + property.slug + '/' + property.property_ref
} else if(jQuery.inArray(property.let_type_id, ['1','2']) != '-1'){
this.propertyInfoLink = '/properties/for-rent/' + property.main_searchable_areas + '/' + property.slug + '/' + property.property_ref
} else {
this.propertyInfoLink = '/properties/for-sale/' + property.main_searchable_areas + '/' + property.slug + '/' + property.property_ref
}
}
},
created() {
var self = this;
axios.get('/properties/json')
.then(function (response) {
self.properties = response.data
self.showProperties = true
})
.catch(function (error) {
console.log(error);
});
}
}
</script>
Everything else is working fine but the bit i've been working on is the removeSstcProperties method, I've got the method triggering fine, however I'm struggling to actually filter the results for properties that have the status_id = 1. I've tried 2 ways (one commented out). Can anyone point me in the right direction?