I can not save values using POST method - laravel vue - laravel

I'm trying to save the data I send from the Event view. in the storeEvent method of the EventController driver but it gives me error 422 and I can not find the problem so far.
The Event model has a many-to-many relationship with the Categories model, and Event also has a many-to-many relationship with the Coins model, which is why I occupy vue-multiselect since the user can select several categories or several coins for the same event
Event.vue
<template>
<form v-on:submit.prevent="createdEvent" class="form-horizontal">
<div class="form-group row">
<label>Titulo</label>
<input type="text" name="title" maxlength="25" v-model="title">
</div>
<div class="form-group row">
<label>*Cryptodivisas</label>
<multiselect v-model="coinvalue" :options="coins"
:multiple="true" label="name"
track-by="id" placeholder="Seleccione">
</multiselect>
</div>
<div class="form-group row">
<label>*Categoría</label>
<multiselect v-model="categoryvalue" :options="categories"
:multiple="true" label="name"
track-by="id" placeholder="Seleccione">
</multiselect>
</div>
<div class="col-sm-12">
<button class="btn" type="submit">Crear evento</button>
</div>
</form>
<script>
import Multiselect from 'vue-multiselect';
export default {
components: {
Multiselect,
},
props: ['auth'],
data () {
return {
user: {},
title: '',
coins: [],
coinvalue: [],
categories: [],
categoryvalue: [],
}
},
created() {
this.getCoins();
this.getCategories();
},
mounted() {
this.user = JSON.parse(this.auth);
},
methods: {
getCoins(){
let urlCoin = '/dashboard/coins';
axios.get(urlCoin)
.then((response) => {
this.coins = response.data;
})
.catch((err) => {
})
},
getCategories(){
let urlCategories = '/dashboard/categories';
axios.get(urlCategories)
.then((response) => {
this.categories = response.data;
})
.catch((err) => {
})
},
createdEvent(){
let urlEvent = '/dashboard/newEvent';
const eventData = {
'id' : this.user.id,
'title' : this.title,
'coin' : this.coinvalue,
'category' : this.categoryvalue,
}
console.log(eventData);
axios.post(urlEvent, eventData)
.then((response) => {
console.log(ok);
})
.catch((err) => {
console.log(err.response.data);
})
}
</script>
storeEvent (EventController)
public function storeEvent(Request $request)
{
$this->validate($request, [
'title' => 'required|max:25',
'coin' => 'required',
'category' => 'required',
]);
$userAuth = Auth::user()->id;
$userEvent = $request->id;
if($userAuth === $userEvent){
$event = new Event;
$event->user_id = $userEvent;
$event->title = $request->title;
if($event->save()){
$event->coins()->attach($request->coin);
$event->categories()->attach($request->category);
return response()->json([
'status' => 'Muy bien!',
'msg' => 'Tu evento ya fue creado con éxito.',
], 200);
}
else {
return response()->json([
'status' => 'Error!',
'msg' => 'No pudimos crear tu evento.',
], 401);
}
}
}
I think the problem may be when I assign the values to the coin () -> attach () and category () -> attach () section, but I have no idea how to solve it due to my inexperience in the tool.
The system was made entirely in Laravel and it worked without problems, now that it is being updated with Vue it began to give inconveniences.
Any ideas? I occupy Laravel 5,6, Vuejs 2, Axios and Vue-multiselect 2

Try sending form data
Here is the example for you.
var urlEvent = '/dashboard/newEvent';
var form_data = new FormData();
form_data.append('id',this.user.id);
form_data.append('title',this.title);
for(let coin of this.coinvalue)
form_data.append('coin[]', coin);
for(let category of this.categoryvalue)
form_data.append('category[]', category);
axios(urlEvent,{
method: "post",
data: form_data
})
.then(res => {
console.log(ok);
})
.catch(err => {
console.log(err.response.data);
});
If this stills gives you a 422 status code (Unprocessable entities). Then try returning $request in you controller. And check what data are actually send to the controller and what your validation is.

422 means validation error so do a console.log or inspect the element on axios call and check that :
'title' : this.title,
'coin' : this.coinvalue,
'category' : this.categoryvalue,
Are not empty, cause right now some data from above is missing since its a 422 validation exception.

Related

Obtain values from Laravel Controller and display in Vue

In a Laravel 8 view, I have a Vue component with a form.
<contact-form-component contact-store-route="{{ route('contact.store') }}">
</contact-form-component>
ContactFormController.vue
<template>
<div>
<div v-if="success">
SUCCESS!
</div>
<div v-if="error">
ERROR!
</div>
<div v-show="!success">
<form
#submit.prevent="storeContact"
method="POST"
novalidate="novalidate"
#keydown="clearError"
>
<input type="text" name="fullname" v-model="formData.fullname" />
<input type="text" name="email" v-model="formData.email" />
<input type="text" name="phone" v-model="formData.phone"/>
<button type="submit">Submit</button>
</form>
</div>
</template>
<script>
import Form from "./Form.vue";
export default {
mixins: [Form],
props: {
contactStoreRoute: String,
},
data() {
return {
formData: {
fullname: null,
lname: null,
email: null,
phone: null,
message: null,
},
};
},
methods: {
storeContact() {
this.post(this.contactStoreRoute, this.formData);
},
},
mounted() {},
};
</script>
Form.vue
<template></template>
<script>
import FormErrors from "./FormErrors.vue";
export default {
name: "Form",
mixins: [FormErrors],
data() {
return {
success: false,
error: false,
errorMessage: "",
};
},
methods: {
post(url, data) {
this.success = false;
this.error = false;
axios
.post(url, data)
.then((res) => {
this.onSuccess(res.data.message);
})
.catch((error) => {
if (error.response.status == 422) {
this.setErrors(error.response.data.errors);
} else {
this.onFailure(error.response.data.message);
}
});
},
get(url, data) {
this.success = false;
this.error = false;
axios
.get(url, data)
.then((res) => {
this.onSuccess(res.data.message);
})
.catch((error) => {
if (error.response.status == 422) {
this.setErrors(error.response.data.errors);
} else {
this.onFailure(error.response.data.message);
}
});
},
onSuccess(message) {
this.reset();
this.success = true;
},
onFailure(message) {
this.error = true;
this.errorMessage = message;
},
reset() {
this.clearAllErrors();
for (let field in this.formData) {
this.formData[field] = null;
}
},
},
};
</script>
FormErrors.vue
<template></template>
<script>
export default {
name: "FormErrors",
data() {
return {
errors: {},
};
},
methods: {
setErrors(errors) {
this.errors = errors;
},
hasError(fieldName) {
return fieldName in this.errors;
},
getError(fieldName) {
return this.errors[fieldName][0];
},
clearError(event) {
Vue.delete(this.errors, event.target.name);
},
clearAllErrors() {
this.errors = {};
},
},
computed: {
hasAnyError() {
return Object.keys(this.errors).length > 0;
},
},
};
</script>
When the form is submitted, a laravel post route is called and the information is stored in the database.
Route::post('/contact/store', [ContactController::class,'store'])->name('contact.store');
After this, the Vue component now hides the form and displays a "success" message. So far, everything works great.
Now, I would like to add a step. Instead of success message, I want to obtain the last id entered in the db and show a new form with a hidden field last_id. I am unsure of how to obtain this information from the controller.
It would be a continuation of the previous form, but I do not want to gather all the data at once, I want it in steps. Now, it is also important to gather data from the first form, and if the user quits after the first form that is fine, no problem, but if the user continues with the second form I need to "link" it to the previous form through the last_id.
I think that I am not approaching this problem correctly, maybe I need to change the logic of what I am doing.
Adding last_id to ContactController return:
class ContactController extends Controller
{
public function store(Request $request)
{
$data = $request->validate([
'fullname' => 'required',
'email' => 'required|email',
'phone' => 'required',
]);
$contact_form = Contact::create($data);
$last_id = $contact_form->id;
return [
//how do I "send" this to the Vue component?
'last_id' => $last_id
];
}
}
This would be the "second step" form using the last ID. It would have it's own post route.
<h4>Your form has been successfully submitted, now please give us more info that will be linked to the previous form:</h4>
<form>
<input type="hidden" name="last_id" value="{HOW_TO_GET_THE_LAST_ID_HERE?}" />
<textarea name="message" required></textarea>
<input type="submit" value="Submit" />
</form>
You can use a JSON response:
https://laravel.com/docs/9.x/responses#json-responses
You can return the id in your Controller for example like this:
return response()
->json(['last_id' => $last_id])
You will be able to get the value from the response object of the post call
.then((res) => {
//get the id from the response
this.last_id = (res.data.last_id);
})

How to validate Dynamic input in vuejs / Laravel

I'm catching errors via interceptors and a Toast for UI. Usually the error is caught by the interceptor and displayed via the toast for one-time inputs, i'm trying to catch errors for an uncertain number of inputs. So far looping through the input array and setting rules does not work.
Component.vue
<template>
<div>
<div class="form-group" v-for="(input,k) in inputs" :key="k">
<input type="text" id="name" placeholder="Name" v-model="input.name" />
<span>
<i class="fas fa-minus" #click="remove(k)" v-show="k || ( !k && inputs.length > 1)"></i>
<i class="fas fa-plus" #click="add(k)" v-show="k == inputs.length-1"></i>
</span>
</div>
<button #click="addName">Create</button>
</div>
</template>
<script>
export default {
data() {
return {
inputs: [{name: ''}]
}
},
methods: {
add(index) {
this.inputs.push({ name: ''});
console.log( this.inputs);
},
remove(index) {
this.inputs.splice(index, 1);
},
addName() {
axios.post('/user', {userinputs:this.inputs}).then(response => {})
.catch(error => {
console.log(error);
});
}
}
}
</script>
Controller:
public function store(Request $request)
{
$rules = [
'userinputs' => 'required|max:255',
];
foreach ($request->input('userinputs') as $key => $my_object_in_array) {
$rules[$my_object_in_array['name']] = 'required|max:10';
}
return $rules;
}
I hope this is what you wanted to achieve.
public function store(Request $request)
{
$rules = [
'userinputs.*.name' => 'required|max:255',
];
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), $rules);
if ($validator->fails()) {
//Return the errors as JSON
return response()->json(['success' => 'false', 'errors' => $validator->errors()], 400);
}
//Do something
return ['success' => 'true'];
}

