How to pass data to method from a vue element iteration - javascript

I am developing an invoice system in laravel vuejs. I am trying to pass data to the method from a form. In this form, I have used iteration to add/remove input text/select fields. In order to Iterate I have used v-model of these inputs. Now these v-models fail to pass data. When I console, I see they are empty.
I am sharing codes of that form :
For Iteration
<div class="form-group" v-for="(item,k) in inputs" :key="k">
<div class="row mb-2">
<div class="col-md-3">
<select class="form-control" v-model="item.product_id"
#change="getProductCost()">
<option value="">Select Product</option>
<option v-for="(product, i) in products" :key="i" :value="product.id">{{
product.product_name }}</option>
</select>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Quantity" v-
model="item.quantity" #keyup="getProductCost">
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Total" v-
model="item.total">
</div>
<div class="col-md-3">
<span>
<i class="fa fa-minus-circle text-danger" #click="removeElement(k)" v-
show="k || ( !k && inputs.length > 1)"></i>
<i class="fa fa-plus-circle text-success ml-4" #click="addElement(k)" v-
show="k == inputs.length-1"></i>
</span>
</div>
</div>
</div>
From script, I need to pass data (item : {}) to getProductCost() method
export default {
data() {
return {
allerrors : [],
inputs : [{
product_id : '',
quantity : '',
total : '',
}],
item : {
product_id : '',
quantity : '',
total : '',
}
}
},
getProductCost() {
axios.get('/api/product-cost?
product_id='+this.item.product_id+'&&quantity='+this.item.quantity,
this.data).then(response => {
this.data.total_product_price = response.data
})
},
addElement() {
this.inputs.push({
product_id : '',
quantity : '',
total : ''
})
},
removeElement (index) {
this.inputs.splice(index, 1)
},

Well, actually you are overwriting the scope of item in the forloop.
I could imagine, that you just have to rename this line
<div class="form-group" v-for="(item,k) in inputs" :key="k">
to something like this:
<div class="form-group" v-for="(input,k) in inputs" :key="k">
and check for renaming the coresponding references aswell.
Edit 1:
You can look here for the vuejs way to handle dynamic data bindings and adjust it to your case: https://blog.logrocket.com/how-to-make-form-elements-dynamic-in-vue-js/

Related

Vue.js What is the correct way to display the selected item from the dropdown?

I am trying to display the selected value in a pill badge that can be removed.
I tried using v-for but I keep breaking the form or it display the selected like this:
here is my code:
data()
{
sport: {
name: '',
sportSize: null,
externalId: '',
teamId: null,
},
teamTransformer: teamTransformer,
comboConfig: {
itemPerPage:30
}
additionalSearchField: null,
},
computed:
{
...mapGetters({
getTeamById: "getTeamById"
})
methodds:{
...mapActions({
fetchTeamsByName: "fetchTeamsByName",
fetchTeamtDetails: "fetchTeamDetails",
fetchOfferByName: "fetchOfferByName",
fetchTeamInfo: "fetchTeamInfo"
}),
async onTeamComboSelect({value})
{
this.teamId = value;
this.form.team = value;
this.form.teamId = value;
this.additionalSearchField = {teamId: this.teamId};
await this.fetchTeamInfo({id: this.teamId});
},
}
<div class="creation-form-field creation-form-field--with-error-wrapper">
<label
for="team"
class="inline-3-columns--camp-wizard"
>
<span class="title__field">Client*</span>
<combo-select
id="teams"
v-model="sport.teamId"
api-location="fetchTeamsByName"
api-details-location="fetchTeamDetails"
search-parameter="teamName"
:additional-search-fields="additionalSearchField"
:transformer="teamTransformer"
:config="{
...comboConfig,
searchLabel: 'Search teams',
showDefaultLabelOnSelect: true
}"
class="input input__typeahead"
#on-select-item="onTeamComboSelect"
/>
<input
v-model="sport.teamId"
type="hidden"
name="teamId"
class="form-control"
:data-vv-scope="sections[0].name"
value="team"
>
</label>
<div class="sport-results-decoration">
<div class="results">
<span
v-for="(teamName, key) in sport.teamId"
class="badge badge-pill badge-success"
>
<span>{{ teamName }}</span>
<font-awesome-icon
icon="times"
class="close"
#click="removeTeam()"
/>
</span>
</div>
</div>
</div>
I also tried {{sport.team}} and {{sport.teamId}} but I get
this
this is how my selected item shows up in inspector:
I tried using label but it shows up empty. Please help, how can I solve this problem?
Many thanks for any help :)

How to create dynamic onclick elements in vuejs without repeating same value

