how to get v-for loop data from outside of loop also in vue.js - vue.js

I have a table which show product name and quantity and price and total price. I had written logic of total cost as formula cost *quantity. i have a button outside of table which is by default hidden by using v-if directive how can i make that button active if only at least one product quantity is greater than zero. By default i had given 0 as quantity because it will vary according to user. I have array of products in v-for loop i iterated as v-for="p in products" so quantity will be p.quantity. how can i use that p.quantity also from outside of loop
## Html table ##
<table class="table table-striped">
<thead>
<tr>
<td>S.No#</td>
<td>Product</td>
<td>Cost</td>
<td>Quantity</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<tr v-for="p in products">
<td>1</td>
<td>{{p.item}}</td>
<td>{{p.cost}}</td>
<td><input type="number" class="form-control qty-box" name="" v-model='p.qt' min="0"></td>
<td>{{p.cost*p.quantity}}</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-md-12">
<center v-if="btn"><button class="btn btn-success">Confirm</button></center>
</div>
</div>
## Vue-cli Code ##
<script>
export default {
name: 'app',
data () {
return {
btn:false,
counter:8,
qty:0,
proTotal:'',
products:[
{'item':'timber','cost':250,'id':1, 'quantity ':0},
{'item':'wood','cost':240,'id':2, 'quantity ':0},
{'item':'primer','cost':120,'id':3, 'quantity ':0},
{'item':'plywood','cost':360,'id':4, 'quantity ':0},
{'item':'marker','cost':220,'id':5, 'quantity ':0},
{'item':'roughwood','cost':480,'id':6, 'quantity ':0},
],
msg: 'Counter',
}
},
mounted:function(){
this.bill();
},
methods:{
bill(){
this.qty = this.p.quantity;
if(this.qty>0){
btn:true;
}
}
}
}
</script>

That's a good use case for computed properties:
computed: {
showButton() {
var showButton = false;
this.products.forEach(product => {
if (product.quantity > 0) {
showButton = true;
}
});
return showButton;
}
}
Also, you have to add number to v-model so it's not stored as string.
Your whole code would look like this:
<template>
<div id="about">
<table class="table table-striped">
<thead>
<tr>
<td>S.No#</td>
<td>Product</td>
<td>Cost</td>
<td>Quantity</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<tr v-for="(p, index) in products" :key="index">
<td>1</td>
<td>{{p.item}}</td>
<td>{{p.cost}}</td>
<td><input type="number" class="form-control qty-box" name="" v-model.number='p.quantity' min="0"></td>
<td>{{p.cost*p.quantity}}</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-md-12">
<p v-if="showButton">
<button class="btn btn-success">Confirm</button>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {
btn: false,
counter: 8,
qty: 0,
proTotal: "",
products: [
{ item: "timber", cost: 250, id: 1, quantity: 0 },
{ item: "wood", cost: 240, id: 2, quantity: 0 },
{ item: "primer", cost: 120, id: 3, quantity: 0 },
{ item: "plywood", cost: 360, id: 4, quantity: 0 },
{ item: "marker", cost: 220, id: 5, quantity: 0 },
{ item: "roughwood", cost: 480, id: 6, quantity: 0 }
],
msg: "Counter"
};
},
computed: {
showButton() {
var showButton = false;
this.products.forEach(product => {
if (product.quantity > 0) {
showButton = true;
}
});
return showButton;
}
}
};
</script>

Related

try to send from data to v-for in Vue but it look like missing something

