Problem: internal server error while passing data from vue.js to laravel using axios
I created fresh laravel project and installed breeze with vue (php artisan breeze:install vue). Then I created One menu controller and rendered menu.vue like this :
public function index()
{
$menuItems = Menu::all();
return Inertia::render('Menu', [
'menuItems' => $menuItems
]);
}
Route::get('menu',[MenuController::class,'index']);
Now I created CartController
<?php
namespace App\Http\Controllers;
use App\Models\Cart;
use App\Models\Menu;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function store(Request $request)
{
dd("CONTROLLER");
$menu_id = $request->input('id');
$menu = Menu::find($menu_id);
$cart=new Cart();
$cart->table=$request->table;
$cart->menus_id=$menu_id;
$response=$cart->save();
}
}
and here I have to store data returned from menu.vue
Menu.vue
<script setup>
import { Head } from '#inertiajs/vue3';
</script>
<template>
<Head title="Menu" />
<navbar />
<div
class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4 mx-20"
>
<div v-for="item in menuItems" :key="item.id">
<div class="p-6 bg-white rounded-lg shadow-lg">
<img
v-bind:src="'menuItemImage/' + item.image"
class="w-12 h-12"
/>
<h3 class="text-lg font-medium leading-tight">
{{ item.name }}
</h3>
<button
#click="addToCart(item)"
class="mt-4 bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600"
>
Add
</button>
</div>
</div>
</div>
</template>
<script>
import navbar from "#/Layouts/NavbarLayout.vue";
import axios from "axios";
export default {
name: "Menu",
data() {
return {};
},
components: {
navbar,
},
props: ["menuItems"],
methods: {
addToCart(item) {
console.log(item.id);
axios
.post("/cart", {
menu_id: item.id,
})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error);
});
},
},
};
</script>
The problem is when This called
axios
.post("/cart", {
menu_id: item.id,
})
It gives me this error:
error
This is my app.js
axios
import './bootstrap';
import '../css/app.css';
import { createApp, h } from 'vue';
import { createInertiaApp } from '#inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, App, props, plugin }) {
return createApp({ render: () => h(App, props) })
.use(plugin)
.use(ZiggyVue, Ziggy)
.mount(el);
},
progress: {
color: '#4B5563',
},
});
This is my app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://fonts.bunny.net/css2?family=Nunito:wght#400;600;700&display=swap">
<!-- Scripts -->
#routes
#vite(['resources/js/app.js', "resources/js/Pages/{$page['component']}.vue"])
#inertiaHead
</head>
<body class="font-sans antialiased">
#inertia
</body>
</html>
This is in storage/log file[2023-02-08 16:39:49] local.ERROR: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'menus_id' cannot be null (SQL: insert into carts (menus_id, table, updated_at, created_at) values (?, ?, 2023-02-08 16:39:49, 2023-02-08 16:39:49)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'menus_id' cannot be null (SQL: insert into carts (menus_id, table, updated_at, created_at) values (?, ?, 2023-02-08 16:39:49, 2023-02-08 16:39:49)) at D:\\Trinity\\7th sem\\Project work\\smart_QR_based_restaurant\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:760) [stacktrace]
This might be your issue,
you are passing this object as the post data
{menu_id: item.id}
then you call a non-existing input in your controller $request->input('id')
$menu_id = $request->input('id');
$menu = Menu::find($menu_id);
it should be $request->input('menu_id');
but again, check your logs to see the actual error thrown
also, you should add a validation in your controller to make sure the ID you pass exist in your table
public function store(Request $request) {
$request->validate([
'menu_id' => 'required|exists:menus,id'
]);
$menu_id = $request->input('menu_id');
$menu = Menu::find($menu_id);
$cart=new Cart();
$cart->table=$request->table;
$cart->menus_id=$menu_id;
$response=$cart->save();
}
I passed menu_id from post menu.vue but $cart->table gets null value so I got this error : Integrity constraint violation
so for now I give this value directly
public function store(Request $request)
{
$menu_id = $request->input('menu_id');
$menu = Menu::find($menu_id);
$cart = new Cart();
$cart->menus_id = $menu_id;
$cart->table = 2;
$response = $cart->save();
}
Thank you guys for helping me 😊
Related
Issue:
I have a laravel 9 app builded with vue3 , inertia-laravel , inertiajs and laravel-vite , it works perfetct on PC but when I try to open it in mobile device It show a blank page without any console log.
NB : when I toggle device toolbar to mobile in a navigator it works correctly but in real mobile no ( I tested on different navigators)
I can't fix this issue come from inertiajs\inertia-vue3 or inertiajs/inertia-laravel
When I render a blade view it works, just when I render inertia object
Versions:
inertiajs/inertia-laravel version: 0.6.3
#inertiajs/inertia version: 0.11.0
#inertiajs/inertia-vue3 version: 0.6.0
Codes:
web.php:
Route::get('/', function() {
return Inertia::render('WelcomeView');
});
app.js
import './bootstrap';
import '../css/main.css'
import { createPinia } from 'pinia'
import { useStyleStore } from '#/Stores/style.js'
import { darkModeKey } from '#/config.js'
import { createApp, h } from 'vue'
import { createInertiaApp } from '#inertiajs/inertia-vue3'
import { InertiaProgress } from '#inertiajs/progress'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m'
import Notifications from 'notiwind'
import * as ConfirmDialog from 'vuejs-confirm-dialog'
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'
const pinia = createPinia()
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(pinia)
.use(Notifications)
.use(ConfirmDialog)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
InertiaProgress.init({
color: '#5136a8',
showSpinner:true
})
const styleStore = useStyleStore(pinia)
/* App style */
//styleStore.setStyle(localStorage[styleKey] ?? 'basic')
styleStore.setStyle()
/* Dark mode */
if ((!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dark)').matches) || localStorage[darkModeKey] === '1') {
styleStore.setDarkMode(true)
}
WelcomeVue.vue (under pages folder) :
<template>
<div>
hellow world
</div>
</template>
and app.blade.php :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{!! csrf_token() !!}" />
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<!-- Scripts -->
#routes
#vite('resources/js/app.js')
#inertiaHead
</head>
<body class="font-sans antialiased">
#inertia
</body>
</html>
In my Vue JS 3 app, I am using the onMounted hook to load an object from a restful API, using the object id defined in the router in my GET request.
Here's the object view.
folder.vue
<template>
<div>
<div v-if="errorMessage">{{ errorMessage }}</div> -->
<NavBar :pageTitle="folder.title" />
<div class="max-w-full md:max-w-7xl lg:max-w-5xl mx-auto mt-6">
<p class="pl-6 pb-2 font-semibold text-white">Cerca </p>
<SearchBar />
<div v-if="folder.documents !== []" class="grid grid-cols-3 gap-4 py-6">
<div v-for="document in folder.documents" :key="document.id">
<RouterLink :to="{ name: 'document', params: { documentId: document.id } }">
<FancyCard :title="document.title" :text="document.intro" />
</RouterLink>
</div>
</div>
<div v-if="folder.documents === [] | folder.documents === null">
<p>Non ci sono documenti, creane uno.</p>
</div>
</div>
</div>
</div>
</template>
import { defineComponent, onMounted, onErrorCaptured, ref } from 'vue';
//... all other necessary imports
export default defineComponent({
name: 'Folder',
components: { NavBar, IconButton, SearchBar, FancyCard },
setup() {
const folder= ref<FolderModel | null>(null);
const router = useRoute();
const folderId = router.params.folderId as string
const folderService = useFolderService();
onMounted(async () => {
folder.value = await folderService.get(folderId);
})
const errorMessage = ref<string | null>(null);
onErrorCaptured((e: unknown) => {
errorMessage.value = (e as Error).message;
return false;
});
return { folder, errorMessage };
}
})
and this is my folderService.ts
export function useFolderService() {
return {
async list(): Promise<Array<FolderModel>> {
const response = await axios.get<Array<FolderModel>>('myAPIendpoint');
return response.data;
},
async get(folderId: string): Promise<FolderModel> {
const response = await axios.get<FolderModel>(`myAPIendpoint/${folderId}/`, { params: { status: 'PENDING' }});
return response.data;
},
};
}
These below are the warnings and error displayed on the console:
(warning) [Vue warn]: Unhandled error during execution of render function at <Folder onVnodeUnmounted=fn ref=Ref<
undefined > > at at
(warning) runtime-core.esm-bundler.js?5c40:38 [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue
internals bug. Please open an issue at
https://new-issue.vuejs.org/?repo=vuejs/vue-next at <Folder
onVnodeUnmounted=fn ref=Ref< undefined > > at
at
(error) Uncaught (in promise) TypeError: Cannot read property 'title' of null
I am assuming the issue is somewhere in this line:
const folder = (ref < FolderModel) | (null > null);
because if I change it and give the folder an initial value, it works as expected, but since I am loading the folder within the onMount lifecycle hook, the above definition should be correct.
On a side note, the same kind of setup used in the listing view where I retrieve all folders works perfectly:
setup() {
const folderService = useFolderService()
const folders = ref<Array<FolderModel> | null>(null);
onMounted(async () => {
folders.value = await folderService.list();
})
return {
folders
};
}
Thank you in advance for your help.
What I want to come true
I want to display an alert message considering the result of the data sent to the server.
However, since alert messages are managed by another component, it is necessary to call the component asynchronously.
The official Vue.js documentation used Vue.component, but what's the right way to do it with Nuxt.js?
Code
I want to use search.vue in success.vue
search.vue
<template>
<v-app>
<div
class="teal lighten-1 background pa-10"
>
<!-- <div
v-if="responseBook === 200"
> -->
<alert-success />
<v-sheet
width="1100px"
class="mx-auto pa-5 rounded-xl"
color="grey lighten-5"
min-height="500px"
>
<!-- 書籍検索、表示 -->
<BookPostDialog />
<!-- 選択されたデータの表示 -->
<BookPostSelected />
</v-sheet>
</div>
</v-app>
</template>
<script>
export default {
computed: {
responseBook () {
return this.$store.state.book.responseBook.status
}
}
}
</script>
<style lang="scss" scoped>
.background {
background-image: url('~/assets/images/tree.png');
background-repeat: space repeat;
}
</style>
Alert/success.vue
<template>
<v-alert type="success">
Succeeded
</v-alert>
</template>
If you want to use that kind of feature, you'll be better suited looking for something like this component: https://buefy.org/documentation/toast
Or anything like this in the jungle of CSS frameworks, pretty sure each of them have one.
Or implement it yourself, for this, you need to rely on portals.
For Vue2, this is how to do achieve it: https://portal-vue.linusb.org/guide/getting-started.html#enabling-disabling-the-portal
<portal to="destination" :disabled="true">
<p>
Your content
</p>
</portal>
If you want to show success.vue component after the connection to server (getting or posting data), you can use v-if as follows:
search.vue
<template>
<div>
<p>search compo</p>
<div v-if="this.$store.state.book.responseBook == 'ok'">
data was received.
<success />
</div>
</div>
</template>
<script>
export default {
mounted() {
this.$store.dispatch('getData')
}
}
</script>
success.vue
<template>
<div>
succeess compo
</div>
</template>
And then in your store/index.js file:
import Vuex from "vuex";
const createStore = () => {
return new Vuex.Store({
state: {
book: {
responseBook: ""
}
},
mutations: {
bookMutate(state, data) {
state.book.responseBook = data;
}
},
actions: {
getData(vuexContext) {
let vue = this;
// your request is here
setTimeout(function() {
vue.$axios.$get("https://pokeapi.co/api/v2/pokemon/ditto").then((result) => {
console.log(result);
vuexContext.commit("bookMutate", "ok");
}).catch(err => {
console.log(err);
})
}, 10000)
},
}
});
};
export default createStore;
I intentionally used setTimeout() in my action to see that the success component is loaded after the data was received. in actual situation it is better to use this action:
getData(vuexContext) {
this.$axios.$get("https://pokeapi.co/api/v2/pokemon/ditto").then((result) => {
console.log(result);
vuexContext.commit("bookMutate", "ok");
}).catch(err => {
console.log(err);
})
},
I used axios for calling the api but you can use your own method of getting data. but after that you must commit the mutation to change the state.
I have that error: Unknown custom element: - did you register the component correctly?
I want do likes system with Vue.js .
How i can fix this? Please help.
It seems like I wrote everything correctly ...
I have practically no experience with a tool like Vue.js, so I don’t quite understand what’s wrong
web.php
Route::post('/blog/like','BlogController#getlike');
Route::post('/blog/like/{id}','BlogController#like');
BlogController
public function getlike(Request $request)
{
$article = Article::find($request->article);
return response()->json([
'article'=>$article,
]);
}
public function like(Request $request)
{
$article = Article::find($request->article);
$value = $article->like;
$article->like = $value+1;
$article->save();
return response()->json([
'message'=>'Thanks',
]);
}
LikeComponent.vue
<template>
<div class="container">
<p id="success"></p>
<i #click.prevent="likePost" class="fa fa-thumbs-up" aria-hidden="true"></i>({{ totallike }})
</div>
</template>
<script>
export default {
props:['article'],
data(){
return {
totallike:'',
}
},
methods:{
likePost(){
axios.post('/blog/like/'+this.article,{article:this.article})
.then(response =>{
this.getlike()
$('#success').html(response.data.message)
})
.catch()
},
getlike(){
axios.post('/blog/like',{article:this.article})
.then(response =>{
console.log(response.data.article.like)
this.totallike = response.data.article.like
})
}
},
mounted() {
this.getlike()
}
}
</script>
app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('like-component', require('./components/LikeComponent.vue').default);
const app = new Vue({
el: '#app',
});
article.blade.php
<like-component :post="{{ $article->id }}"></like-component>
i think you have to define your sub components
inside a tag which has an id app in
article.blade.php
like this :
< div id=“app”>
< like-component : post="{{ $article->id }}">
< / div>
“
and you have to run
npm run watch in your console
I am currently refactoring some old code. I want to get the data of of a vue form in order to post into my database through laravel's api. Looking at the json output I get & the controllers method everythings looks fine to me. I also tried to move the Route::post code to the regular web.php without success.
I'll post a screenshot of my schema & exact errors message (xhr cancelled).
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('/session', 'SessionController#index');
Route::get('/session/{id}', 'SessionController#currentRoom');
Route::post('/create', 'SessionController#create');
Route::put('/session/{id}', 'SessionController#update');
Route::delete('/session/{id}', 'SessionController#destroy');
SessionController.php
<?php
namespace App\Http\Controllers;
use App\Services\LongPolling;
use Faker\Generator;
use App\Session;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Response;
class SessionController extends Controller
{
public function create(Request $request)
{
// $session = new Session();
// $session->playerName = $faker->name;
// $session->playerId = $faker->numberBetween($min = 0, $max = 127);
// $session->roomName = $faker->name;
// $session->roomDescription = $faker->text;
// $session->overallValue = $faker->numberBetween($min = 10, $max = 70);
// $session->playerValue = $faker->randomDigitNotNull;
// $session->isAdmin = $faker->boolean ? false : true;
// $session->save();
$validator = Validator::make($request->all(), [
'roomName' => 'required|string',
'roomDescription' => 'required|string'
]);
if ($validator->fails()){
return Response::json(['errors' =>$validator->errors()], 422);
}
$session = Session::create([
'roomName' => $request('roomName'),
'roomDescription' => $request('roomDescription')
]);
return Response::json(['session' => $session,
'message' => 'success'], 200);
}
Create.vue
<template>
<div>
<form>
<strong>roomname:</strong>
<br />
<input type="text" v-model="roomName" />
<br />
<strong>description:</strong>
<br />
<input type="text" v-model="roomDescription" />
<br />
<button v-on:click="formSubmit">Click me</button>
</form>
</div>
</template>
<script>
export default {
components: {},
data() {
return {
roomName: "",
roomDescription: ""
};
},
methods: {
formSubmit() {
axios
.post("/api/create", {
roomName: this.roomName,
roomDescription: this.roomDescription
})
.then(function(response) {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
}
};
</script>
<style>
</style>
room.blade.php
<!-- Stored in resources/views/child.blade.php -->
#extends('layouts.app')
#section('title', 'Scrumpoker')
#section('content')
<br>
<br>
<create>
</create>
#endsection
app.js
require('./bootstrap');
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
Vue.use(Vuetify)
const opts = {}
// Vue.component('App', require('./components/App.vue').default);
// Vue.component('Card', require('./components/card.vue').default);
// Vue.component('session', require('./components/Session.vue').default);
Vue.component('create', require('./components/Create.vue').default);
const app = new Vue({
el: '#app',
vuetify: new Vuetify(),
});
Check if it's related to CORS and not related to POST?