I am trying to create a form in vuejs, where a group of inputs can be append onclick. It works fine, but the problem is, All inputs return the same value. I am sharing an image here :
I am sharing my code from template :
<div class="form-group" v-for="(input,k) in data.invoice_product" :key="k">
<div class="row mb-2">
<div class="col-md-3">
<select class="form-control" v-model="data.invoice_product.product_id"
#change="getProductCost">
<option v-for="(product, i) in products" :key="i" :value="product.id">{{
product.product_name }}</option>
</select>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Quantity" v-
model="data.invoice_product.quantity" #keyup="getProductCost">
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Total" v-
model="data.invoice_product.total">
</div>
<div class="col-md-3">
<span>
<i class="fa fa-minus-circle" #click="removeElement(k)" v-show="k || ( !k
&& data.invoice_product.length > 1)">Remove</i>
<i class="fa fa-plus-circle" #click="addElement(k)" v-show="k ==
data.invoice_product.length-1">Add fields</i>
</span>
</div>
</div>
</div>
from my script (I am excluding irrelevant code segments) :
export default {
data() {
return {
data : {
customer_id : '',
vat : ''
},
inputs: [{
product_id : '',
quantity : '',
total : ''
}],
input: {
product_id : '',
quantity : '',
total : ''
},
products : []
}
},
methods : {
getProductCost() {
axios.get('/api/product-cost?
product_id='+this.item.product_id+'&&quantity='+this.item.quantity,
this.data).then(response => {
this.input.total = response.data
})
},
addElement() {
this.data.invoice_product.push({
product_id : '',
quantity : '',
total : ''
})
},
removeElement (index) {
this.data.invoice_product.splice(index, 1)
},
}
Input returns null if I use "input" instead :
The problem is not providing correct data to v-model.
Here, you make an iteration, where you get "input" as an element.
<div class="form-group" v-for="(input,k) in data.invoice_product" :key="k">
But here, you are providing "data.invoice_product" instead of "input".
<select class="form-control" v-model="data.invoice_product.product_id"
#change="getProductCost">
Just change "data.invoice_product.product_id" to "input.product_id", and also do it for other inputs.
You are already looping through data.invoice_product with this
<div class="form-group" v-for="(input,k) in data.invoice_product"> .... </div>
so the v-model on your select tag should be
<select v-model="input.product_id"> .... </select>
instead of
<select v-model="data.invoice_product.product_id"> .... </select>
Similar case for your input tags for Quantity and Total.
So, the code in your template should be something like this:
<div class="form-group" v-for="(input,k) in data.invoice_product" :key="k">
<div class="row mb-2">
<div class="col-md-3">
<select class="form-control" v-model="input.product_id"
#change="getProductCost">
<option v-for="(product, i) in products" :key="i" :value="product.id">{{
product.product_name }}</option>
</select>
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Quantity" v-
model="input.quantity" #keyup="getProductCost">
</div>
<div class="col-md-3">
<input type="text" class="form-control" placeholder="Total" v-
model="input.total">
</div>
<div class="col-md-3">
<span>
<i class="fa fa-minus-circle" #click="removeElement(k)" v-show="k || ( !k
&& data.invoice_product.length > 1)">Remove</i>
<i class="fa fa-plus-circle" #click="addElement(k)" v-show="k ==
data.invoice_product.length-1">Add fields</i>
</span>
</div>
</div>
</div>
[Updated]
Your scripts should be left as it was before:
export default {
data() {
return {
data : {
customer_id : '',
vat : '',
invoice_product: [{
product_id : '',
quantity : '',
total : ''
}],
},
input: {
product_id : '',
quantity : '',
total : ''
},
products : []
}
},
methods : {
addElement() {
this.data.invoice_product.push(this.input)
},
removeElement (index) {
this.data.invoice_product.splice(index, 1)
},
}

Get the value of inputs and convert them to a certain array format

I'm trying to get the value of all input that is located in a table header created using ng-repeat upon clicking a button.
This is my html code for creating all the inputs
<th ng-repeat="(index, header) in filterTbl.gatVisibleFilterHeaders track by $index"
style="display: {{header.is_visible ? 'block' : 'none'}};
width: {{filterTbl.gatFilterHeadersWidth}}px !important;">
<div>
<span class="field-{{ header.filter_type }} th-title">{{ header.name }}</span>
<span class="fa fa-filter header-filter spanHF-{{index}}" title="Filter"
ng-click="filterTbl.showFilter(index, $event)" role="button"
tabindex="0"></span>
</div>
<div class="actual-filter divAF-{{index}} filter_input">
<input type="hidden" value="{{ header.col }}" class="header_col"
name="filter_header_col" />
<div ng-if="header.filter_type == 'text' || header.filter_type == ''"
ng-click="filterTbl.getFilterRecords(index, header)">
<div class="filter_select_container_{{ index }}"
style="display: block">
<select class="form-control select2 filter_{{ index }}"
name="filter_select" multiple="multiple">
</select>
</div>
</div>
<div ng-if="header.filter_type == 'numeric'">
<div class="number-range">
<div style="display: none;" class="filter-numeric-error"></div>
<input type="text" class="form-control froms "
onclick="event.stopPropagation();"
placeholder="From"
pattern="[0-9]{1,14}\.[0-9]{2}"/>
<div class="clearfix"></div>
</div>
<div class="number-range">
<div style="display: none;" class="filter-numeric-error"></div>
<input type="text" class="form-control to"
onclick="event.stopPropagation();"
placeholder="To" pattern="[0-9]{1,14}\.[0-9]{2}"/>
<div class="clearfix"></div>
</div>
</div>
</div>
</th>
I successfully created all the select tag and inputs but being able to pass them properly on javascript side.
This is my function when i click a button to get all the value of created input
var filterSelect = [];
$('#filterTable').find('table input,table select,table textarea').each(function(item, value) {
// console.log(item, value);
console.log(this.value);
});
I'm successfully receiving the value of a select but I need to convert it to a result something like this
['name of input': value, 'name of input': value]
example : [col:1, filter_select: "sample"]
Does anybody has an idea how can I accomplish this. been stuck for 1 week already.
Did you try to have array in which you push the values selected from select ? Your modified function will be as follows
filterSelect = [];
$('#filterTable').find('table input,table select,table
textarea').each(function(item, value) {
var obj={item:value};
this.filterSelect.push(obj);
//to verify the array items
angular.forEach(this.filterSelect, function(value, key) {
console.log(key + ': ' + value);
});
});

