How can the value change immediately after I clicked add or minus - vue.js

Hi currently I am making a add & minus function and the problem I am facing is once I clicked add or minus, the value still remain the same... I use the watch property also and it still not working
The get_list is calling from a API
<b-row v-for="(data,i) in get_list" :key="i" class="mt-3 mx-0">>
<b-button pill
class="quantity-btn btn-secondary"
#click="addQuantity(data.id_product,data.id_style)"
>
<span style="transform: translateY(-5%);">+</span>
</b-button>
<div class="px-2">
<b-form-input type="number" min="1" :max="data.quantity_available" :value="quantity" v-model="data.cart_quantity" class="quantity-input"></b-form-input>
</div>
<b-button pill
class="quantity-btn btn-secondary"
#click="minusQuantity(data.id_product,data.id_style)"
>
<span style="transform: translateY(-5%);">-</span>
</b-button>
</b-row>
script
data: () => ({
get_list: [],
quantity:0,
}),
method :{
addQuantity(id,style) {
this.quantity++
this.updateQuantity(id,style)
},
minusQuantity(id,style) {
this.quantity--
this.updateQuantity(id,style)
},
},
watch: {
quantity(newVal, oldVal) {
console.log('new'+newVal)
}
}

Take a look of this code in code proved above.
<div class="px-2">
<b-form-input type="number" min="1" :max="data.quantity_available" :value="quantity" v-model="data.cart_quantity" class="quantity-input"></b-form-input>
</div>
Here it seems cart_quantity is getting used in template instead of quantity due to this it's not getting updated.
to fix this issue, you can update the cart_quantity property of the data object instead of the quantity data property in the addQuantity and minusQuantity
methods: {
addQuantity(id, style) {
this.get_list.forEach(item => {
if (item.id_product === id && item.id_style === style) {
item.cart_quantity++;
}
});
},
minusQuantity(id, style) {
this.get_list.forEach(item => {
if (item.id_product === id && item.id_style === style) {
item.cart_quantity--;
}
});
}
}
Please remove watch property as well it seems not required.

The problem is that you are performing the add/minus operation on the quantity variable but in the template, you are using the cart_quantity variable which is not increasing/decreasing.
So, either use quantity or cart_quantity as per your logic.
addQuantity(id, style) {
this.cart_quantity++;
// If you are using quantity as v-model
// this.quantity++
this.updateQuantity(id, style);
},
minusQuantity(id, style) {
this.cart_quantity--;
// If you are using quantity as v-model
// this.quantity--
this.updateQuantity(id, style);
},
One more thing, you don't need to use value and v-model together at the same time. If you want to give some initial value to the input, simply assign that value to your cart_quantity on mounted and use it further.
The last thing, you don't need a watcher as well.

Related

Vue onEnable/onDisable event

In my vue application I need to observe an element getting enabled/disabled (It binds to a function) and by looking that I need to trigger an onEnabled/onDisabled event which will clean up some other data nodes.
So is there a listener like #click, #enabled or something?
Eg:
<v-checkbox :value="getValue(layout.responseNode)" #change="setValue(layout.responseNode, $event)" :label="expression(layout.label)" :disabled="expression(layout.enableIf)" ></v-checkbox>
This is the code so far with me. here enableIf will be a dynamic expression from server.
Its properly working now.
Now I need to run some more expression like
<v-checkbox :value="getValue(layout.responseNode)" #change="setValue(layout.responseNode, $event)" :label="expression(layout.label)" :disabled="expression(layout.enableIf)" #onDisabled="expression(layout.disableCommand)" ></v-checkbox>
Is there an event matching onDisabled?
i would recommend watchers you can bind a variable/computed to :disabled of the checkbox and watch the value changing
exp.
<template>
<div>
<p>{{ checkboxState }}</p>
<input type="checkbox" :disabled="checkboxState" />
<button #click="checkboxChanged()">Disable Checkbox!</button>
</div>
</template>
<script>
export default {
name: "App",
data: () => {
return {
checkboxState: true,
};
},
methods: {
checkboxChanged() {
this.checkboxState = !this.checkboxState;
},
},
watch: {
checkboxState() {
// this is fired when the checkboxState changes
console.log("fired when checkboxState changes");
},
},
};
</script>
note: the function name and the variable must have the same name for watchers to work.
Like this Sandbox

How to register an array of objects with v-model? Vue 2

