Set Index in computed function - vue.js

I have a v-for loop like following:
<div class="inputArea mt-2" v-for="(id, index) in inputs" :key="index">
<div class="row">
<div class="col-md-6 m-1">
<div class="mt-2">Input Number</div>
<b-form-input type="number" v-model="Number[index]"></b-form-input>
</div>
<div class="row">
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">Autofill 1</div>
<b-form-input type="text" :value="Autofill[index].autofill1" </b-form-input>
</div>
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">Autofill 2</div>
<b-form-input type="text" :value="Autofill[index].autofill2" </b-form-input>
</div>
</div>
</div>
</div>
How can I reference my index into a computed function:
computed: {
Autofill() { <!-- Autofill[index]() is not working -->
var returnelement = {};
if(this.json!= undefined) {
this.json.forEach(element => {
for(const item of this.Number) {
if (+element.number === +item)
returnelement = element;
}
});
}
return returnelement;
},
},
data() {
return {
inputs:[{}],
Number: [],
json: json, //imported before
}
}
Autofill[index] ( ) is not working, but I need this unique index in here..
Thanks for helping me out!

Try this
If you want to pass the index from the loop to Autofill, then you should use the methods.
You cannot pass data to a function from computed.
<div class="inputArea mt-2" v-for="(id, index) in inputs" :key="index">
<div class="row">
<div class="col-md-6 m-1">
<div class="mt-2">Number</div>
<b-form-input type="number" v-model="Number[index]"></b-form-input>
</div>
<div class="row">
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">Autofill 1</div>
<b-form-input type="text" :value="Autofill(index).autofill1" </b-form-input>
</div>
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">Autofill 2</div>
<b-form-input type="text" :value="Autofill(index).autofill2" </b-form-input>
</div>
</div>
</div>
</div>
<script>
export default {
//...
methods: {
Autofill(index) {
var returnelement = {};
if (this.json != undefined) {
this.json.forEach(element => {
for (const item of index) {
if (+element.number === +item)
returnelement = element;
}
});
}
return returnelement;
},
},
}
</script>

Related

Autofill input fields

I need following to work. I have an input field (in my Code number1) and I need to autofill (not autocomplete) the other input fields (in my Code autofill1 + autofill2).
I'm working with Bootstrap Vue (Bootstrap 4.6 and Vue.js 2).
Here is my code:
<template>
<div class="m-2 mt-3">
<table class="table table-striped mt-2">
<tbody>
<h5 class="ml-1">Informations</h5>
<tr>
<div class="row">
<div class="col-md-6 m-1">
<div class="mt-2">number1</div>
<b-form-input class="form-control" placeholder="1234567" id="number1" />
</div>
</div>
<div class="row">
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">autofill1</div>
<b-form-select id="autofill1"> </b-form-select>
</div>
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">autofill2</div>
<b-form-select id="autofill2"> </b-form-select>
</div>
<div class="row">
<div class="col-md-3 mt-2 ml-1">
<b-button variant="success" type="submit"><b-icon icon="check-circle-fill"></b-icon> Save Changes</b-button>
</div>
</div>
</div>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
};
</script>
<style scoped>
</style>
So my goal is to load some data (first guess was an json file) into my script and after I write a matching number (also possible that its a text) in input field number1 the other two fields will be autofilled.
Thanks in advance for helping me out!
Structure json data:
[
{ "number": 1234567, "autofill1": "Hello", "autofill2": "Goodbye" },
{ "number": 9876543, "autofill1": "Ciao", "autofill2": "Arrivederci" },
{ "number": 1346795, "autofill1": "Hallo", "autofill2": "Tschuess" }
]
Something like this would work: Example
<template>
<div>
<input type="number" placeholder="1234567" v-model.number="number1" />
<input type="text" :value="getAutofill.autofill1" />
<input type="text" :value="getAutofill.autofill2" />
</div>
</template>
<script>
export default {
computed: {
getAutofill(){
if (!this.data.find(item => item.number == this.number1)) return ["",""]
return this.data.find(item => item.number == this.number1)
}
},
data() {
return {
number1: undefined,
data: [
{ "number": 1234567, "autofill1": "Hello", "autofill2": "Goodbye" },
{ "number": 9876543, "autofill1": "Ciao", "autofill2": "Arrivederci" },
{ "number": 1346795, "autofill1": "Hallo", "autofill2": "Tschuess" }
]
}
}
};
</script>
you need to add some things to the data and than watch for the variable number1 to change...
<template>
<div class="m-2 mt-3">
<table class="table table-striped mt-2">
<tbody>
<h5 class="ml-1">Informations</h5>
<tr>
<div class="row">
<div class="col-md-6 m-1">
<div class="mt-2">number1</div>
<b-form-input class="form-control" placeholder="1234567" id="number1" v-model="number1" />
</div>
</div>
<div class="row">
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">autofill1</div>
<b-form-input class="form-control" id="autofill1" v-model="autofill1" />
</div>
<div class="col-md-5 ml-1 mr-1">
<div class="mt-2">autofill2</div>
<b-form-input class="form-control" id="autofill2" v-model="autofill2" />
</div>
<div class="row">
<div class="col-md-3 mt-2 ml-1">
<b-button variant="success" type="submit"><b-icon icon="check-circle-fill"></b-icon> Save Changes</b-button>
</div>
</div>
</div>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data(){
return {
number1: "",
autofill1: "",
autofill2: "",
jsonDATA: {...}
}
},
methods: {
findData(key) {
for(let i=0; i < this.jsonDATA.length; i++){
if(this.jsonDATA[i]['number'] === key) return element[i]
}
// add somthing when no data in array...
}
},
watch: {
number1(){
try {
let tmp = this.findData(this.number1)
this.autofill1 = tmp['autofill1']
this.autofill2 = tmp['autofill2']
}
}
}
};
</script>
<style scoped>
</style>
I havent tested this but this should work... This is not complete, you need to add some behaviour what to do when no data is found...