How to select rows based on string options in html vue js?

I need to add new rows based on the select options.
If my option is "kfc" I need to select a particular row. If my selected option is "cemrt", I need to add another row.
<div class="card-content" v-for="(bok, index) in rules" :key="index">
<div class="row">
<div class="col-md-6">
<div class="form-group label-floating">
<label class="control-label">Booked</label>
<select class="form-control" v-model="bok.name">
<option value="SEENAT">SEENAT</option>
<option value="CEMRT">CEMRT</option>
<option value="KFC">KFC</option>
</select>
</div>
</div>
</div>
<div class="row" v-if="bok.name == SEENAT"> //NOT WORKING FROM HERE
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Arms(if any)</label>
<input type="text" class="form-control" v-model="bok.data.head" required="">
</div>
</div>
</div>
<div class="row" v-if="bok.name == KFC">
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Arms(if any)</label>
<input type="text" class="form-control" required="">
</div>
</div>
</div>
</div>
But I am using this code not able to add rows based on the options.
My vue js code is
addForm = new Vue({
el: "#addForm",
data: {
rules : [{
name:null,
section:null,
data : [{head:null,value:null}]
}],
},
methods: {
addNewRules: function() {
this.rules.push({ name: null, section: null,data [{head:null,value:null}] });
},
},
});
If I use option value as 1,2,3 etc. I am getting the result.
But I need to send SEENAT,CEMRT,KFC as data. How can I able to achieve the result.
Hard to tell. A reproduction on codesandbox would be welcome.
What I can see in your code at a first glance :
1) You forgot quotes around the options keys and thus it expects a constant. The fact you're using double equals instead of triple doesn't help:
v-if="bok.name === 'SEENAT'" // this
v-if="bok.name == SEENAT" // instead of that
2) data should be a function:
data() {
return {
rules: [
{
name: null,
section: null,
data: [{ head: null, value: null }]
}
]
};
},

Vue.js 2.0 Vee Validate plugin not clearing errors after ajax call

