Laravel Routes with Vue Router (SPA) Not Working as normal - laravel

I am trying to create a Laravel Vue SPA application. And it seems that I cannot get the route all to function properly. Everytime I use the get('{any}') all my axios get methods call returns the index.blade.php. But if I define all routes in routes.js with more or less the same signature in my web.php (Laravel) my axios routes in getting the data works fine.
web.php
// This work but every time I do an Axios call it returns my index.blade.php
Route::get('{any}', 'SiteController')->where('any', '.*');
// This works if I define all routes, with axios fetching data normally and
// displaying the data in Vue normally
Route::get('/', 'SiteController');
Route::get('/blog', 'SiteController');
Route::get('/post/{postId?}', 'SiteController');
routes.js
const routes = [
{ path: '*', component: Home },
{
path: '/',
component: Home,
children: [
{
name: 'blog',
path: '/blog',
component: PageBlogLists,
},
{
name: 'post',
path: '/post/:page_id',
component: PageBlog,
},
],
},
];
export default new VueRouter({
base: '/',
fallback: true,
mode: 'history',
routes: routes,
});

So I finally got it working I've changed my routes to
Route::get('/{any}', 'SiteController')->where('any', '^(?!api).*$');
and move all my API requests to the api.php file
Route::resource('/posts', 'WordpressController');
router.js and axios works fine now :)

So first the root view, I do not know how does yours look like but it should be something like this
Route::get('{path}', function () {
return view('index');
})->where('path', '(.*)');
Second, you are building SPA, you should not be using web.php, you should use api.php
if you have to and really want to use web.php, you can move the any down to the bottom, and prefix all the other routes with something else.

I do not have a clear picture of the other codes you have in your hands.
But for laravel vue router, this reference helps me a lot
https://medium.com/#weehong/laravel-5-7-vue-vue-router-spa-5e07fd591981
You could give it a try. Hope this helps.

Related

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

Laravel Vue VueRouter history mode

I'm building an e-commerce project with laravel, vue and vue router
I want to use vue router with history mode but it cause me trouble.
Here is my code
new Vue({
el: '#app',
router: new VueRouter({
mode: 'history',
routes
})
});
Here is my route in web.php which have locale middleware
Route::group(['prefix' => '{locale}', 'where' => ['locale' => '[a-zA-Z]{2}'], 'middleware' => 'setlocale'], function () {
Route::view('/{path?}', ('layouts.app'))->where('path', '.*');
});
Here is my route with vue router
export const routes = [
{
path: '/',
component: require('./components/Page/HomePage').default,
},
{
path: '/product',
component: require('./components/Page/Product/ProductPage').default,
},
];
I need my url to be
http://localhost/en
instead of (with the hashtag)
http://localhost/en#/
After using history mode, i successfully remove the hashtag. But, the router link of other will remove my locale in my url
http://localhost/product
I don't know what to do now with it.
Please help~ Thanks.
Update 19 Mar 2020
You need to set the base value to tell Vue Router what the base URL of your application is. In your case you can set it dynamically using the locale value.
For example, in your Blade template you could have the following script to set the locale value on the JavaScript window object:
<script>
window._locale = "{{ app()->getLocale() }}";
</script>
And then you can set the base value to the locale when creating your router:
router: new VueRouter({
mode: 'history',
base: `/${window._locale}/`,
routes
})
Very simple way is too Accept the locale in Vue router too. So your route would be like this:
export const routes = [
{
path: '/:locale',
children: [
{
path: '',
component: require('./components/Page/HomePage').default,
},
{
path: 'product',
component: require('./components/Page/Product/ProductPage').default,
},
]
}
];
just be sure for children route dont put '/' in begining because its remove locale

On refresh vuejs template is not working and I get just json Data, Vuejs and Laravel

