How can I get the :value from input with Vuejs? - vue.js

Hi I have list like this:
<tr v-for="(post, index) in posts" v-bind:index="index">
<td>{{ post.rut }}</td>
<td>{{ post.names }} {{ post.father_lastname }} {{ post.mother_lastname }}</td>
<td>
<input type="number" class="form-control" id="exampleInputEmail1" v-bind:value="post.employee_id" #input="form.amount[post.employee_id]" placeholder="Ingresa el monto">
</td>
</tr>
I defined in v-bind:value="" a initial value for every input of the list, then I need to send that data with axios but when I do that it does not send anything I mean I can not catch the vale for every input why? because it displays the value.. my axios is:
onSubmit(e) {
this.loading = true; //the loading begin
e.preventDefault();
let currentObj = this;
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
let formData = new FormData();
formData.append('amounts', JSON.stringify(this.form.amount));
axios.post('/api/payroll_management/store?api_token='+App.apiToken, formData, config)
.then(function (response) {
currentObj.success = response.data.success;
})
.catch(function (error) {
console.log(error);
});
}
so I wonder how can I get the data from the inputs? if it returns empty this.form.amount
Thanks

Since each post has an amount value that gets changed with the <input>, it is easier to have that value be part of the post item itself.
This is done using v-model="post.amount" (see documentation) on the <input> of each post.
This way, there is a single place where the amount value is and where it gets updated.
Then when you submit the form, you can get the an array of these amount values by using a computed property (see documentation).
For better understanding what is happening, I highly recommend going through VueJS's documentation, since it's very readable and explains everything quite well.
Now, bringing it all together, have a look at this example:
new Vue({
el: "#app",
data: {
posts: [
{
rut: "A",
names: "Name Name",
father_lastname: "Lastname",
mother_lastname: "Lastname2",
employee_id: 5,
amount: 5, // Default value here
},
{
rut: "B",
names: "Name Name",
father_lastname: "Lastname",
mother_lastname: "Lastname2",
employee_id: 2,
amount: 2, // Default value here
},
],
},
computed: {
// Make form data a computed object.
form: function() {
// Get only the amount values from the posts.
// The inputs will update those automatically,
// so these will change as well.
let amount = this.posts.map((post, idx) => {
return parseInt(post.amount); // parseInt() is optional here
});
return {
amount: amount,
// ... other stuff
};
},
},
methods: {
getFormData: function() {
console.log( JSON.stringify(this.form.amount) );
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<h2>Posts:</h2>
<table>
<tr v-for="(post, index) in posts" v-bind:index="index">
<td>{{ post.rut }}</td>
<td>{{ post.names }} {{ post.father_lastname }} {{ post.mother_lastname }}</td>
<td>
<input type="number" class="form-control" v-model="post.amount">
</td>
</tr>
</table>
<br/>
<button v-on:click="getFormData()">Console log form data</button>
</div>

Related

re render tabel get json vuejs

how to render a table after an update delete or insert action here I have a table using the following code
<tbody>
<tr v-for="(item, index) in DATASKILL" :key="item.ID">
<td>{{ index + 1 }}</td>
<td>{{ item.skills }}</td>
<td>{{ item.profiency }}</td>
<td class="text-xs-center">
</tr>
</tbody>
export default {
data: function() {
return {
item: {
skills: "",
profiency: "",
idusers : parseInt(localStorage.getItem("userId")),
},
};
},
computed: {
DATASKILL() {
return this.$store.state.skill //call json using axios in store
},
},
methods:{
Submited() {
this.$store
.dispatch("createSkills", this.item)
.then((response) => {
// setTimeout(()=>{
// this.$store.dispatch('getSkill') // load response json use action get in store
// },2000)
})
.catch((error) => {
error;
});
},
}
when I insert data using the modal form, how do I make the table render without being refreshed?

'pagination' has been removed, use 'options' instead vuetify

<template>
<div>
<v-data-table
:items="agents"
hide-default-footer
class="agent-table"
v-bind:pagination.sync="pagination">
<template slot="item" slot-scope="props">
<tr>
<td>{{ props.item.first_name }} {{ props.item.last_name }}</td>
<td>{{ props.item.email }}</td>
<td>{{ props.item.phone }}</td>
</tr>
</template>
</v-data-table>
<div >
<v-pagination v-model="pagination.page" :length="pages" :total-visible="7"></v-pagination>
</div>
</div>
<template>
<script>
export default {
data: function() {
return {
pagination: {
rowsPerPage: 15,
page: 1
},
agents:[]
}
},
computed: {
pages () {
return this.pagination.rowsPerPage && this.agents.length !== 0 ? Math.ceil(this.agents.length / this.pagination.rowsPerPage) : 0
},
},
created() {
this.fetchAgents();
}
methods: {
fetchAgentss() {
var that = this;
this.$axios.get('agents.json')
.then(response => {
that.agents = response.data.agents;
});
}
}
}
</script>
I am upgrading from vuetify version 1.0.5 to 2.3.10 and I am using v-pagination for custom pagination but I am getting this error
[breaking] 'pagination' has been removed, use 'options' instead
Please help me find where I am going wrong
Instead of using v-bind:pagination.sync use v-bind:options.sync
{
page: number,
itemsPerPage: number,
sortBy: string[],
sortDesc: boolean[],
groupBy: string[],
groupDesc: boolean[],
multiSort: boolean,
mustSort: boolean
}
Refer Official API
For Example

Change v-model value without changin the actual data

So i've this data
data: () => ({
products: [
{ id: 1, name: "Prod 1", price: 2, stock: 5 },
{ id: 2, name: "Prod 2", price: 3, stock: 6 }
]
})
Template
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
</tr>
</thead>
<tbody>
<tr v-for="product in products" :key="product.id">
<td>{{ product.id }}</td>
<td>{{ product.name }}</td>
<td>
<input
type="text"
class="form-control"
v-model="product.price"
#paste.prevent
/>
</td>
<td>
<input
type="text"
class="form-control"
maxlength="999"
v-model="product.stock"
#paste.prevent
#keypress="onlyNumber($event)"
#input="handleInputStock($event.target.value)"
#blur="updateStock($event.target.value, product.id)"
/>
</td>
</tr>
</tbody>
</table>
So what I want is that when the user hit delete/backspace from the stock input field the value cannot be empty (blank) or it must be greater than or equal to zero. but without changing the products.stock value. this is because I need the product.stock value to compare with the changed value (stock input field) before sending to the server. So if stock value is equal to product.stock don't send to server otherwise send and update stock value.
so here's what i've done so far.
prevent the stock value empty but not working
handleInputStock(value) {
return +value.replace(/[^0-9]/g, "");
},
update stock
updateStock(stock, productId) {
const productStock = this.products.find(product => product.id == productId).stock;
if (!(stock == productStock)) {
// do ajax
}
},
onlyNumber
onlyNumber(e) {
const charCode = e.which ? e.which : event.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
e.preventDefault();
}
},
Personally this feels like a higher level question to which your flow of product editing needs tweaking. Here is what I can think of:
User enters all the information.
User hits submit button.
Check whether of not the stock count is empty or 0.
Return an error message if it is.
Submit and update otherwise.
It might be worth looking into vuelidate that handles such validation in JavaScript. Meanwhile, we are also coming up with a tool called CRUDS DS (a WIP) that handles such situation with ease.
The best way is to create a ProductComponent and watch every product separately inside its own component, as shown below:
Product.vue
<ProductComponent
v-for="product in products"
:product="product"
:key="product.id" />
ProductComponent.vue
<template>
<tr>
<td>{{ product.name }}</td>
<td>
<input
type="text"
class="form-control"
v-model="product.price"
#paste.prevent
/>
</td>
<td>
<input
type="text"
class="form-control"
maxlength="999"
v-model="product.stock"
#paste.prevent
#keypress="onlyNumber($event)"
#blur="updateStock($event.target.value, product.id)"
/>
</td>
</tr>
</template>
<script>
export default {
props: {
product: {
type: Object,
default: {},
},
},
data: () => ({ actual_stock: "" })
// this is for handle stock cannot be empty or GTE:0
// also you dont need handleInputStock anymore
watch: {
product: {
handler(val) {
this.actual_stock = val.stock;
},
immediate: true,
},
"product.stock": function (newVal, oldVal) {
this.product.stock = +newVal;
},
},
methods: {
updateStock(stock, productId) {
if (!(stock == this.actual_stock)) {
// do ajax
}
}
}
}
</script>
If you want to handle it on parent side, you may use $emit to send an event upwards.
Can we have two versions of products? One for the server, one for v-models.
var server_products = [
{ id: 1, name: "Prod 1", stock: 5 },
{ id: 2, name: "Prod 2", stock: 6 }
]
//...
data: () => ({
products = server_products
})
updateStock(stock, productId) {
server_products.forEach((product) => {
if(product.id === productId && stock !== product.stock){
product.stock = stock
// do ajax
}
})
},
//...
If not than you can use vue's watch property so vue finds changes to the array for you.
//...
data: () => ({
products: [
{ id: 1, name: "Prod 1", stock: 5 },
{ id: 2, name: "Prod 2", stock: 6 }
]
}),
watch: {
'products': {
handler: function(newValue) {
// do ajax
},
deep: true
}
}
//...

Vue.js/Axios - Duplicate results in list. Has unique-keys in v-for

I have two other uses of v-for in separate components. They also sometimes throw errors. All three v-for invocations are wrapped with v-if/else. Here is the code that produces duplicate key errors & renders data twice:
AccountDashboard.vue
<tbody>
<tr v-if="!residents.length" class="table-info">
<td class="text-center">
<p>
No residents on record.
</p>
</td>
</tr>
<template v-else>
<tr is="AccountResidentList"
v-for="resident in residents"
v-bind:key="'resident-list-' + resident.id"
v-bind:first_name="resident.first_name"
v-bind:last_name="resident.last_name"
v-bind:dob="resident.dob | date_formatted"
>
</tr>
</template>
</tbody>
Note the unique id attempt in the binding of key.
Here is a look at the child component
ProviderAccountList.vue
<template>
<tr class="AccountResidentList">
<td>
{{ this.$attrs.id }}
</td>
<td>
{{ this.$attrs.first_name }} {{ this.$attrs.last_name }}
</td>
<td>
{{ this.$attrs.dob }}
</td>
<td>
<button #click="toResidentProfile({account_id, id})" class="btn btn-sm btn-purple btn-with-icon">
<div class="ht-25">
<span class="icon wd-25"><i class="fa fa-eye"></i></span>
<span class="pd-x-10">view</span>
</div>
</button>
</td>
<!--TODO: Add view profile button-->
</tr>
</template>
<script>
import Axios from "axios";
import router from "../../router";
import { mapGetters } from "vuex";
import moment from "moment";
export default {
name: "AccountResidentList",
computed: {
...mapGetters['Resident', {
resident: 'getResident'
}]
},
filters: {
date_formatted: (date) => {
return moment(date).format('MMMM Do, YYYY');
}
},
methods: {
toResidentProfile(account_id, resident_id) {
router.push(`/accounts/${account_id}/residents/${resident_id}`)
}
},
};
</script>
<style scoped></style>
My Axios call looks like:
Account.js (a namespaced vuex-module)
async retrieveAccount(context, account_id) {
// Axios.defaults.headers.common['Authorization'] = 'Bearer ' + window.$cookies.get('jwt')
let response
let valid_id = window.$cookies.get('valid_id');
response = await Axios.get(`http://localhost:3000/api/v1/providers/${valid_id}/accounts/${account_id}`, { headers: { 'Authorization': 'Bearer ' + window.$cookies.get('jwt') } })
.then((response) => {
let account = response.data.locals.account;
let account_address = response.data.locals.account_address;
let residents = response.data.locals.residents;
// set Account
context.dispatch('Account/setId', account.id, {root: true});
context.dispatch('Account/setProviderId', account.provider_id, {root: true});
.
.
.
// set AccountAddress
// !Array.isArray(array) || !array.length
if (account.address) {
context.dispatch('Account/setAddressId', account_address.id, {root: true});
context.dispatch('Address/setId', account_address.id, {root: true});
.
.
.
// set AccountResidents
// !Array.isArray(array) || !array.length
residents.forEach(resident => {
if (resident) {
// Add object to parent's list
context.dispatch('Account/setResidents', resident, {root: true}); // Set attr values for object
context.dispatch('Resident/setId', resident.id, {root: true});
.
.
.
(remaining attrs removed for brevity)
}
})
router.push(`/providers/${account.provider_id}/accounts/${account_id}`);
})
.catch(function(error) {
console.log(error);
})
Note: the Account action #setResidents simply calls the mutator that adds one resident to a list total.
i.e state.list.push(resident)
I logged the response to the console and can confirm that the data isn't being sent twice (or more) from my Axios call.
I have reviewed & attempted the following to no avail:
https://alligator.io/vuejs/iterating-v-for/
https://www.reddit.com/r/vuejs/comments/7n3zi4/vue_warn_duplicate_keys_detected_vfor_with/
https://github.com/hejianxian/vddl/issues/23
https://github.com/hejianxian/vddl#warning
https://medium.com/#chiatsai/vue-js-common-issue-duplicate-keys-stops-components-rendering-df415f31838e
Finally, It should be mentioned that I have tried variations of using/not using template to wrap the list, including/not including the for loop in the template, etc..
Did not anticipate it would be this bothersome to iterate a collection.
Am I overlooking something obvious?
Update: What worked for me
I needed access to the resident.id also the id declared in the paren seems like an index. So here is a look at what removed the duplicate render errors and allow me access to the resident's id even after fixing the duplicate keys error:
<template v-else>
<tr is="AccountResidentList"
v-for="(resident, id) in residents"
v-bind:key="id"
v-bind:id="resident.id"
v-bind:first_name="resident.first_name"
v-bind:last_name="resident.last_name"
v-bind:dob="resident.dob | date_formatted"
>
</tr>
</template>
Thanks again #Billal Begueradj for the assist!
For me, I suspect that in residents there are entries which have the same id. So we have to find out a way to overcome this issue. We can give it an efficient try as follows:
<tr
is="AccountResidentList"
v-for="(resident, id) in residents"
:key="id"
// rest of your code

Vuejs2 - List rendering filtered with computed properties

I've some problems with list rendering and filtering the data with computed properties
Instead of hardcoded row.age value, I'd like to use filterKey to filter row.age.
How to archieve this? I just don't get it.
Here's my example:
template:
<button type="button" class="btn btn-t1-secondary" v-on: click="filterKey = '15'">11</button>
<button type="button" class="btn btn-t1-secondary" v-on: click="filterKey = '30'">8</button>
<table>
<thead>
<tr>
<th>Category</th>
<th>Age</th>
<th>Food</th>
</tr>
</thead>
<tbody>
<tr v-for="row in filteredCategory">
<td>{{ row.category }}</td>
<td>{{ row.age }}</td>
<td>{{ row.food }}</td>
</tr>
</tbody>
</table>
JavaScript:
<script>
var app = new Vue({
el: '#app',
data: {
filterKey: '',
filterCategory: '',
dataToFilter: [
{
category: 'dog',
age: '11',
food: 'bone'
},
{
category: 'cat',
age: '8',
food: 'fish'
}
//etc.
]
},
computed: {
filteredCategory() {
return this.dataToFilter.filter(function (row) {
return row.category === 'dog'
})
.filter(function (row) {
console.log(this.filterKey)
return row.age === '15'
})
},
}
})
</script>
Solution
As #Sadraque_Santos suggested, I used arrow functions.
Code
filteredCategory() {
return this.dataToFilter.filter( r => r.category === 'dog' && r.age === this.filterKey);
}
Also, I have to support IE11 so I just use Babel to compile the code for me.
To have access to this inside a filter, map or another useful method you must learn about arrow functions, they allow you to create a function without the this bound to that object, so instead of using:
filteredCategory () {
return this.dataToFilter.filter(function (row) {
return row.category === 'dog'
})
.filter(function (row) {
console.log(this.filterKey)
return row.age === '15'
})
}
Your code should be like this:
filteredCategory () {
return this.dataToFilter
.filter((row) => row.category === this.filterCategory)
.filter((row) => row.age === this.filterKey)
}