The first time that I dive into making this type of form with Vue, the issue is that I can't think of how to save the data inside the foreach that I generate with axios.
Where I would like to save the ID and the option selected with the input select as an object in order to make faster the match in the backend logic.
<template>
<div class="row" v-else>
<div class=" col-sm-6 col-md-6 col-lg-6" v-for="(project, index) in projects" :key="index">
<fieldset class="border p-2 col-11">
<legend class="w-auto col-12">Proyecto: {{project.name}}</legend>
<b-form-group
id="user_id"
label="Reemplazante"
>
<b-form-select
v-model="formProject[index].us"
:options="project.users"
value-field="replacement_user_id"
text-field="replacement_user_name"
#change="addReemplacemet($event,project.id)"
>
<template v-slot:first>
<b-form-select-option value="All">Seleccione</b-form-select-option>
</template>
</b-form-select>
<input type="hidden" name="project" v-model="formProject[index].proj">
</b-form-group>
</fieldset>
</div>
</div>
</template>
<script>
import skeleton from './skeleton/ProjectUserSkeleton.vue'
export default {
name: 'ProjectsUser',
components: { skeleton },
props:{
user: { type: String },
},
data() {
return {
user_id: null,
showProject: false,
projects: [],
loadingProjects: true,
formProject: [
{
us: 'All',
proj: null
}
]
}
},
watch: {
user: function() {
this.viewProjects(this.user)
}
},
methods: {
async getProjects(salesman){
this.loadingProjects = true
await axios.get(route('users.getProjects'),{
params: {
filter_user: salesman
}
})
.then((res)=>{
this.projects = res.data.data
setTimeout(() => {
this.loadingProjects = false
}, 800);
})
},
This is the form:
This is the message error:
At first glance, this looks like an issue with data. Your error suggests that you're trying to read an undefined variable.
It's often undesirable to use an index from iterating one array on another. In your Vue code, the index is projects, but you use it to access the variable formProject. This is usually undesirable because you can no longer expect that index to reference a defined variable (unless you're referencing the array you are currently iterating).
The easiest solution, for now, is to make sure the arrays are of the same length. Then utilizing v-if or other methods to not render the snippet if the variable is not defined.
A more complicated but better solution is restructuring your data such that formProject exists in projects

Why are checkboxes not reset by v-model?

This is what i have:
Template
<div
v-for="(filter, index) in filtersList"
:key="index"
class="option-block"
>
<label
v-for="value in filter.values"
:key="value.id"
class="option-block__container"
>
{{ value.title }}
<input
type="checkbox"
v-model="filtersValues[filter.name]"
:value="value.value"
>
<span class="option-block__checkmark"></span>
</label>
</div>
And the part of my vue code:
data() {
return {
filtersList: {},
filtersValues: {}
}
},
beforeMount() {
this.loadInitData();
this.initFilters();
},
methods: {
loadInitData() {
const data = JSON.parse(this.$el.getAttribute('data-data'));
this.filtersList = data.filters;
},
initFilters() {
for (let i in this.filtersList) {
if (!this.filtersList.hasOwnProperty(i)) {
continue;
}
this.filtersValues[this.filtersList[i].name] = [];
}
}
}
It works, but when i call initFilters() method again (for reseting) checkboxes are still selected, and i don't know why.
The way you are assigning new, empty arrays to filterValues is not reactive.
If you change your initFilters to assign an entire new value to filterValues, you don't need to worry about using Vue.set(). For example
initFilters() {
this.filtersValues = this.filtersList.reduce((vals, { name }) => ({
...vals,
[ name ]: []
}), {})
}
Demo ~ https://jsfiddle.net/cjx09zwt/
Where did filter.values come from in line 2 of template?
Anyways vue would not be able to track the changes you are making (judging from the visible code)
There are some caveats to vue 2's reactivity. Check here for more info.
TLDR; you will need to declare anything you want to be made reactive in the component's data option upfront.
HTH

dynamically show and hide button according to computed property in vuejs

i want to show delete button for each comment that a particular user made, but i am unable to do it, i am using v-bind to disable delete buttton for others comment, so that user cant delete others comment, but its still visible for all the comments i.e (for other users as well ). suppose i am a user i comment 3 times then delete button should show on my comments only not on others comment. can some one please help me to achieve this?
My code snippet is below
<div class="comment-list" v-for="comment in comments" :key="comment._id">
<div class="paragraph" :class="[name, onCaretButtonClick ? 'paragraph' : 'hide']">
<span class="names" id="comment-desc">
<label class="comm-name">{{ comment.name }}</label>
<button class="like-btn" id="like-comment"><i class="fas fa-heart"></i></button>
<label> {{ comment.likes + ' likes' }} </label>
<button v-bind:disabled="isCommentIdMatched" v-on:click="deleteComment(comment.userId)"
class="del-btn">delete</button>
</span>
<p>{{ comment.comment }}</p>
</div>
</div>
below is deleteComment function and computed properties that i am using
computed: {
comments() {
return store.state.comments
},
getUserId() {
return store.state.user._id
},
isCommentIdMatched() {
let comments = store.state.comments
let value = false
if(comments) {
comments.forEach((comment) => {
if(comment.userId.match(this.getUserId)) {
value = true
}
})
return value
}
else {
return value
}
}
},
methods: {
deleteComment: function(commentUserId) {
let userId = store.state.user._id
if(commentUserId.match(userId)) {
console.log('yes matched')
}
},
}
there is no need to write isCommentIdMatched property, instead you can use change some lines.
add v-bind="comments" in below line
<div v-bind="comments" class="comment-list" v-for="comment in comments" :key="comment._id">
and add v-if="comment.userId && comment.userId.match(getUserId)" in below button
<button v-if="comment.userId && comment.userId.match(getUserId)" v-on:click="deleteComment(comment.userId)" class="del-btn">delete</button>

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

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.