I have a route where when I refresh the page I get only the JSON info for that page. (only on refresh F5). The rest of the routes are ok. I am not sure what I am doing wrong.
web.php
Route::get('/persons', 'MyController#index');
Route::post('/record/{personId?}', 'MyController#create'); // this is the one that don't work on refresh
Route::get('/record/{id}', 'MyController#getRecord');
Route::delete('/record/{id}', 'MyController#destroy');
Route::get('/lookups', 'LkpController#index');
Route::post('/validate', 'MyController#getValidation');
//Routes for VueJs
Route::get('/{any}', function () {
return view('welcome');
})->where('any','^(?!api).*$')->name('home');
router.js
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: { requiresAuth: true }
},
{
path: "/record",
name: "Record",
component: Record,
meta: { requiresAuth: true }
},
{
path: "/record/:id",
name: "View Record",
component: require ('./components/AddPerson').default,
meta: { requiresAuth: true }
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
The problem is that you are putting all your routes in web.php, and you have the same routes for your Vue SPA as your Laravel application.
You should put your API routes in your web/api.php file that way they will be automatically prefixed with the 'api' route.
The route that is returning JSON data is not the one you pointed out, it is the next one:
Route::get('/record/{id}', 'MyController#getRecord'); // this is the one that don't work on refresh
This is because your Vue router is pointing to the exact same route:
{
path: "/record/:id",
name: "View Record",
component: require ('./components/AddPerson').default,
meta: { requiresAuth: true }
}
Both routes point to yourwebsite.com/record/{id}, but on refresh you make a brand new request to your Laravel application, that means your not in your Vue application anymore and your browser will load whatever Laravel will tell them first, in this case it will be the first route in the routes/web.php file:
Route::get('/record/{id}', 'MyController#getRecord');
Edit: This is how you should do it if you cannot use API routes due to authentication:
You must make sure that your don't have duplicate routes between your Vue router and your Laravel routes, you can just prefix them with something that makes sense to you.
Route::prefix('prefix')->group(function () {
Route::get('/persons', 'MyController#index');
Route::post('/record/{personId?}', 'MyController#create');
Route::get('/record/{id}', 'MyController#getRecord');
Route::delete('/record/{id}', 'MyController#destroy');
Route::get('/lookups', 'LkpController#index');
Route::post('/validate', 'MyController#getValidation');
});
//Routes for VueJs
Route::get('/{any}', function () {
return view('welcome');
})->where('any','^(?!api).*$')->name('home');
In this example, the route you are having trouble with will now be prefixed with 'prefix' yourwebsite.com/prefix/record/{id}, you can change it to whatever you need it to be.

Laravel middleware on a VueJS route

I have a VueJS route in my SPA application. I would like to apply a Laravel Middleware to a route (the auth middleware, in this case).
Actually, I have try this:
app.js
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: require('./views/Home').default,
},
{
path: '/hello',
name: 'hello',
component: require('./views/Hello').default,
},
],
});
routes/web.php
Route::get('/hello', 'HomeController#home')->middleware('auth');
Route::get('/{any}', 'FrontendController#index')->where('any', '.*');
In this code, I have try to link the auth middleware to the route /hello, but it don't work. What is the best way to do that ?
Thanks.
I have not worked with Laravel for about 6 years, but with Vue. I believe that this is because you never get into your Laravel route, since the Vue app is assembled, and it is therefore fully available in the browser.
It would be different if you loaded the component in the Vue router via lazy load.
component: () => import(/* webpackChunkName: "hello" */ './views/helo.vue')
I don't know exactly how that works with Laravel. I use the Vue CLI tool. Hope this could help you a little.

Skip login screen while opening a vue route link

I am using laravel and vue js in my app. All the vue routes ask for a login when opened as i am using laravel auth. I want to create some routes that should be accessable without a user to be logged in. In other words I want some route that can be accessed by guest user as well. But at the moment all routes require user to be authenticated. These are my routes
const routes = [
{ path: '/dashboard_admin', component: require('./components/dashboard.vue').default},
{ path: '/ongoing_events_admin', component: require('./components/events.vue').default } ,
{ path: '/courses_admin', component: require('./components/courses.vue').default},
{ path: '/front_images_admin', component: require('./components/front_images.vue').default},
{ path: '/news_admin', component: require('./components/news.vue').default},
{ path: '/main', component: require('./components/main_view/index_view_general.vue') ,
name: 'index',
props: true ,
beforeEnter:DontrequireLogin
},
//general vue
// { path: '/', component: require('./components/main_view/index_view_general.vue').default},
]
const router = new VueRouter({
mode: 'history',
routes // short for `routes: routes`
})
const app = new Vue({
el: '#app',
router
});
These are my routes. I want some of these routes that can be accessed by guest user as well but at the moment all routes require user to be logged in.
So you need to do this meta's, for more about this you can read from its official documentation Route Meta
Let me explain litle bit what meta's do .
in meta you define a bolean object which indicate , this route is for authenticated or users or for guest user. let see below example.
i have authenticated route, only for authenticated users.
{path: '/account-setting',component:accountSetting,meta:{auth:true}},
so i pass auth object in meta and decide in route.beforeach what to do with this route.
so same a normal route
{path: '/about',component:about}
in this i give no meta, which means its for all user.
read the documentation to know how to use it.

Resources