Laravel + Vue Looping a Specific ID once

Hey guys so I'm planning to have a list of my recent chats. The problem is that i just want to loop the same Id (ex. Chatroom_id), in my case its looping the same the Chatroom Id 5 times, cause im checking a db that reciever_id is mine and the result is 5, hence the 5 times it loops the same Chatroom ID. I just want it to loop once ever chatroom Id
Laravel View // where i insert my vue component
<!--- Message or online followers and followings -->
<div id="messagesidebar" class="app-sidebar-userdetails">
<h6 class="sm text-white"> <i> Recent Chat </i> </h6>
<div id="recentchat">
<recentchat-component :user_id="{{ Auth::user()->id }}"></recentchat-component>
</div>
</div>
<!-- /# Message or online followers and followings -->
</div>
Vue Template
<div class="chats" v-for="recentchat in recentchats" v-bind:key="recentchat.id">
{{ recentchat.chatroom_id}}
</div>
Laravel Controller
public function fetchrecentchat($user_id)
{
$recentchat = Chat::Where('receiver_id', $user_id)
->orderBy('created_at', 'DESC')
->get();
return ChatResource::collection($recentchat);
}
Chat Resource
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'message' => $this->message,
'chatroom_id' => $this->chatroom_id,
'user_id' => $this->user_id,
'receiver_id' => $this->receiver_id,
'created_at' => $this->created_at->diffForHumans(),
'updated_at' => $this->updated_at,
];
}
Tell me if you need to review codes that i did not add above so much thanks guys!
Update
Vue script
<script>
export default {
props: [ 'user_id' ],
data() {
return {
recentchats: [],
recentchat: {
id: '',
chatroom_id: '',
user_id: '',
receiver_id: '',
created_at: '',
updated_at: '',
}
}
},
created() {
this.fetchchatrooms();
},
methods: {
fetchchatrooms(){
fetch('/api/fetchrecentchat/' +this.user_id)
.then(res => res.json())
.then(res => {
console.log(res);
this.recentchats = res.data
});
}
},
mounted() {
console.log('Recent Chat mounted.')
}
}