I use v-for in html is correct way or not or I can not use v-for
in vue3 'items:' is defined but never used but i try to use in iteration with v-for how to fix it I am not sure the way that
<template>
<div id="app">
<table>
<tbody>
<tr v-for="(item, index) in items">
<td><input v-model.number="item.qty" size="10"></td>
<td><input v-model.number="item.price" size="10"></td>
<td><input v-model.number="subtotalRow[index]" readonly size="10"></td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>{{total}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
items: [
{qty: 5, price: 25 },
{qty: 3, price: 88 }
]
return {};
},
computed: {
subtotalRow() {
.....
},
total() {
...
}
}
};
</script>
I can fix by change
<div v-for="(item, index) in items"> {{index}}. {{item.name}} </div>
to
<div v-for="(item, index) in items" :key="item.id"> {{index}}. {{item.name}} </div>
and change data return to
data() {
return {items: [
{qty: 5, price: 25 },
{qty: 2, price: 16 },
{qty: 8, price: 320 },
{qty: 3, price: 88 }
]};
},

Vue JS Checkbox select all With Nested Array

I’m not sure If I am doing this correctly but I am trying to collect an Array of Id’s that I will use to update data on my back end,
I implemented checkboxes but I do not know how to add support when parent checkbox is selected to select all children checkbox , and also when select all children checkbox to select parent checkbox ?
here is i'm tried this so far:
export default {
data() {
return {
userlistes: [
{
id: 2,
username: "Larry",
department_id: 3,
department: {
department_name: "IT",
id: 3,
},
worklists: [
{
id: 278,
user_id: 2,
task_id: 1,
date: "2021-07-30",
hour: 2,
description: "A",
is_overtime: false,
overtime_hour: 0,
task: {
taskname: "Task A",
},
hr_checked: false,
},
{
id: 277,
user_id: 2,
task_id: 1,
date: "2021-07-30",
hour: 3,
description: "B",
is_overtime: false,
overtime_hour: 0,
task: {
taskname: "Task B",
},
hr_checked: false,
},
],
},
{
id: 4,
username: "Tom",
department_id: 2,
department: {
department_name: "Business",
id: 2,
},
worklists: [
{
id: 259,
user_id: 4,
task_id: 7,
date: "2021-07-27",
hour: 6.5,
description:
"A",
is_overtime: false,
overtime_hour: 0,
task: {
taskname: "Task A",
},
hr_checked: false,
},
{
id: 260,
user_id: 4,
task_id: 7,
date: "2021-07-27",
hour: 0.5,
description: "B",
is_overtime: false,
overtime_hour: 0,
task: {
taskname: "Task B",
},
hr_checked: false,
},
],
},
],
isChecklist: [],
checkAll: false,
};
},
methods: {
clickCheckAll() {
var _this = this;
_this.checkAll = !_this.checkAll;
for (var i = 0; i < _this.userlistes.worklists.length; i++) {
var checkedData = _this.userlistes.worklists[i];
checkedData.hr_checked = _this.checkAll;
updateWorkhourAPI(checkedData.id, checkedData);
}
},
clickCheckbox(id, worklist) {
var _this = this;
worklist.hr_checked = !worklist.hr_checked;
if (worklist.manager_checked) {
_this.isChecklist.push(id);
updateWorkhourAPI(id, worklist);
} else {
var last = _this.isChecklist.length - 1;
_this.isChecklist.splice(last, 1);
updateWorkhourAPI(id, worklist);
}
if (_this.isChecklist.length == _this.userlistes.length) {
_this.checkAll = true;
} else {
_this.checkAll = false;
}
},
},
};
<b-card no-body class="mb-1" v-for="users in userlistes" :key="users.id">
<b-card-header header-tag="header" class="p-0" role="tab">
<div class="d-grid gap-2">
<b-button
block
variant="outline-primary"
v-b-toggle="`accordion-${users.id}`"
>
{{ users.username }}
</b-button>
</div>
</b-card-header>
<b-collapse
:id="`accordion-${users.id}`"
accordion="table-accordion"
role="tabpanel"
>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th colspan="10">
<h3 style="text-align: center">
{{ users.username }} Work-Lists
</h3>
</th>
</tr>
<tr>
<th>Task Name</th>
<th>Date</th>
<th>Description </th>
<th>Hour (hr)</th>
<th>Overtime </th>
<th>Overtime Hour (hr)</th>
<th>
<label class="form-checkbox">
<input
type="checkbox"
#click="clickCheckAll()"
v-model="checkAll"
/>
<i class="form-icon"></i>
</label>
</th>
</tr>
</thead>
<tbody>
<tr v-for="worklist in users.worklists" :key="worklist.id">
<td>{{ worklist.task.taskname }}</td>
<td>{{ worklist.date }}</td>
<td>{{ worklist.description }}</td>
<td>{{ worklist.hour }}</td>
<td>{{ worklist.is_overtime ? "Yes" : "No" }}</td>
<td>{{ worklist.overtime_hour }}</td>
<td>
<label class="form-checkbox">
<input
type="checkbox"
#click="clickCheckbox(worklist.id, worklist)"
v-model="worklist.hr_checked"
/>
<i class="form-icon">
{{ worklist.hr_checked }}
</i>
</label>
</td>
</tr>
</tbody>
</table>
</b-collapse>
</b-card>
i figured it out how to solve this problem: count array index ,
thanks advanced
<b-card no-body class="mb-1" v-for="(users, idx) in userlistes" :key="users.id">
<b-collapse
:id="`accordion-${users.id}`"
accordion="table-accordion"`enter code here`
role="tabpanel"
>
<table class="table table-striped table-bordered">
<thead>
<th>
<label class="form-checkbox">
<input
type="checkbox"
#click="clickCheckAll(idx)"
:value="allChecked(idx)"
/>
<i class="form-icon"></i>
</label>
</th>
</tr>
</thead>
</table>
</b-collapse>
</b-card>
export default {
data() {
return { //.. };
},
methods: {
allChecked(idx) {
return this.userlistes[idx].worklists.some((el) => el.hr_checked)
},
clickCheckAll(idx) {
this.checkAll = !this.checkAll;
const currentUser = this.userlists[idx]
for (let i = 0; i < currentUser.worklists.length; i++) {
currentUser.worklists[i].hr_checked = this.checkAll;
}
},
},
}

How to store array to Vuex in VueJs

Can someone tell me how to write an array of objects in Vuex
I will explain the essence
In this situation, I need to create an order management system
I have an array of products with different data
This array I get from the server using axios request
Via v-for, I displayed this array in the select option html tag
Next, by clicking on the html option tag, I need to add the product to the data table
Also, with the addition of a specific product to the table, it is necessary that the product for which a click is made is recorded in the Vuex store, but not with rewriting, but with addition to existing data
Next, in synchronization with the addition to the Vuex store, information is output from the Vuex store to the table
this is my code in Vue Component
<div class="row">
<div class="col-md-8">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>QTY</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4">
<form>
<div class="form-group">
<label for="products">Select Products</label>
<select v-model="orderData" #change="addOrderData" id="products" class="form-control">
<option v-for="product in products" multiple v-bind:value="{productId: product.id, name: product.name, price: product.price}">{{product.name}}</option>
</select>
<pre>{{orderData}}</pre>
</div>
</form>
</div>
</div>
data() {
return {
selected: '',
formData: {
userId: ''
},
orderData: {
productId: [],
price: [],
total: [],
quantity: []
}
}
},
methods: {
addOrderData()
{
let data = {
productId: this.orderData.productId,
name: this.orderData.name,
price: this.orderData.price,
}
this.$store.commit('orders/setOrderProduct', data)
}
},
this is my code in Vuex store
function initialState () {
const orderProducts = [];
return {
orderProducts
}}
const getters = {
orderProducts(state)
{
return state.orderProduct;
},};
const mutations = {
setOrderProduct(state, orderProduct)
{
state.orderProduct = orderProduct;
}};
If I understand you correctly, please check the following:
template:
<select v-model="orderData" #change="addOrderData">
<option v-for="(product) in products" :key="product.productId" :value="{productId: product.productId, name: product.name, price: product.price}">
{{product.productId}} - {{product.name}}</option>
</select>
<br /><br />
<table>
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody v-if="orderProducts.length > 0">
<tr v-for="(item, index) in orderProducts" :key="index">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="2">No products to display</td>
</tr>
</tbody>
</table>
code:
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
orderProducts: []
},
mutations: {
addProduct(state, payload) {
state.orderProducts.push(payload);
}
}
})
new Vue({
store,
el: '#app',
data() {
return {
products: [{
productId: 1,
name: 'Product One',
price: 10
},
{
productId: 2,
name: 'Product Two',
price: 15
}
],
orderData: {
productId: [],
price: [],
total: [],
quantity: []
}
};
},
computed: {
orderProducts() {
return this.$store.state.orderProducts;
}
},
methods: {
addOrderData() {
this.$store.commit('addProduct', this.orderData);
}
}
});
The idea is when change event is triggered by selecting an option, you commit mutation to the store with the selected product as payload. The orderProducts computed property will refresh, and the table will get the latest data. You can check this jsfiddle.