Cannot use 'in' operator to search for 'xxxxx' in undefined in vue.js

I'm trying to create a modal form that will add a record. I am able to display the default values from data but as soon as I try to modify the field, I get the following error whenever I try to type changes to the input box.
*vue.min.js:6 TypeError: Cannot use 'in' operator to search for 'fullname' in undefined
at a.ke [as $set] (vue.min.js:6)
at input (eval at Ya (vue.min.js:1), <anonymous>:3:2182)
at He (vue.min.js:6)
at HTMLInputElement.n (vue.min.js:6)
at HTMLInputElement.Yr.o._wrapper (vue.min.js:6)*
In given Below I added the code of the component I'm trying to create:
Any help, please.
var bus = new Vue();
Vue.component('leagues_add', {
props: {
show: Boolean,
is_admin: Boolean,
},
data: function () {
return {
newLeague: {"fullname":"a", "notes":"b", "group_image_path": "c"} // remember to always enclose the fieldnames in doublequotes
}
},
methods: {
closeModal() {
this.show = false;
},
showModal() {
this.show = true;
},
addLeague() {
event.preventDefault();
var formData = this.toFormData(this.newLeague);
axios.get("http://"+ window.location.hostname +"/db/leagues/index.php?action=create").then(function(response){
if (response.data.error) {
app.errorMessage = response.data.message;
} else {
app.leagues = response.data.leagues;
}
});
},
toFormData(obj) {
var fd = new FormData();
for (var i in obj) {
fd.append(i, obj[i]);
}
return fd;
},
}
,
template:
`
<!-- Add new Leage -->
<div>
<div class="text-center pb-3" >
<button type="button" class="btn btn-outline-primary bg-success text-white" #click="showModal"><b class="" style="">Add League</b></button>
</div>
<transition name="modal">
<div id="overlay" v-show="this.show">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add League</h5>
<button type="button" class="close" #click="closeModal"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<form action="#" method="POST">
<div class="form-group">
<input type="text" v-model="this.newLeague.fullname" class="form-control form-control-md" placeholder="Name of League">
</div>
<div class="form-group">
<textarea v-model="this.newLeague.notes" rows="3" cols="100%" name="notes" class="form-control form-control-md" placeholder="Describe this league">
</textarea>
</div>
<div class="form-group form-inline ">
<div class="col-12 p-0">
<input type="url" v-model="this.newLeague.group_image_path" class="col-5 pull-left form-control form-control-md" placeholder="Image URL">
<button class="col-4 btn btn-primary btn-md">Image</button>
</div>
</div>
<div class="form-group">
<button class="btn btn-info btn-block btn-md" #click="closeModal();addLeague();">Add this league</button>
</div>
</form>
</div>
</div>
</div>
</div>
</transition>
<div>
`
});
<div class="row">
<div class="col-md-12">LEAGUES SECTION</div>
</div>
<div class="row mt-2">
<div class="col-md-12">
<leagues_add :show="true" />
</div>
</div>
The problem is here:
v-model="this.newLeague.fullname"
You cannot use this. with v-model. Instead it should be:
v-model="newLeague.fullname"
You should also remove all other references to this within your template. In many cases they are harmless but sometimes, such as with v-model, they will cause problems.
Complete examples below. Note how the first input does not function correctly when editing the text.
new Vue({
el: '#app1',
data () {
return { newLeague: { fullname: 'League 1' } }
}
})
new Vue({
el: '#app2',
data () {
return { newLeague: { fullname: 'League 1' } }
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app1">
<input type="text" v-model="this.newLeague.fullname">
{{ newLeague.fullname }}
</div>
<div id="app2">
<input type="text" v-model="newLeague.fullname">
{{ newLeague.fullname }}
</div>
I followed the way #skirtle wrote the data section and it worked.
My original syntax was:
data: function () {
return {
newLeague: {"fullname":"a", "notes":"b", "group_image_path": "c"} }
}
to
data () {
return { newLeague: { fullname: 'League 1' } }
}

On form button click success, form validations fire again

Hopefully this is a newbie question.
I am using Vuelidate to validate my form and the form validations works fine, when the “send email” button is clicked.However on success, instead of showing me the successful message, the system shows that all the form controls have errors(This is because I have bound the name, email, message controls to their corresponding empty data elements).
What am I missing?
How can I fix this issue?
Contact.vue
<template>
<div>
<section class="slice slice-lg" id="sct_contact_form">
<div class="container">
<div class="mb-5 text-center">
<span class="badge badge-soft-info badge-pill badge-lg">
Contact
</span>
<h3 class=" mt-4">Send us a message</h3>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<form>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Name</label>
<input class="form-control" type="text" placeholder="Name" v-model="user.name" id="name" name="name" :class="{ 'is-invalid': submitted && $v.user.name.$error }" >
<div v-if="submitted && !$v.user.name.required" class="invalid-feedback">Name is required</div>
</div>
</div>
</div>
<div class="row align-items-center">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Email</label>
<input class="form-control" type="email" placeholder="email#example.com"
v-model="user.email" id="email" name="email" :class="{ 'is-invalid': submitted && $v.user.email.$error }" >
<div v-if="submitted && $v.user.email.$error" class="invalid-feedback">
<span v-if="!$v.user.email.required">Email is required</span>
<span v-if="!$v.user.email.email">Email is invalid</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Message</label>
<textarea class="form-control" data-toggle="autosize" placeholder="Tell us a few words ..." rows="3" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 96.9922px;"
v-model="user.message" id="message" name="message" :class="{ 'is-invalid': submitted && $v.user.message.$error }" ></textarea>
<div v-if="submitted && $v.user.message.$error" class="invalid-feedback">
<span v-if="!$v.user.message.required">Message is required</span>
<span v-if="!$v.user.message.minLength">Message must be at least 6 characters</span>
</div>
</div>
</div>
</div>
<div class="text-center mt-4">
<button type="button" class="btn btn-dark rounded-pill" v-on:click="SendEmail()">Send your message</button>
<span class="d-block mt-4 text-sm">We'll get back to you in 24-48 h.</span>
<div v-if="submitted" class="valid-feedback">
<span v-if="!$v.user.name.$error && !$v.user.email.$error && !$v.user.message.$error">Your email was send successfully. We'll get back to you in 24-48 h.</span>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
</div>
</template>
import { Email } from '../api/email.js';
import { required, email, minLength, sameAs } from "vuelidate/lib/validators";
export default {
name: "Contact",
components:{
},
data() {
return {
user: {
name: "",
email: "",
message: ""
},
submitted: false
};
},
validations: {
user: {
name: { required },
email: { required, email },
message: { required, minLength: minLength(6) }
}
},
methods: {
SendEmail() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
var nameWithEmailText="Email message from: "+ this.user.name + "\nEmail message: " + this.user.message;
var subject="Email from contact us page in common membership website";
Meteor.call('email.send', this.user.email, subject, nameWithEmailText);
this.user.name='';
this.user.email='';
this.user.message='';
}
}
}
You should wait for the Meteor.call() to complete, then reset the validation state.
For example
Meteor.call('email.send', this.user.email, subject, nameWithEmailText, (error, result) => {
this.user.name = ''
this.user.email = ''
this.user.message = ''
this.$v.$reset()
})

vuejs :disabled doesn't work

I have a problem on reactivating the button even if the conditional statement works.
it looked like the v-model wasn't communicating with the data but with a simple interpolation the value was updated.
I don't really know where I'm doing wrong on the code.
<template>
<div class="col-sm-6 col-md-4">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">{{stock.name}}
<small>(Price: {{stock.price}})</small>
</h3>
</div>
<div class="panel-body">
<div class="pull-left">
<input v-model="quantity" type="number" class="form-control" placeholder="Quantity">
</div>
<div class="pull-right">
<button class="btn btn-success" #click="buyStock" :disabled="isDisabled">Buy</button>
</div>
<p>{{quantity}}</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: [
"stock",
],
data() {
return {
quantity: 0,
}
},
methods: {
buyStock() {
const order = {
stockId: this.stock.id,
stockPrice: this.stock.price,
quantity: this.quantity
};
console.log(order);
this.$store.dispatch("buyStock", order);
this.quantity = 0;
}
},
computed: {
isDisabled() {
if (this.quantity <= 0 || !Number.isInteger(this.quantity)) {
return true;
} else {
return false;
}
}
}
}
</script>
By default, the v-model directive binds the value as a String. So both checks in your isDisabled computed will always fail.
If you want to bind quantity as a number, you can add the .number modifier like so:
<input v-model.number="quantity" type="number" ... >
Here's a working example:
new Vue({
el: '#app',
data() {
return { quantity: 0 }
},
computed: {
isDisabled() {
return (this.quantity <= 0 || !Number.isInteger(this.quantity))
}
}
})
<template>
<div class="col-sm-6 col-md-4">
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">{{stock.name}}
<small>(Price: {{stock.price}})</small>
</h3>
</div>
<div class="panel-body">
<div class="pull-left">
<input v-model="quantity" type="number" class="form-control" placeholder="Quantity">
</div>
<div class="pull-right">
<button class="btn btn-success" #click="buyStock" :disabled="isDisabled">Buy</button>
</div>
<p>{{quantity}}</p>
</div>
</div>
</div>
</template>
<script>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<input v-model.number="quantity" type="number">
<button :disabled="isDisabled">Foo</button>
</div>

How to hide / show component in vuejs

I'm developing a small application in VueJs where I'm having a div element and trying to show element if the data value is 1 and hide if the data value is 0, for this I'm having v-model as withClient something like this:
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="1" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="0">
<label>
No
</label>
</div>
</div>
And the element which needs to be hidden:
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection">
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
I've computed property as withClientSelection:
withClientSelection() {
if(this.withClient === 0)
{
this.clientParticipants = ''
return false
}
else
{
return true
}
}
But somehow I'm not able to get this. Help me on this. Thanks
It's actually very simple, you should use
this.withClient === '0'
instead of
this.withClient === 0
I also overlooked this part and verified your code myself first, here's a fully working example that I used.
Vue.component('v-select', VueSelect.VueSelect);
const app = new Vue({
el: '#app',
data: {
withClient: '0',
clientParticipants: '',
dummyData: ['Aaron', 'Bart', 'Charles', 'Dora', 'Edward', 'Flora', 'Gladys', 'Heidi', 'Iris', 'Jason'],
contactClients: []
},
computed: {
withClientSelection() {
if (this.withClient === '0') {
return false
}
return true
}
},
watch: {
withClient(newVal) {
if (newVal === 0) {
this.clientParticipants = '';
}
}
},
methods: {
getOptions(search, loading) {
/*
loading(true)
this.$http.get('https://api.github.com/search/repositories', {
q: search
}).then(resp => {
this.contactClients = resp.data.items
loading(false)
})
*/
this.contactClients = this.dummyData
.filter((name) => name.toLowerCase().indexOf(search.toLowerCase()) >= 0);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.3.4"></script>
<script src="https://unpkg.com/vue-select#latest"></script>
<div id="app">
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="1" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" v-model="withClient" value="0">
<label>
No
</label>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection === true">
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Selected Clients:</label>
<div class="col-sm-8" v-if="withClientSelection === true">
{{clientParticipants}}
</div>
</div>
</div>
I think the intention with v-model on hidden inputs is to set up a one-way binding, in which case it's much better to use
<input type="hidden" :value="someData" >
You can try this, it will help you to solve your problem.
new Vue({
el: '#app',
data: {
clientParticipants: '',
withClientSelection: 1
},
methods: {
checkMe: function(type) {
return this.withClientSelection = type
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="col-sm-6">
<label class="col-sm-6 control-label">With client*:</label>
<div class="radio col-sm-3">
<input type="radio" name="with_client" #change="checkMe(1)" checked="">
<label>
Yes
</label>
</div>
<div class="radio col-sm-3">
<input type="radio" name="with_client" #change="checkMe(0)">
<label>
No
</label>
</div>
</div>
<div class="col-sm-6">
<label class="col-sm-3 control-label">Clients:</label>
<div class="col-sm-8" v-if="withClientSelection">
Display now!
<v-select
multiple
:options="contactClients"
:on-search="getOptions"
placeholder="Client name"
v-model="clientParticipants">
</v-select>
</div>
</div>
</div>