I'm trying to figure out how I can set up this Vue component so that if there is an error in my backend validation from Laravel then I can save the inputs and when it redirects back to the create page then auto-populate with the old data.
As of right now it's not sending the old data to the prop for my component. Is there something I'm doing wrong?
Blade File
<component name="{{ old('name') }}" locationType="{{ old('location_type') }}" paymentType="{{ old('payment_type') }}"></component>
Vue Component
<template>
<div>
<div>
<p class="mbxs"><b>Choose Location Type <span style="color: red">*</span></b></p>
<label class="custom-control custom-radio" v-for="choice in choices">
<input name="location_type" type="radio" v-model="chosen" :value="choice" class="custom-control-input" required>
<span class="custom-control-indicator"></span>
<span class="custom-control-description">{{ choice }}</span>
</label>
</div>
<template v-if=" chosen == 'Residential' ">
<div class="row">
<div class="col-12 col-sm-6">
<div class="form-group form-group-required">
<label for="name" class="control-label">Last Name</label>
<input class="form-control" required name="last_name" type="text">
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group form-group-required">
<label for="name" class="control-label">First Name</label>
<input class="form-control" required name="first_name" type="text">
</div>
</div>
</div>
</template>
<template v-if=" chosen == 'Commercial' ">
<div class="form-group form-group-required">
<label for="name" class="control-label">Name</label>
<input class="form-control" required name="name" type="text">
</div>
</template>
</div>
</template>
<script>
module.exports = {
http: {
headers: {
'X-CSRF-TOKEN': window.Laravel.csrfToken
}
},
props: [ 'name', 'locationType', 'paymentType' ],
data: function(){
return {
name: '',
locationType: '',
locationName: '',
paymentType: '',
insuranceType: '',
choices: [ 'Commercial', 'Residential'],
chosen: ''
};
}
}
</script>
Well you're defining the props this.name, this.locationType, this.PaymentType, then you're assigning them as empty in your data declaration, so you have a collision.
Given your architecture, its not the most elegant, but it will probably do:
props: [ 'name', 'locationType', 'paymentType' ],
created: function() {
this.form.name = this.name;
this.form.locationType = this.locationType;
this.form.paymentType = this.paymentType;
},
data: function() {
form: {
name: '',
locationType: '',
locationName: '',
paymentType: '',
insuranceType: '',
choices: [ 'Commercial', 'Residential'],
chosen: ''
}
}
We've namespaced our data to form and assign the values from our properties to the form namespace.
Update your bindings as such to v-model="form.name" etc.
Related
I have fields to submit to insert into the database. The account field has to select from options by Dropdown. The options should be fetched from the accounts table in the database and I have used API for that. I have coded and it can not see the accounts. Please instruct me to fix it.
the input types as follows.
<div class="modal-body">
<div class="form-row" v-show="!deleteMode">
<div class="form-group col-md-6">
<label for="exampleInputBorderWidth2">Funds From</label>
<select class='form-control' v-model='accountData.selectAccount'>
<option value='0' >Select Account</option>
<option v-for='data in selectAccounts' :value='data.id'>{{ data.name }}</option>
</select>
<span class="text-danger" v-show="accountError.selectAccount">Fund From required </span>
</div>
</div>
<div class="form-row" v-show="!deleteMode">
<div class="form-group col-md-6">
<label for="exampleInputBorderWidth2">Account Name</label>
<input type="text" class="form-control form-control-border border-width-2 text-danger text-lg" id="name" placeholder="Account Name" v-model="accountData.name" required>
<span class="text-danger" v-show="accountError.name">Name is required </span>
</div>
<div class="form-group col-md-6">
<label for="exampleInputBorderWidth2">Account Description</label>
<input type="text" class="form-control form-control-border border-width-2 text-primary text-lg" id="description" placeholder="Account Description" v-model="accountData.description">
<span class="text-danger" v-show="accountError.description">Description is required</span>
</div>
</div>
</div>
script as follows
data() {
return {
editMode: false,
deleteMode:false,
accountData:{
id: '',
name: '',
description: '',
status: '',
selectAccount: 0,
selectAccounts:[]
},
get Method
getSelectAccounts(){
axios.get("/api/allAccForSelect").then(response => {
this.selectAccounts = response.data
}).bind(this);
},
getDepAcc(){
axios.get("/api/depositAccount/depositAccountIndex").then(response => {
this.depAccs = response.data
}).catch(errors =>{
console.log(errors)
});
},
router API
Route::get('/allAccForSelect', [AccountController::class, 'allAccForSelect']);
Controller
public function allAccForSelect(Request $request)
{
$userId = Auth::id();
return response()->json(Account::where('user', $userId)->where('status', 1)->get());
}
I want to create a membership form with picture upload and other input data required. I have a form with input file and input text which to be considered as multi-part data. I am using the Laravel 8 and Inertia.js.
Here is what I've tried:
In my Form, I have like this:
<form action="/member" method="POST" #submit.prevent="createMember">
<div class="card-body">
<div class="form-group">
<label for="exampleInputFile">Picture</label>
<div class="input-group">
<div class="custom-file">
<input type="file" class="custom-file-input" id="exampleInputFile" #input="form.picture">
<label class="custom-file-label" for="exampleInputFile">Choose image</label>
</div>
<div class="input-group-append">
<span class="input-group-text">Upload</span>
</div>
</div>
</div>
<div class="form-group">
<label for="exampleInputEmail1">First name</label>
<input type="text" class="form-control" id="fname" placeholder="First name" v-model="form.firstname">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Middle name</label>
<input type="text" class="form-control" id="mname" placeholder="Middle name" v-model="form.middlename">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Last name</label>
<input type="text" class="form-control" id="lname" placeholder="Last name" v-model="form.lastname">
</div>
<div class="col-md-12">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Name ext</label>
<input type="text" class="form-control" id="next" placeholder="Name extension" v-model="form.name_ext">
</div>
<div class="form-group">
<label>Membership Date:</label>
<div class="input-group date" id="reservationdate" data-target-input="nearest">
<input type="text" class="form-control datetimepicker-input" id="mem_date" data-target="#reservationdate" v-model="form.membership_date"/>
<div class="input-group-append" data-target="#reservationdate" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div>
</div>
</div>
<div class="form-group">
<label>Date of Birth:</label>
<div class="input-group date" id="reservationdate" data-target-input="nearest">
<input type="text" class="form-control datetimepicker-input" id="date_of_birth" data-target="#reservationdate" v-model="form.date_of_birth"/>
<div class="input-group-append" data-target="#reservationdate" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div>
</div>
</div>
<div class="form-group">
<label>Sex:</label>
<div class="radio-inline">
<label class="radio radio-solid">
<input type="radio" name="travel_radio" class="details-input" value="Male" v-model="form.sex"/> Male
<span></span>
</label>
<label class="radio radio-solid">
<input type="radio" name="travel_radio" class="details-input" value="Female" v-model="form.sex"/> Female
<span></span>
</label>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
then I have tried vue and inertia implementation like this:
export default {
props: [],
components: {
AppLayout,
},
data() {
return {
form: {
picture: '',
firstname: '',
middlename: '',
lastname: '',
name_ext: '',
date_of_birth: '',
sex: '',
membership_date: '',
}
}
},
methods: {
createMember() {
this.$inertia.post('/member', this.form, {
_method: 'put',
picture: this.form.picture,
onSuccess: () => {
console.log('success');
// $('.toastrDefaultSuccess').click(function() {
// toastr.success('Successfully Added');
// });
},
onError: (errors) => {
console.log(errors);
},
})
}
}
}
then from my backend, I tried to dd the request and got null from picture:
public function store(MemberPost $request) {
dd($request);
}
Assuming you are using inertia 0.8.0 or above, you can use the inertia form helper. This will automatically transform the data to a FormData object if necessary.
Change your data method to:
data() {
return {
form: this.$inertia.form({
picture: '',
firstname: '',
middlename: '',
lastname: '',
name_ext: '',
date_of_birth: '',
sex: '',
membership_date: '',
})
}
}
and the createMember function to:
createMember() {
// abbreviated for clarity
this.form.post('/member')
}
More info: docs. If you need to migrate FormData from inertia < 0.8.0 to a current version, see this page.
if you using multi-upload remove array from files
before: <input type="file" #input="form.image = $event.target.files[0]" multiple/>
after: <input type="file" #input="form.image = $event.target.files" multiple/>
add enctype="multipart/form-data" to form tag
and you need move the picture to directory. example
$name = $file->getClientOriginalName();
$file->move('uploads/posts/',$name);
sorry, i dont know how to implement this code to inertia.
This way works for me
this.$inertia.post('/member', this.form)
I have simple form:
<form action="" method="post">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Check me out</label>
</div>
<div class="form-group">
<tags-multiselect></tags-multiselect>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And Vue tags-multiselect component:
<!-- Vue component -->
<template>
<div>
<multiselect v-model="value" :options="options" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Выберите тэги" label="name" track-by="name" :preselect-first="true">
<template slot="selection" slot-scope="{ values, search, isOpen }"><span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} выбрано</span></template>
</multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: { Multiselect },
data () {
return {
value: [],
options: [
{ name: 'Vue.js', language: 'JavaScript' },
{ name: 'Adonis', language: 'JavaScript' },
{ name: 'Rails', language: 'Ruby' },
{ name: 'Sinatra', language: 'Ruby' },
{ name: 'Laravel', language: 'PHP' },
{ name: 'Phoenix', language: 'Elixir' }
]
}
}
}
</script>
<!-- New step!
Add Multiselect CSS. Can be added as a static asset or inside a component. -->
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
I need select field on the my form. When I send form, In controller I need accept array from select tags. How I can do this with vue multiselect? Or I need use simple select multiple for it? Help me please.
You can solve this by making the options only the identifier (in your case the name) and use a custom label that filters itself. Like this:
<multiselect
v-model="rule.id"
:options="types.map(type => type.name)"
:custom-label="opt => types.find(x => x.id == opt).language">
</multiselect>
Also make sure to remove trackBy property, since your options are no longer objects, its now an array of the form ['Vue.js', 'Adonis',...]
Source: https://github.com/shentao/vue-multiselect/issues/432
I want to bind the select option with returned JSON data. However, when I do the API call and set the options model groups to the returned JSON, I get the error 'TypeError: Cannot set property 'groups' of undefined'.
Here is the vue file
<template>
<div class="register">
<div class="container">
<div class="row">
<div class="col">
<h3 class="mb-10">Register as a volunteer</h3>
<form action="">
<div class="form-group">
<label for="first_name">First Name</label>
<input type="text" v-model="first_name" placeholder="First Name" class="form-control" id="first_name">
</div>
<div class="form-group">
<label for="last_name">Last Name</label>
<input type="text" v-model="last_name" placeholder="Last Name" class="form-control" id="last_name">
</div>
<div class="form-group">
<label for="group">Select Institution/Organization/Company</label>
<select v-model="group" class="form-control" id="group">
<option v-for="group in groups" v-bind:name="name">{{ group.code }}</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="phone">Phone</label>
<input type="text" v-model="adv_phone" placeholder="Phone" class="form-control" id="phone">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" v-model="adv_password" class="form-control" id="password" placeholder="Password">
</div>
<div class="form-group">
<label for="confirm-password">Confirm Password</label>
<input type="password" v-model="adv_password" class="form-control" id="confirm-password" placeholder="Confirm Password">
</div>
<div class="from-group">
<input type="submit" class="btn btn-primary" value="Register">
<router-link :to="{name:'home'}">
<a class="btn btn-outline-secondary">Cancel</a>
</router-link>
</div>
</form>
</div>
</div>
</div>
<div class="register-form"></div>
</div>
</template>
<script>
export default {
mounted(){
this.getGroups()
},
data (){
return {
group: '',
groups:'',
first_name:'',
last_name:'',
adv_email:'',
adv_phone:'',
adv_password:'',
confirm_password:''
}
},
methods:{
getGroups(){
axios.get('/api/group/get/all')
.then(function (response) {
console.log(response);
this.groups = response.data;
//console.log(groups);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
}
}
}
</script>
and here is my json returned
[{"id":8,"name":"Villa Maria Academy","code":"Vil-9458-3786","advisors":25,"students":99,"subscription_time":99,"subscription_type":0,"admin_name":"","admin_email":"","phone":"817879234","address":"Abcde street","state":"Pennsylvania","zip":16502,"apt":"","city":"Erie"},{"id":9,"name":"Cathedral Prep","code":"Cat-1959-1432","advisors":99,"students":99,"subscription_time":99,"subscription_type":0,"admin_name":"","admin_email":"","phone":"0","address":"","state":"","zip":0,"apt":"","city":""}]
Why am I getting a type error, when I set this.groups = response.data?
You can use arrow function to fix problem.
methods:{
getGroups(){
axios.get('/api/group/get/all')
.then(response => {
console.log(response);
this.groups = response.data;
//console.log(groups);
})
.catch(error => {
console.log(error);
})
.then(() => {
// always executed
});
}
}
this is going to be super long winded!
Admittedly I am not a good frontend designer and my Javascript skills leave much to be improved upon.
TL:DR - How is the working code different from the JSON encoded data object (merchant) in the non-working code, in regards to the Axios POST request? Shouldn't they produce the same result?
Some background first: I am building a Laravel REST backend that is feature complete, form validators, policies, the works. I have tested the backend with the ARC REST client for Chrome and have verified my backend is fully functional.
The problem: While designing my frontend using Vuejs, Vue-Router and Axios, I am having issues POSTing data to my backend. Specifically it is failing form validation with an HTTP error 422. I have narrowed down this issue to be relating to object encapsulation in either Vue or Axios.
Here is the non-working Vue component:
<div class="panel panel-default">
<div class="panel-heading">Create Merchant</div>
<div class="panel-body">
<form action="#" #submit.prevent="createMerchant()">
Primary
<input v-model="merchant.primary" type="text" name="primary" class="form-control" autofocus>
Alternate
<input v-model="merchant.alternate" type="text" name="alternate" class="form-control">
Contact
<input v-model="merchant.contact" type="text" name="contact" class="form-control">
Street
<input v-model="merchant.street" type="text" name="street" class="form-control">
City
<input v-model="merchant.city" type="text" name="city" class="form-control">
State
<input v-model="merchant.state" type="text" name="state" class="form-control">
Country
<input v-model="merchant.country" type="text" name="country" class="form-control">
Postal Code
<input v-model="merchant.postalCode" type="text" name="postalCode" class="form-control">
<button type="submit" class="btn btn-primary">Create Merchant</button>
</form>
</div>
</div>
<div v-if='errors && errors.length' class="panel panel-default">
<div class="panel-heading">Error</div>
<div class="panel-body">
<ul>
<li v-for='error of errors'>
{{error.message}}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
merchant: {
primary: '',
alternate: '',
contact: '',
street: '',
city: '',
state: '',
country: '',
postalCode: ''
},
errors: []
};
},
methods: {
createMerchant() { console.log(JSON.stringify(this.merchant));
axios.post('/payment-gateway/public/api/v1/merchant', JSON.stringify(this.merchant))
.then((response) => {
console.log(response.data.id);
this.$router.push({ name: 'merchantList' });
})
.catch(e => {
this.errors.push(e);
});
}
}
}
</script>
The data being posted, from my point of view appears to be correct:
{"primary":"Widget Company","alternate":"Widget Co","contact":"555-555-0055","street":"123 Main St","city":"Olympia","state":"WA","country":"USA","postalCode":"98501"}
But the above code always results in a HTTP 422 error.
Now for the part that is confusing me, this is working code:
<div class="panel panel-default">
<div class="panel-heading">Create Merchant</div>
<div class="panel-body">
<form action="#" #submit.prevent="createMerchant()">
Primary
<input v-model="merchant.primary" type="text" name="primary" class="form-control" autofocus>
Alternate
<input v-model="merchant.alternate" type="text" name="alternate" class="form-control">
Contact
<input v-model="merchant.contact" type="text" name="contact" class="form-control">
Street
<input v-model="merchant.street" type="text" name="street" class="form-control">
City
<input v-model="merchant.city" type="text" name="city" class="form-control">
State
<input v-model="merchant.state" type="text" name="state" class="form-control">
Country
<input v-model="merchant.country" type="text" name="country" class="form-control">
Postal Code
<input v-model="merchant.postalCode" type="text" name="postalCode" class="form-control">
<button type="submit" class="btn btn-primary">Create Merchant</button>
</form>
</div>
</div>
<div v-if='errors && errors.length' class="panel panel-default">
<div class="panel-heading">Error</div>
<div class="panel-body">
<ul>
<li v-for='error of errors'>
{{error.message}}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
merchant: {
primary: '',
alternate: '',
contact: '',
street: '',
city: '',
state: '',
country: '',
postalCode: ''
},
errors: []
};
},
methods: {
createMerchant() { console.log(JSON.stringify(this.merchant));
axios.post('/payment-gateway/public/api/v1/merchant', {
primary: this.merchant.primary,
alternate: this.merchant.alternate,
contact: this.merchant.contact,
street: this.merchant.street,
city: this.merchant.city,
state: this.merchant.state,
country: this.merchant.country,
postalCode: this.merchant.postalCode
})
.then((response) => {
console.log(response.data.id);
this.$router.push({ name: 'merchantList' });
})
.catch(e => {
this.errors.push(e);
});
}
}
}
</script>
So my question is, how is the working code different from the JSON encoded data object (merchant) in the non-working code?
In one instance you're sending an object, in the other a string. Although they will both be transferred as a string eventually, when you pass the object, the ContentType is set under the hood to application/json.
That being said, if you set the ContentType to application/json for the one you're passing as a string, it will sort the issue.