Update Table Item Quantity

Guys I'm starting with Vue and I'm having a little difficulty. In the image below I have a table with some items and when I will increase the amount of the item Orange for example is increased all other items, how to fix it?
enter image description here
My code
new Vue({
el: '#app',
data() {
return {
quantity: 1,
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00" },
{ Code: 2, Name: 'Abacate', Price: "50.00" },
{ Code: 3, Name: 'Morango', Price: "60.00" },
{ Code: 4, Name: 'Maçã', Price: "17.00" },
{ Code: 5, Name: 'Laranja', Price: "30.00" }
]
}
},
methods: {
add() {
this.quantity++
},
remove() {
if(this.quantity === 0) {
this.quantity = 0
} else {
this.quantity--
}
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove">-</button>
<input type="text" :value="quantity">
<button #click="add">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
You should just need to have a quantity on each item in your list. You'd then pass the relevant item to add or remove.
new Vue({
el: '#app',
data() {
return {
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00", quantity: 1 },
{ Code: 2, Name: 'Abacate', Price: "50.00", quantity: 1 },
{ Code: 3, Name: 'Morango', Price: "60.00", quantity: 1 },
{ Code: 4, Name: 'Maçã', Price: "17.00", quantity: 1 },
{ Code: 5, Name: 'Laranja', Price: "30.00", quantity: 1 }
]
}
},
methods: {
add(fruit) {
fruit.quantity++
},
remove(fruit) {
if(fruit.quantity !== 0) {
fruit.quantity--
}
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove(fruit)">-</button>
<input type="text" v-model.number="fruit.quantity">
<button #click="add(fruit)">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
I've also switched :value to v-model.number, which seems more likely to be what you'd want though it's not directly related to the problem mentioned in the question.

Vuejs2- How to call a filter function from a method

I am using "moneyFormat" filter for formatting the currency value. It's formatting the values which is defined already. I want to format the dynamic values. Hence I have called the filter function through a method called "displayValue", but I am getting error
and the given input field also not updated.
Here is my code :
<template>
<b-card>
<div class="panel-body" id="app">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 20px;">No.</th>
<th style="width: 330px;">Description</th>
<th style="width: 130px;" class="text-right">Charges</th>
<th style="width: 130px;">Total</th>
<th style="width: 130px;"></th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows" :key="row.qty">
<td>
{{ index +1 }}
</td>
<td>
<select name="" id="" class="form-control" v-model="row.billChgDesc">
<option v-for="option in billChgDescOpt" v-bind:value="option.value"
:key="option.value"> {{ option.text }}
</option>
</select>
</td>
<td>
<input #input="displayValue" class="form-control text-right" type="text" v-model="row.charges" data-type="currency" v-validate="'required'" :name="'charges' + index">
<span v-show="vErrors.has('charges' + index)" class="is-danger">{{ vErrors.first('charges' + index) }}</span>
<td>
<input class="form-control text-right" :value="row.qty * row.charges | moneyFormat" number readonly />
<input type="hidden" :value="row.qty * row.charges * row.tax / 100" number/>
</td>
<td>
<button class="btn btn-primary btn-sm" #click="addRow(index)"><i class="fa fa-plus"></i></button>
<button class="btn btn-danger btn-sm" #click="removeRow(index)"><i class="fa fa-minus"></i></button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right">DELIVERY</td>
<td colspan="1" class="text-right"><input class="form-control text-right" v-model="delivery" number/></td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</b-card>
</template>
<script>
import Vue from 'vue'
import accounting from 'accounting'
export default {
filters:{
moneyFormat: function (val){
if (val > 0) {
return accounting.formatMoney(val, " ₹ ", 2, ",", ".");
}
}
},
data: function () {
return {
billChgDescOpt: [
{ value: '', text: 'Select' },
{ value: 'M', text: 'Maintenance Fee'},
{ value: 'W', text: 'Water Charges'},
{ value: 'P', text: 'Penalty Fee'},
],
rows: [
{qty: 5, billChgDesc: '', charges: 55.20, tax: 10},
{qty: 19, billChgDesc: '', charges: 1255.20, tax: 20},
],
grandtotal: 0,
delivery: 40
}
},
computed: {
total: function () {
var t = 0;
$.each(this.rows, function (i, e) {
t += accounting.unformat(e.total, ",");
});
return t;
},
taxtotal: function () {
var tt = 0;
$.each(this.rows, function (i, e) {
tt += accounting.unformat(e.tax_amount, ",");
});
return tt;
}
},
methods: {
addRow: function (index) {
try {
this.rows.splice(index + 1, 0, {});
} catch(e)
{
console.log(e);
}
},
removeRow: function (index) {
this.rows.splice(index, 1);
},
displayValue:function (e) {
var value = e.target.value
var a = this.filters.moneyFormat(value);
return a;
}
}
}
</script>
<style lang="scss" scoped>
.is-danger{
color: RED;
}
</style>
You could use:
this.$options.filters.moneyFormat(value)
Check: https://v2.vuejs.org/v2/api/#vm-options
For global filters, first set:
Vue.prototype.$filters = Vue.options.filters
And then:
this.$filters.foo
Edit:
Looking closer your code, you are not using the filter as a Vue filter and only calling from one point (a method) instead of calling inline from HTML, maybe it's better that the method itself returns the value of the input, like:
displayValue: function (e) {
var val = e.target.value
if (val > 0) {
return accounting.formatMoney(val, " ₹ ", 2, ",", ".");
}
}
Did it work? Or the same error is shown? If yes, can you paste the error?
Hope it helps!
As it's been said, if you want to use the filter, you need to do this.$options.filters.moneyFormat(value)
What you're trying to achieve it's rendered the moneyFormat inside an input and the value displayed is the v-model. It's this one you have to format.
So you can initialize a new data property filled with each row.charges formatted on mounted:
data: function () {
return {
rows: [
//...
],
currentCharges: []
}
},
mounted() {
this.rows.forEach(row => {
let formattedCharges = this.$options.filters.moneyFormat(row.charges)
this.currentCharges.push(formattedCharges)
})
},
and use this data to fulfill your inputs:
<tr v-for="(row, index) in rows">
<td>
<input v-model="currentCharges[index]" #input="displayValue($event, index)">
<td>
To keep the current row.charges updated, reassign it when the v-model updates:
methods: {
displayValue:function (e, index) {
// the target value is a string like this " ₹ 55.20"
// split it and convert the last element to Float type
let arrValue = e.target.value.split(" ")
let parseValue = parseFloat(arrValue[arrValue.length -1])
// reassign the row.charges with the new float value
this.rows[index].charges = parseValue
}
},