Foreign key on post request Laravel & Vue

I am using a larvel backend with a vue frontend. They are connected by API. I have been trying to figure out how i can correctly submit a form for a model that has a foreign_key relationship with a parent model.
Here is the relationships
A User has many Tasks
A Task belongs to User
A Client has many Engagements
A Engagement belongs to Client
Engagements and Tasks have many to many
User and Client have no direct relationship
So I know that if i wanted to submit a post request for data that had a relationship with user It would be simple to assign the foreign_key like below
*Example
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|string',
'completed' => 'required|boolean',
]);
$todo = Todo::create([
'user_id' => auth()->user()->id,
'title' => $request->title,
'completed' => $request->completed,
]);
return response($todo, 201);
}
But when i try to do this same thing for my client I get a 500 internal server error..
So here is the Workflow
On my vue frontend in the AddEngagment.vue component
<template>
<div class="page-wrapper mt-1">
<div class="add-engagement container">
<div class="card-body bg-light border-primary mb-2">
<h4 class="text-left text-primary m-0"><i class="mr-3 far fa-folder-open"></i>New Engagement</h4>
</div>
<form #submit.prevent="addEngagement" class="d-flex-column justify-content-center">
<div class="form-group">
<select class="form-control mb-3" id="type" v-model="engagement.return_type">
<option v-for="type in types" :key="type.id" :value="type">{{ type }}</option>
</select>
<input type="text" class="form-control mb-3" placeholder="Year" v-model="engagement.year">
<input type="text" class="form-control mb-3" placeholder="Assign To" v-model="engagement.assigned_to">
<input type="text" class="form-control mb-3" placeholder="Status" v-model="engagement.status">
<button type="submit" class="btn btn-lg btn-primary d-flex justify-content-start">Create</button>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'add-engagement',
data() {
return {
engagement: {
return_type: null,
year: '',
assigned_to: '',
status: '',
},
types: [
'Choose Return Type...',
'1040',
'1120',
],
}
},
methods: {
addEngagement(e) {
if(!this.engagement.return_type || !this.engagement.year ){
return
} else {
this.$store.dispatch('addEngagement', {
id: this.idForEngagement,
return_type: this.engagement.return_type,
year: this.engagement.year,
assigned_to: this.engagement.assigned_to,
status: this.engagement.status,
})
e.preventDefault();
}
e.preventDefault();
this.engagement = ""
this.idForEngagement++
this.$router.push('/engagements')
},
},
created: function() {
this.engagement.return_type = this.types[0]
},
}
</script>
I am capturing the data in the input and then dispatching the store for the addEngagement action
Now in the URL for the AddEngagement.vue component I have the client_id shown like below
add-engagement/{client_id}
This is the store.js action for the addEngagement
addEngagement(context, engagement) {
axios.post(('/engagements'), {
return_type: engagement.return_type,
year: engagement.year,
assigned_to: engagement.assigned_to,
status: engagement.status,
done: false
})
.then(response => {
context.commit('getClientEngagement', response.data)
})
.catch(error => {
console.log(error)
})
},
So from here, it sends the request to my /engagement on the laravel api route file like below
Route::post('/engagements', 'EngagementsController#store');
And then goes to the EngagementsController to run the store method below
public function store($client_id, Request $request)
{
$data = $request->validate([
'return_type' => 'required|string',
'year' => 'required|string',
'status' => 'required|string',
'assigned_to' => 'required|string',
'done' => 'required|boolean'
]);
$engagement = Engagement::create([
'return_type' => $request->return_type,
'year' => $request->year,
'assigned_to' => $request->assigned_to,
'status' => $request->status,
'done' => $request->done,
+ [
'client_id' => $client_id
]
]);
return response($engagement, 201);
}
At this point is where I am getting my error and I think it has to do with the $client_id which I have tried many different ways of formatting it with no success. When the URL is storing the client_id on the front end for the post request I do not know how that data is getting shared with laravel for it to know which client the client_id foreign key will be assigned to.
First of all:
$engagement = Engagement::create([
'return_type' => $request->return_type,
'year' => $request->year,
'assigned_to' => $request->assigned_to,
'status' => $request->status,
'done' => $request->done,
+ [
'client_id' => $client_id
]
]);
why is there this +[...] array thing? Doesn't really makes sense to me...
But the 500 Server Error most probably results from your false request (which most of 500's do).
If this is your Route definition:
Route::post('/engagements', 'EngagementsController#store');
This is the method head:
public function store($client_id, Request $request)
And your Post request is the following:
axios.post(('/engagements'), {
return_type: engagement.return_type,
year: engagement.year,
assigned_to: engagement.assigned_to,
status: engagement.status,
done: false
})
You will notice, that the function definition differs from your Route. In the function you expect a parameter 'client_id' which isn't known by the route. So to resolve this issue, put your client_id into the Post request body (underneath your done: false for example) and remove the parameter from the function definition.

Laravel Dynamic Dependent Dropdown

I need to add a Laravel Dynamic Dependent Dropdown. Im confused..
In my database, i have both categories and their childrens.
Account_id =0 => Categorie
Account_id =1 => Sub Categorie of category or subcategory with id =1
Account_id =2 => Sub categorie of category or subcategory with id =2
This is my actual code :
Method:
public function index()
{
$categories = Account::where('account_id', '=', 0)->get();
$allCategories = Account::where('account_id', '=', 0)-
>pluck('account_name','id');
return view('Account.list',compact('categories', 'allCategories')); //
set the path of you templates file.
}
public function children(Request $request)
{
return Account::where('account_id', $request->account_id)->pluck('account_name', 'id');
}
View:
<div class="form-group">
{!! Form::label('account_id', 'Parent Category:')!!}
{!! Form::select('account_id', $allCategories, ['placeholder' =>
'Choose Category'])!!}
</div>
<div class="form-group">
{!! Form::label('children', 'Child category:')!!}
{!! Form::select('children', [], null, ['placeholder' => 'Choose child
category'])!!}
</div>
Route:
Route::get('/categories', [
'uses' => 'AccountController#index',
'as' => 'categories'
]);
Route::get('/categories/children', [
'uses' => 'AccountController#children',
'as' => 'categories.children'
]);
JS:
<script>
$('#account_id').change(function(e) {
var parent = e.target.value;
$.get('/categories/children?account_id=' + account_id, function(data) {
$('#children').empty();
$.each(data, function(key, value) {
var option = $("<option></option>")
.attr("value", key)
.text(value);
$('#children').append(option);
});
});
});
</script>
try this first create new route
Route::post('subchildren/youcontroller', [
'as' => 'children.categories',
'uses' => 'youUrlController\yourController#childrenCategory',
]);
next create route go to controller create new method
public function childrenCategory(Request $request)
{
try {
$subCategory= subCategory::where('category_id', $request->nameSelectCategoryinYourView)->get();
return response()->json(['subCategory' => $subCategory], 200);
} catch (Exception $e) {
return response()->json(['error' => 'Error'], 403);
}
}
next in your view
<div class="form-group m-b-40">
<select name="subCategory" class="form-control p-0" id='subCategory'></select>
</div>
next in your javascript
jQuery(document).ready(function($) {
$('#FirstSelect').change(function () {
$('#subCategory').empty();
var Category = $(this).val();
datos = {
tipo : Category
},
$.ajax({
url: '{{ route('children.categories') }}',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: datos,
success: function (argument) {
arreglo = {id:"a", tipo:""};
argument.detalles.unshift(arreglo);
$.each(argument.subCategory, function(index, el) {
var opcion = '<option value="'+ el.id +'">'+ el.subCategoryName+'</option>';
$('#subCategory').append( opcion );
});
}
})
.done(function() {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
})
});
});

Resources