405 error when deleting row Laravel, Inertia+Vue.js - laravel

I am working with Laravel and Inertia+Vue.js.
I am trying to delete a row but I get a 405 error method not allowed.
Here is my code in Layout.vue :
<a #click="destroy(website)">delete</a>
import AppLayout from '#/Layouts/AppLayout.vue';
import {Link} from "#inertiajs/inertia-vue3";
import {Inertia} from "#inertiajs/inertia";
export default {
components: {
Link, AppLayout, Inertia
},
props: {
websites: Object
},
methods: {
destroy(website) {
if(confirm('are u sure?')) {
this.$inertia.delete(`/destroy/website/${website.id}`)
}
}
},
the method in my controller :
public function destroy(Website $website)
{
$website->delete();
return redirect()->route('dashboard');
}
my route in web.php :
Route::delete('/destroy/website/{id}', [WebsiteController::class, 'destroy']);
the request from the browser as it appears in the network panel is DELETE https://website.fr/destroy/website/2 (2 is the id of the website I clicked on)
any help will appreciated !

For this to work:
destroy(Website $website)
your route should be:
Route::delete('/destroy/website/{website}', [WebsiteController::class, 'destroy']);
not /destroy/website/{id} so Laravel can inject the model with the id passed from your front end

My suggested code for the routes section:
Route::delete('destroy-website/{website}', [WebsiteController::class, 'destroy']);

Related

Vue & Laravel - Pass prop to a constant

I'm passing posts from controller to a Vue component:
public function show(Post $post)
{
return Inertia::render('Post/Show', ['post' => $post]);
}
In my vue file I have this:
<script>
import { ref, computed } from 'vue'
export default {
props: {
post: Object
}
}
const article = ref(post)
But this throws an error: Uncaught (in promise) ReferenceError: post is not defined.
How do I pass my post obj and assign it to the article constant?
I tried props.post but that isn't the solution, I'm very new to Vue and I'm mostly focused on backend stuff.

Cannot read properties of null (reading 'allowRecurse')

I have a problem with Laravel/Inertia which gets me the error message :
Cannot read properties of null (reading 'allowRecurse')
There is a form, i post the form to a controller and after saving the data i tried to redirect to the main page. I tried several ways, return Redirect::route('home'); or return redirect()->back(); even other ways i found searching for a solution. They all give me the same error message.
The redirect()->back() function works and brings me back to my form, but when i try to redirect there i get that same message.
I deleted everything of what i think is not essential, so the form and controller now don't do anything anymore, but still i get that error message.
I can't find anything about this error on the internet. What mistake am I overlooking?
Edit: I found something... Somewhere in page that i am going to (that home.vue page) i have a link with the same URL as where i came from. Apparently Vue or Laravel doesn't approve. But i need that. Can i set the value of AllowRecurse to True somewhere? Or is that a bad idea?
My vue-file:
<template>
<div>
<form #submit.prevent="submit">
<div class="flex justify-center mt-4">
<app-button class="w-1/2 justify-center" :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
Insturen
</app-button>
</div>
</form>
</div>
</template>
<script>
import AppButton from '#/Components/Button.vue'
export default {
components: {
AppButton,
},
props: {
game_id: String,
code: String,
},
data() {
return {
form: this.$inertia.form({
name: '',
email: '',
})
}
},
setup() {
},
methods: {
submit() {
this.form.post(route('toto_store',{'game_id': this.game_id, 'code': this.code}), {
preserveScroll: true,
resetOnSuccess: false,
onSuccess: () => { this.$inertia.visit(route('home'))} ,
});
}
}
}
</script>
My controller:
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Models\Guess;
use Illuminate\Http\Request;
class TotoController extends Controller
{
public function store(Request $request, $id, $code)
{
return redirect()->back()->with("success", "Opgeslagen");
}
}
My webroutes:
Route::get('/', [HomeController::class, 'show'])->name('home');
Route::get('/guesses/{game_id?}', [GuessController::class, 'index'])->name('guesses');
Route::get('/toto/{game_id}/{code}', [TotoController::class, 'create'])->name('toto_create');
Route::post('/toto/{game_id}/{code}', [TotoController::class, 'store'])->name('toto_store');
Route::get('/qr-code/{id}', [QRController::class, 'show'])->name('qr-code');
The error:
Any ideas?

Axios response.data return HTML instead of an object

I need help about Axios.
I develop a SPA webapp on Laravel 6 (with package SPARK) and VueJS (version 2).
On a Vue component, I want to retrieve datas from my bdd.
So, I use Axios to make a get request on an API uri.
But, when I call Axios request, data field in Response object is a HTML code.
This is my code :
routes/web.php
Route::get('/', function(){
return view('welcome');
});
Route::middleware('auth')->get('/{any?}', function (){
return view('documents');
})->where('any', '[\/\w\.-]*');
The "welcome" view is a blade page where redirect on "/login" if user is not authenticate.
Otherwise, it redirect on "/home".
The link "/home" is define on vue-router in app.js.
The other route is the unique way to display the webapp (it's a single page application).
The Vue instanciation is in "passeport" view.
resources/js/app.js
import 'es6-promise/auto'
require('spark-bootstrap');
require('./components/bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
Vue.component('index', require('./components/pages/index').default);
import Dashboard from './components/pages/dashboard.vue';
...
const routes = [
{
name: 'dashboard',
path: '/home',
component: Dashboard,
},
{...}
]
const router = new VueRouter({
history: true,
mode: 'history',
routes: routes
});
var app = new Vue({
mixins: [require('spark')],
router,
});
router package is added in Vue instanciation.
it is in the same context than spark component (identify by the #spark-app element)
resources/views/documents.blade.php
#extends('spark::layouts.app')
#section('content')
<div id="app">
<index :user="user"></index>
</div>
#endsection
It is the view returned for any path.
In the spark::layout.app, there is only a div with id="spark-app" and the #yield('content').
resouces/js/components/pages/index.vue
<template>
<transition name="fade">
<Component :is="layout" :user="user">
<router-view :layout.sync="layout" :user="user"></router-view>
</Component>
</transition>
</template>
.
.
<script>
const default_layout = "default";
export default{
props: ['user'],
data(){
return{
layout: 'div',
}
},
}
</script>
It's just the vue component with the router-view configure with a layout.
resources/js/components/pages/dashboard.vue
<template>
...
</template>
<script>
import Default from './../layouts/Default.vue'
export default {
props: ['user'],
data: function () {
return {
documents: []
}
},
created() {
this.$emit('update:layout', Default);
},
mounted(){
// extract passeports's informations
this.axios.get('/api/documentslist').then(response => {
console.log(response);
this.documents= response.data.data;
});
}
}
</script>
Here, I call the documentslist API define in routes/api.php.
routes/api.php
Route::middleware('auth:api')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::get('/documentslist', 'DocumentController#list');
});
app/http/Controllers/DocumentController.php
...
public function list(Request $request){
return DocumentCollection(Document::all());
}
...
When I go to "/home", I verified "documents" data in Vue (or in the javascript console log), and response.data = "\r\n\r\n\r\n (...) v-if=\"notification.creator\" :src=\"notification.creator.photo_url\" class=... (10024 total length)"
But, list method in DocumentController have to return a list of documents, and not a HTML code.
Furthermore, I use Passport Laravel to unified authentication by login and the API token.
And the Axios request work in the same project without SPA structure.
I hope I'm clear in the problem explanation, and that I forget any detail to understand.
Thanks.
You can simply return like this from your controller
return response()->json(Document::all());
I suspect the API link to redirect with the SPA route (in routes/web.php, any path return the "home" view).
I try to change route in routes/web.php.
instead of :
Route::middleware('auth')->get('/{any?}', function (){
return view('home');
})->where('any', '[\/\w\.-]*');
I put this :
Route::middleware('auth')->get('/home', function (){
return view('home');
});
Like this, this route doesn't take account of all path.
And...it works !
But...it isn't what I want :(
Indeed, without the route with '/{any?}' the SPA doesn't work.
I don't understand why this method works another project in Laravel (without Spark package), and doesn't work with this project.
I don't know about laravel but this problem arises when the route you are calling is not the correct one. Do some efforts and check what route the application in eventually calling also take a look at your proxy settings.
****I am NodeJs developer not Laravel

How to check in a Vue component if a user is authenticated in Laravel?

As the title states, I'm a little confused how I would tackle a method in my Vue Component with if/else statement based on if the user is logged in and authenticated with Laravel's Auth facade. I'm making various Axios requests which I need to allow/disallow based on if user logged in.
I have VUEX setup and was thinking that I can use local storage somehow to have a state for isLoggedin for example that works with Laravel. But I don't know if this is correct method, or secure and presumably Laravel is already storing it's authentication. So can I just access that direct in Vue?
Some unclean solutions here that I don't think are the best -
https://laracasts.com/discuss/channels/vue/hide-button-if-user-is-logged-with-laravel-and-vuejs
I can not find any examples for this :(
Usually from your controller, you pass the authenticated user object into the view which will then be stored in a javascript variable
Controller:
public function index()
{
return view('index', [
'auth_user' => Auth::user()
]);
}
You will know if a user is authenticated if it returns an object or null where null means no user is authenticated.
In your blade, assign the auth_user into a javascript variable:
<script>
window.auth_user = {!! json_encode($auth_user); !!};
</script>
your vuex store object should atleast look like this:
{
state: {
user: null
},
mutations: {
setAuthUser(state, user) {
state.user = user;
}
},
getters: {
isLoggedIn(state) {
return state.user !== null;
}
}
}
Then in your Vue root component, get the auth_user and save it into the store:
<script>
export default {
mounted() {
this.$store.commit('setAuthUser', window.auth_user);
}
}
</script>
You now basically have a getter called this.$store.getters.isLoggedIn that you can use in your application for checking if a user is currently logged in.
e.g:
Use axios interceptors. You intercept the access denied http response code and then act accordingly.
window.axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
if (419 === error.response.status) {
location.reload();
} else {
//Something else you want to do or do nothing
}
});
Putting a script within blade file will throw Vue Warning. Let me answer "How to check in a Vue component if a user is authenticated in Laravel" and leave you with your Vuex complexity. Also this method is simpler.
So, in your controller:
public function index()
{
return view('index')->with('auth_user', auth()->user());
}
In your blade(main.blade.php):
<div class="container">
<example-component :auth_user='#json($auth_user)'></example-component>
</div>
In your vue-component, get your props(ExampleComponent.vue):
<script>
export default {
props: ['auth_user'],
created () {
console.log(this.auth_user)
}
}
</script>
Returns null if user is not logged in
I'm working with laravel 7+
and it doesn't need to send Auth::user() via controller
Just call it from your laravel blade template file like below
your-template-name.blade.php
#if (Auth::check())
<script>window.authUser={!! json_encode(Auth::user()); !!};</script>
#else
<script>window.authUser=null;</script>
#endif
inside YourComponent.vue, store authUser like this:
<script>
export default {
data() {
return {
authUser: window.authUser
}
},
created() {
console.log(this.authUser);
},
methods: {
yourMethodName() {
console.log(this.authUser);
}
}
}
<script>

What is the best way to use Laravel route in Vue JS component

I have a vue js component which makes an axios request to a laravel route. But in the vue files I don't have access to the route() function and have to use static url's for now.
Here's some code:
web.php:
// API
Route::group(['prefix' => 'api'], function() {
// GET
Route::get('/brands', 'BrandsController#getBrands')->name('api-get-brands');
Route::get('/{brand_id}/models', 'BrandsController#getModels')->name('api-get-models');
Route::get('/fuel-types', 'BrandsController#getFuelTypes')->name('api-get-fuel-types');
Route::get('/gearboxes', 'BrandsController#getGearboxes')->name('api-get-gearboxes');
});
Vue component:
methods: {
getBrands: function() {
let app = this
axios.get('/api/brands')
.then(function(response) {
app.brands = response.data
})
.catch(function(error) {
console.log(error)
})
},
...
}
It works now but I wonder if that's the best way or is there some better way to do it
You can pass the route as props to the component inside the blade file.
Inside the view:
<component home-route="{{ route('home') }}"></component>
Inside the vue component:
<script>
export default {
props: ['homeRoute'],
}
</script>
Then you can access the route inside the component like so:
this.homeRoute
You can learn more about props here: https://v2.vuejs.org/v2/guide/components-props.html
Hope this helps.
The only way how to use routes with parameters that I found out is like this:
The route:
Route::get('route/{param1}/{param2}', [Controller::class, 'actionName'])->name('routeName');
The blade:
<component :route="'{{ route('routeName', ["", ""]) }}'"></component>
where the number of empty strings in the array is equal to the number of required parameters for the route.
The component:
<script>
export default {
props: {
route: String
},
data() {
return {
param1: "",
param2: ""
}
},
computed: {
fullRoute() {
return this.route + '/' + this.param1 + '/' + this.param2;
}
}
}
</script>
I am using Laravel 8 and Vue 3.
Use https://github.com/tighten/ziggy
Ziggy provides a JavaScript route() helper function that works like Laravel's, making it easy to use your Laravel named routes in JavaScript.
You can then use routes in JS just like in PHP
route('posts.index');
With parameters too
route('posts.show', [1]);

Resources