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

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)
},
}

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 pass data to method from a vue element iteration

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/

How do I use one input to control the other in vuejs

I need to find a way to basically show "per Month" in the assessments_period input if the assessments fee input has a typed-in value.
I've tried bindings and components but can't pull this off.
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Fee <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_fee" placeholder="$">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Period <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_period" placeholder="(per month/quarter/etc.)">
</div>
</div>
data() {
return {
now: new Date().toISOString(),
document: {
assessments_fee: '',
assessments_period: '',
}
}
},
components: {
assessments_fee: function() {
if(this.assessments_fee != null || '') this.assessments_period = "per Month";
}
},
you can create a watcher for assessments_fee so when its not null assessments_period= 'per Month'.
Here is how you can do it:
new Vue({
el: '#app',
data() {
return {
now: new Date().toISOString(),
document: {
assessments_fee: '',
assessments_period: '',
}
}
},
computed: {
assessmentsFee() {
return this.document.assessments_fee
}
},
watch: {
assessmentsFee() {
this.document.assessments_fee ?
this.document.assessments_period = "per Month" :
this.document.assessments_period = ""
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Fee <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_fee" placeholder="$">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>Assessment Period <span class="note">C</span></label>
<input type="text" class="form-control" v-model="document.assessments_period" placeholder="(per month/quarter/etc.)">
</div>
</div>
</div>

Vuelidate errors return true but elements don't render

I have a contact form that uses vuelidate to validate fields. The problem is - the validation works, but the errors don't render.
$v.name.dirty is TRUE and $v.name.required is FALSE.
Logging $v.name.dirty && !$v.name.required returns TRUE which is the same condition in the v-if directive but the error elements still don't show.
However, when .$touch() is called and $v.name.dirty becomes true and $v.name.required false, anything I type in the input fields will show the errors.
JS:
import translationsBus from "../../app/translations";
export default {
name: "contactForm",
beforeMount() {
this.$store.dispatch("updateTranslations", translationsBus.translations);
},
data: function () {
return {
name: '',
email: '',
subject: '',
message: ' ',
errors: [],
isSuccessful: ''
}
},
mounted() {
var my_axios = axios.create({
baseURL: '/'
});
Vue.prototype.$http = my_axios;
},
computed: {
isLogged: function () {
return isLoggedOn;
},
shouldShowSubjectOption: function () {
return showSubjectOption;
},
translations: function () {
return this.$store.state.translations.translations;
},
},
methods: {
onContactUsClick: function onContactUsClick() {
const _this = this;
this.$v.$touch();
if (!this.$v.$error) {
let model = {
senderName: _this.name,
senderEmail: _this.email,
subject: _this.subject,
message: _this.message
};
this.$http.post('/home/contactus', model)
.then(response => {
console.log(response);
_this.isSuccessful = response.data;
})
.catch(e => {
console.log(e);
});
}
}
},
validations: {
email: {
required: required,
isValidEmail: function isValidEmail(value) {
var re = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
return re.test(value);
}
},
name: {
required: required
},
subject: {
required: required
},
message: {
required: required
}
}
}```
HTML:
<div v-bind:class="{ 'col-lg-6' : shouldShowSubjectOption, 'col-lg-12' : !shouldShowSubjectOption }">
<div id="form-contact">
<h1 class="lead">Get in touch...</h1>
<form class="text-center" >
<div class="form-group">
<label for="name">{{translations['contact_Form_Name']}}</label>
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-user"></span></span>
<input type="text" class="form-control" name="senderName" id="senderName" v-model:bind="name" v-bind:placeholder="translations['contact_Form_NamePlaceholder']" />
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.name.$dirty && !$v.name.required">{{translations['shared_Validation_ReuiredField']}}</label>
</div>
</div>
<div class="form-group">
<label for="email">{{translations['contact_Form_EmailAddress']}}</label>
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-envelope"></span></span>
<input type="email" class="form-control" name="senderEmail" id="senderEmail" v-model:bind="email" v-bind:placeholder="translations['contact_Form_EmailAddressPlaceholder']" />
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.email.$dirty && !$v.email.required">{{translations['shared_Validation_ReuiredField']}}</label>
<label class="control-label" v-if="$v.email.$dirty && $v.email.required && !$v.email.isValidEmail">{{translations['contact_Form_EmailAddressValidationMessage']}}</label>
</div>
</div>
<div class="form-group" v-if="shouldShowSubjectOption">
<label for="subject">{{translations['contact_Form_Subject']}}</label>
<select id="subject" name="subject" class="form-control" v-model:bind="subject" v-bind:title="translations['contact_Form_SubjectPickerText']">
<option value="service">1</option>{{translations['contact_Form_SubjectOption_GCS']}}
<option value="suggestions">2</option>{{translations['contact_Form_SubjectOption_Suggestions']}}
<option value="product">3</option>{{translations['contact_Form_SubjectOption_ProductSupport']}}
</select>
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.subject.$dirty && !$v.subject.required" v-cloak>{{translations['shared_Validation_ReuiredField']}}</label>
</div>
<div class="form-group">
<label for="name">{{translations['contact_Form_Message']}}</label>
<textarea name="message" id="message" class="form-control" v-model:bind="message" rows="9" cols="25"
placeholder="">{{translations['contact_Form_Message']}}</textarea>
</div>
<div class="has-error" v-cloak>
<label class="control-label" v-if="$v.message.$dirty && !$v.message.required">{{translations['shared_Validation_ReuiredField']}}</label>
</div>
<div class="form-group" v-if="isLogged">
<div class="g-recaptcha" data-sitekey=""></div>
</div>
<button type="button" class="btn btn-primary btn-block" v-on:click="onContactUsClick" id="btnContactUs">{{translations['contact_Form_SendMessageButton']}}</button>
</form>
</div>
</div>
</div>
</div>
I expect error elements to appear on submit.

Traslating placeholder values by using 18next js

I wrote a code for translating the app from en-US to id-ID. It translates div, p, span and a tag elements successfully, however it doesn't translate placeholder values.
Here is my code:
<script src="js/i18next-1.10.1.min.js"></script>
<div class="row-fluid" id="loginfb">
<span class="pull-left" id="iconbox"><i class="fa fa-facebook" id="icon"></i></span>
<span class="form-control text-center" id="log_fb_msg"></span>
</div>
<div class="row-fluid" id="loginGmail">
<span class="pull-left" id="iconbox"><i class="fa fa-facebook" id="icon"></i></span>
<span class="form-control text-center log_gmail_msg" id="log-gmail-msg">Login with Gmail</span>
</div>
<div id="top">
<hr class="line_colr" id="right_or_line">
<div id="textrow">
<span class="text-center" id="or_span" </span>
</div>
<hr class="line_colr" id="left_or_line">
</div>
<h5 style="text-align: center; color: red;" id="validation"></h5>
<div class="row-fluid" id="mail">
<input type="text" class="form-control text text-center" id="mail_or_name" data-i18n="[placeholder]mail_or_name" placeholder="Email or Username">
</div>
<div class="row-fluid" id="passwordmail">
<input class="form-control text text-center" type="password" id="pass_span" placeholder="Password">
</div>
<div id="forgotpwd">
<span id="forgot_pass_span"><a id="link" href="#"></a></span>
</div>
<div class="row-fluid" id="signin">
<span class="form-control text-center blue_clr yelw_color" id="sign_in"></span>
</div>
<div id="createAccount">
<span id="create_new_acc"><a id= "registerLink" href="#">CREATE NEW ACCOUNT</a></span>
</div>
<script>
$.i18n.init({
//lng: 'en-US',
ns: {
namespaces: ['ns.common', 'ns.special'],
defaultNs: 'ns.special'
},
useLocalStorage: false,
debug: true
}, function(t) {
$('#add').text($.t('ns.common:add'));
$('#appname').text($.t('app.name'));
$('#log_fb_msg').text($.t('app.log_fb_msg', {
log_fb_msg: ''
}))
$('#or_span').text($.t('app.or_span', {
or_span: ''
}))
$('#link').text($.t('app.link', {
link: ''
}))
$('#sign_in').text($.t('app.sign_in', {
sign_in: ''
}))
$('#registerLink').text($.t('app.registerLink', {
registerLink: ''
}))
$('.log_gmail_msg').text($.t('app.log_gmail_msg', {
log_gmail_msg: ''
}))
/*$("input[placeholder]").val = $.t('app.sd', {
pvalue: ''
});*/
$("input[placeholder]").val(function() {
var pvalue = $(this).attr("placeholder");
alert($.t('app.sd', {
pvalue: ''
}));
$('pvalue')($.t('app.sd', {
pvalue: ''
}))
});
/*$('#registerLink').text("BUAT AKUN BARU");*/
});
</script>
My ns.special.json is:
{
"app": {
"name": "i18n",
"register": " DAFTAR __register__",
"username": "nama pengguna __username__",
"congrats": "Selamat! __congrats__",
"welcome": "Selamat Datang di Bistip Aplikasi Mobile __welcome__",
"please" : "Lengkapi profil Anda, sehingga Anda __please__",
"post" : "posting yang ditampilkan pada timeline. __post__",
"continue_span" : "LANJUTKAN __continue_span__",
"log_fb_msg" : "Masuk dengan Facebook __log_fb_msg__",
"or_span" : " Atau __or_span__",
"link" : "lupa kata sandi? __link__",
"sign_in" : "MASUK __sign_in__",
"header_msg" : "REKENING __header_msg__",
"profile" : "Profil __profile__",
"hover_my_trip" : "Saya Perjalanan __hover_my_trip__",
"review" : "Ulasan __review__",
"payout" : "Pembayaran __payout__",
"warning" : "Tidak ada diposting perjalanan ditemukan! __warning__",
"leftcolumn" : "Menyerahkan __leftcolumn__",
"rightcolumn" : "Membatalkan __rightcolumn__",
"registerLink" : "BUAT AKUN ANDA __registerLink__",
"log_gmail_msg" : "Masuk dengan Gmail __log_gmail_msg__",
"sd": "Email atau nama pengguna __mail_or_name__"
},
"placeHolder": {
"mail_or_name": "Email atau nama pengguna __mail_or_name__"
}
}
The problem is when I set setLng to id-ID, placeholder values are shown as alert, but they won't be translated on the page. Rest of the things are working fine. How can I modify my code to translate placeholders?
Got the solution.
I wrote a code like this:
$('#text_pswrd_conf').attr("placeholder",$.t('app.pwordConf'));
Where #text_pswrd_conf is the id of required input text. pwordConf is the translated value from ns.special.json
Given your ns.special.json file, the key for your placeholder should be placeHolder.mail_or_name

Categories

Resources