Laravel and Inertia create route inside Vue - laravel

I installed Laravel with Inertia. And I got this inside resources/js/app.js:
require('./bootstrap');
// Import modules...
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
})
.mixin({ methods: { route } })
.mixin(require('./translation'))
.use(InertiaPlugin)
.mount(el);
InertiaProgress.init({ color: '#4B5563' });
As you may see there is .mixin({ methods: { route } }). I can use this.route('name.of.route') to generate named route from ˙routes` folder.
I want to modify route method to add prefix by default every time route is generated. How do I adjust Inerta's route method.

With Inertia all routing is defined server-side. Meaning you don't
need Vue Router or React Router. Simply create routes using your
server-side framework of choice.
You can read more about it here (https://inertiajs.com/routing#top)
You've got all the routes available on your javascript installed because of ziggy library. It provides a JavaScript route() helper function that works like Laravel's, making it easy to use your Laravel named routes in JavaScript.
To modify or add prefix to the URL, you'll have to do it from the backend(Laravel) using Middleware or Route Groups, because Ziggy doesn't create URL, it just provides the URL that you define in your Laravel's web.php file in your Javascript.
That's why you have #routes in your root blade file. If you remove that, this.routes or this.$routes won't be available.
E.g.
Route::group(['prefix' => 'u'], function () {
Route::inertia('/dashboard', 'Dashboard')->name('dashboard');
});
This means this URL will be available at /u/dashboard and you can access it with Javascript as this.route('dashboard');
Or read more on the ziggy package to give you the desired result

Related

Laravel Vue3 - Passing Token and User info to Vue store

I'm creating a Laravel/Vue3 app and wanted to completely separate the Laravel router from the SPA router.
In order to achieve this I created a dashboard.blade.php file which contains the following content:
<x-app-layout>
<div id="app"></div>
</x-app-layout>
Vue then simply mounts on top of that div and the app is started.
My webpack.mix.js:
const mix = require("laravel-mix");
mix.ts("resources/js/app.ts", "public/js")
.vue({ version: 3 })
.postCss("resources/css/app.css", "public/css", [
require("postcss-import"),
require("tailwindcss"),
require("autoprefixer"),
]);
The app.ts file is also quite simple:
import { createApp } from 'vue';
import App from './App';
createApp(App).mount('#app');
Which is great, but my holdup is that for subsequent requests (via Axios), I will need the user token. How can I get this token/logged in user info to my Vue3 app?
I'm using Laravel Breeze for authentication (if that helps).
Thank you,
It turns out the answer was 'extremely' simple. I had to do nothing besides removing the comment tags on this line:
And add headers as follows in your axios config:
import axios from "axios";
import store from "../store";
const Axios = axios.create({
baseURL: process.env.APP_URL,
headers: { Accept: "application/json" },
});
Axios.interceptors.request.use(
(config) => {
store.commit("setLoader", true);
return config;
},
(error) => Promise.reject(error)
);
Axios.interceptors.response.use(
(response) => {
store.commit("setLoader", false);
return response;
},
(error) => Promise.reject(error)
);
export default Axios;
Subsequent axios calls have the token attached automatically.
You can find all the required information here. Love Laravel...

Vue components in Inertia with Laravel seems to load twice

With a newly created Laravel with Inertia and Vue project, I have an error that it runs code inside my vue components twice.
For a simple test demo, I have a Test.vue, with this code
<template>
<div>
TEST
</div>
</template>
<script>
export default {
name: "Test",
mounted() {
console.log('test')
}
}
</script>
<style scoped>
</style>
Route in web.php:
Route::get('/test', array(App\Http\Controllers\DashboardController::class, 'test'));
In controller:
public function test(): Response
{
return Inertia::render('Test');
}
When I go to the route /test, it echoes out 'test' twice on mounted in my console. In more advanced components which calls APIs and such, also calls them twice.
I suspect maybe my project is set up wrongly, in app.blade.php or app.js but cannot figure it out.
I followed the guides on https://inertiajs.com/server-side-setup and https://inertiajs.com/client-side-setup to set this up.
My source code is here: https://github.com/ekstremedia/laravel-inertia
Edit: It seems to only echo out twice in the first component I load. If I in that component link to another component, and go there, it doesn't load that twice.
I found that this is solved by modifying your app.js file in your resources directory thus:
import Vue from 'vue'
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue'
Vue.use(InertiaPlugin)
new Vue({
render: (h) =>
h(InertiaApp, {
props: {
initialPage: JSON.parse(app.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
},
}),
}).$mount(app);
Your problem seems to have been in how you initialized your inertia app.

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

Get data from Laravel(in api folder) to Vue (placed in another folder)

I have Laravel in api folder and Vue is in the root folder, and I try to pass data from Laravel to Vue Components.From what I find I must use axios for this but I didn't know how. I am looking for a solution for some hours now, but nothing worked. PS. I didn't do anything in blade till now. Any help, please !?
api/routes/api.php
Route::get('/content', 'ContentController#index');
ContentController
public function index() {
$customers = Customer::all();
return $customers;
}
Vue component
<template>
</template>
<script>
import axios from 'axios'
export default {
name: "Home"
};
</script>
Since you created your Vue app using the Vue CLI, running vue serve starts your application at a local URL, you need to have your Laravel API app running as well so you can request data from it using Axios in Vue components
cd api
php artisan serve
Then in your template, you should have something like this
<template>
<div></div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
databaseConfiguration: "",
errors: {}
};
},
name: "Home",
created: function() {
axios
.get("http://127.0.0.1:8000/api/content")
.then(response => {
this.databaseConfiguration = response.data;
console.log(response.data);
})
.catch(error => {
this.errors.push(error);
console.log(error);
});
}
};
</script>
Here's a full working example app on GitHub
Hope this helps

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