I am working on a vue.js 2.0 project. I am using the Vee-Validate plugin. I have a form and when it submits, it makes an ajax call to my api. After the api call returns successfully, I am trying to clear my vee-validation so that I can invite another user with the same form, but it's not working at all.
I tried the method this.errors.clear() as suggested in their documentation
I have also thought that maybe its happening too fast, so I added a set timeout function for a couple seconds, but it still doesn't clear the errors.
Here is my Vue file with all related code:
<template>
<div v-if="user.first_time_login == 0 && user.stripe_check == 1">
<div class="viv-modal-overlay">
<div class="container">
<div class="viv-modal green">
<span class="modal-title" id="setup-team-top">Now let’s set up your team.</span>
<p>Your plan allows up to {{this.user.company.max_users}} users. Would you like to shoot out some team invites before we send you to the dashboard?</p>
<div class="invited-users" v-bind:class="{ show: show_invites }" v-if="show_invites">
<p>You can invite up to 4 more team members. Upgrade to add more.</p>
<ul>
<li v-for="invite in invites">
<img src="/img/icons/checkmark.svg" width="20" height="20" alt="success">
You invited {{invite.email}}.
<span class="clearfix"></span>
</li>
</ul>
<div class="team-done-adding">
I'm done adding team members.
</div>
</div>
<div class="modal-form">
<form id="setup-stripe-form">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>Team Member's Email<span>*</span></label>
<input type="text" name="email" v-model="newUser.email" v-validate data-vv-rules="required" class="form-control" :placeholder="'user#'+user.company.company_name.replace(/[^A-Z0-9]+/ig, '').toLowerCase()+'.com'">
<span v-show="errors.has('email')" class="error">{{ errors.first('email') }}</span>
</div>
<div class="form-group">
<label>Access to Leads and Contacts<span>*</span></label>
<select name="access_leads" v-model="newUser.access_leads" v-validate data-vv-rules="required" class="form-control">
<option value="1">they can see leads and contacts they created</option>
<option value="2">they can see all leads and contacts</option>
<option value="0">no access to leads and contacts</option>
</select>
<span v-show="errors.has('access_leads')" class="error">{{ errors.first('access_leads') }}</span>
</div>
<div class="form-group">
<label>Access to Proposals<span>*</span></label>
<select name="access_proposals" v-model="newUser.access_proposals" v-validate data-vv-rules="required" class="form-control">
<option value="1">they can see proposals they created</option>
<option value="2">they can see all proposals</option>
<option value="0">no access to proposals</option>
</select>
<span v-show="errors.has('access_proposals')" class="error">{{ errors.first('access_proposals') }}</span>
</div>
<div class="form-group">
<label>Access to Invoices<span>*</span></label>
<select name="access_invoices" v-model="newUser.access_invoices" v-validate data-vv-rules="required" class="form-control">
<option value="1">they can see invoices they created</option>
<option value="2">they can see all invoices</option>
<option value="0">no access to invoices</option>
</select>
<span v-show="errors.has('access_invoices')" class="error">{{ errors.first('access_invoices') }}</span>
</div>
<div class="form-group">
<label>Access to Projects<span>*</span></label>
<select name="access_projects" v-model="newUser.access_projects" v-validate data-vv-rules="required" class="form-control">
<option value="1">they can see projects they created</option>
<option value="2">they can see all projects</option>
<option value="0">no access to projects</option>
</select>
<span v-show="errors.has('access_projects')" class="error">{{ errors.first('access_projects') }}</span>
</div>
</div>
<div class="col-md-12 text-center">
<div class="modal-btn-pad">
<button type="submit" v-bind:class="{ disabled: adding_team_member }" class="btn btn-lg btn-green" #click="submitInviteForm">
<span class="sending-invite" v-if="adding_team_member">Sending Invite <img src="/img/preloader.svg" width="20" height="20"></span>
<span v-else>Continue</span>
</button><br>
<a class="light-link" href="#" #click="skipInviteForm">Skip this for now.</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
newUser: {
email: '',
access_leads: 1,
access_proposals: 1,
access_invoices: 1,
access_projects: 1
},
users_invited: 0,
invites: [],
show_invites: false,
adding_team_member: false
}
},
computed: mapState({
appLoading: state => state.appLoading,
user: state => state.user
}),
methods: {
submitInviteForm: function(e) {
e.preventDefault()
this.$validator.validateAll()
if (!this.errors.any()) {
//There are no errors, move forward...
//Add the team member to the database...
//Grab the authorized user
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
//Create the payload...
var newTeamMember = this.newUser
//Were adding a team member now so show the loader!
this.adding_team_member = true
//Create the new company and add the owner...
this.$http.post('/api/team',
{
newTeamMember: JSON.stringify(newTeamMember)
},
{
headers: {
Authorization: 'Bearer ' + authUser.access_token
}
}).then((response) => {
if(response.status === 200) {
//Assign the user to a variable
var invitedUser = response.body
//Add the user to the list of invited users
this.invites.push({email: invitedUser.email })
//Show the invite list...
this.show_invites = true
//Jump to top
location.hash = '#setup-team-top'
//reset the new user
this.newUser.email = ''
this.newUser.access_leads = 1
this.newUser.access_proposals = 1
this.newUser.access_invoices = 1
this.newUser.access_projects = 1
//Were done adding a team member so hide the loader!
this.adding_team_member = false
//Clear the validation errors
this.errors.clear()
}
}).catch(function(error){
console.log(error);
})
}
},
skipInviteForm: function(e) {
e.preventDefault()
alert('skip invite!')
}
}
}
</script>
Try to have a look at this fiddle which was extracted from this issue.
Basically, you have to call this.$validator.clean(); after you have reset the input fields of your form.

Categories

Resources