reactJS , accessing URL with daynamic segments says 'page not found' - php

The issue is pretty obvious. I have declared a route with 2 dynamic parts in my react.js app with the following line :
<Route path='/products/:cat_id/:subcat_id' component={ProductsWise} />
But when I try to access the url: http://127.0.0.1:8000/products/4/1 , it simply says :
404 Not Found. The code follows :
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import ProductsWise from './ProductsWise'
class App extends Component {
render () {
return (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path='/products/:cat_id/:subcat_id' component={ProductsWise} />
</Switch>
</div>
</BrowserRouter>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
I am not putting the content inside ProductsWise.js here as I think that is not necessary to solve the problem.
How to get rid of the problem ?
P.S: I am actually building an app with PHP Laravel framework in server side and react.js in client side.

The problem is that the SPA is not rendered for the products/4/1 path from the backend perspective.
I believe Route::view('/{path?}', 'app') is not relevant.
As far as there is no information about wildcard routing in the official Laravel routing documentation - you can render your SPA for / and for /products/{catId}/{subcatId} paths separately:
Route::view('/', 'app');
Route::view('/products/{catId}/{subcatId}', 'app');

Related

Laravel Inertia rendering data from backend to frontend

Totally new to using reactJS with laravel inertia.
I am trying to render the data from my database to the front end. I use a controller to get the data from the database by using...
// Show all main categories
public static function index() {
return MainCategory::all(['main_category_id', 'main_category_name']);
}
then passing it to the frontend using the web.php by using the following code.
Route::get('/', function () {
return Inertia::render('Admin/Categories', [
'categories' => MainCategoryController::index()
]);
})->name('admin.category-setup');
I currently do not know how to call categories in the front end using reactjs.
How can I do that?
I sometimes approach the accessing of passed props by using Inertia's inbuilt usePage-Hook for React. This comes in handy when you are working with shared data that you have made accessible for all of the frontend components (https://inertiajs.com/shared-data). As long as your Backend (Laravel) Code works properly and the actual categories-Property is handed over to the Categories-Component or shared for all of the frontend, you could do something like this:
import React from 'react';
import { usePage } from '#inertiajs/inertia-react';
function App() {
const categories = usePage().props.categories;
return (
<ul>
{categories.map((category) =>
(<li>{category}</li>))}
</ul>
);
}
The most common practice for me however is to simply give the same variable names that you pass in Laravel into the Inertia-Component into the React-Component-Props like this. To me it looks like that should perfectly work with your Use-Case:
import React from 'react';
function App({categories}) {
return (
<ul>
{categories.map((category) =>
(<li>{category}</li>))}
</ul>
);
}
If you want to find more about Inertia, I highly recommend to go through the docs. The developers did a great job in explaining everything so that an unexperienced Laravel and React Dev could understand what is going on. It is actually not much to read but shows some interesting features:
https://inertiajs.com/

Is it possible for certain routes to use vue router while other routes use laravel router?

What I have is an existing laravel application with blades , laravel routes and a few vue components. So I don't want to replace the existing routes with vue router. What I want is to add additional routes without disturbing the existing laravel routes.
For an example I have a category which already is using the following category
Route::get('category/index' , 'CategoryController#index')->name('category.index');
Then I would like to add a new route using vue router without disturbing the category route
For an example:
import Dashboard from "../views/Dashboard.vue";
const routes = [
{
path: "/",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true
}
}
]
Is this possible?
Update: This is what I did (If anyone can point out what am I doing wrong, it would be greatly appreciated)
1.0 Install Vue Router using npm
2.0 App.js (Use Vue Router)
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const routes = [
{ path: '/dashboard', component: require('./components/Dashboard')},
];
const router = new VueRouter({
routes, // short for `routes: routes`
mode: 'history',
});
3.0 Web.php
Route::get('/{vue_capture?}', function () {
return view('testing.main');
})->where('vue_capture', '^(?!storage).*$');
4.0 main.blade.php(in testing folder)
#extends('layouts.app')
#section('content')
<div class="container" id="app">
<router-view></router-view>
</div>
#endsection
5.0 It doesn't work
Thank you.
Yes I believe this should be possible.
You will need to add a Laravel route that captures all the vue routes and shows a view which includes the vue routes.
Route::get('/vue/{vue_capture?}', function () {
return view('vue.index');
})->where('vue_capture', '[\/\w\.-]*');
You should be able to include both this route and the original Laravel ones. One option would be to prefix the view routes as shown above with /vue, alternatively if you put the routes in the correct order you should be able to avoid the prefix, if you so wish.
The php artisan route:list command will help you, by allowing you to see what the current routes are.
Yes you can and simple.
All you need is to put the existing route at the top over the route that handles for vue app.
it should look like this.
web.php
// existing route
Route::get('category/index' , 'CategoryController#index')->name('category.index');
// handle vue app
Route::get('{path}', 'VueController')->where('path', '(.*)');
VueController
public function __invoke()
{
reuturn view('index');
}
for working example you can read this section to work with vue-router vue-router

How can I Integrate Vue into a legacy PHP app and gain access to specific Vue components

I have a server-side-rendered legacy PHP 5.6 web app that I want to modernise using VueJS
Within the project structure I have set up a new Vue project and set up Vue Router and Webpack with an entry point of main.js
Main.js
Vue.config.productionTip = false
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import router from './router/router'
new Vue({
render: h => h(App),
router
}).$mount('#app')
I am currently inserting VueJS into the legacy app by inserting this code at the bottom of a php file:
<div id="app">
</div>
<script src="http://localhost:8080/js/main.js"></script>
The url of this page is https://www.example.com/user_portal/employee_holiday_info.php#/
However Vue Router recognises it as / because it is the point of entry.
At the moment I have to insert the above code on every PHP file that I want to use VueJS on. Is there a better way of doing this?
If I insert the above code at the bottom of say, index.php then Vue Router would also recognise that page as /. In which case both urls:
https://www.example.com/user_portal/employee_holiday_info.php#/
https://www.example.com/user_portal/index.phpwould render the same Vue component, HelloWorld.
Vue Router
import HelloWorld from "../components/HelloWorld";
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'hello-world',
component: HelloWorld,
}
]
});
export default router;
How can I set this up so I can on multiple Vue components throughout a single php file and share data between them using Vuex.

Laravel routes with multiple slugs won't work in React

I have an application with a Laravel back-end/React.js front-end. I am using react router so to make that work I have any path pointing to the Controller which loads the view with the components in them. However when I add nested routes in the react side i.e. "blog/:blogId", it seems that it completely skips the tag in which components are loaded into and shows me content from the Laravel view instead.
I originally had:
`Route::get('/{slug?}', 'ProjectsController#index'`
I've tried:
`Route::any('{path}', function($path){
$projects = Project::all();
$posts = Post::all();
return view('welcome', compact('projects', 'posts'));
})->where('path', '.*');`
This won't work either:
`Route::get('/{slug?}/{id?}', 'ProjectsController#index'`
What I want is for both /blog and /blog/2 to go to ProjectsController#index which loads the view with the react tag.
The data in my index function in ProjectsController is:
`$projects = Project::all();
$posts = Post::all();
//return $projects;
return view('welcome', compact('projects', 'posts'));`
Has anyone come across this before? Thanks.
UPDATED:
The welcome view being returned by the controller index method:
The <div id="content"></div> is where my base component is being loaded into. So when navigating to route '/blog' I see my component, when navigating to '/blog/anything' I see Laravel's login and register links.
`#extends('layout')
#section('content')
#if (Route::has('login'))
<div class="top-right links">
#if (Auth::check())
Home
#else
Login
Register
#endif
</div>
#endif
<div id="content"></div>
#include('partials._scripts')
#endsection`
The component making use of the link:
`View here
<Route path="/blog/:blogId" component={Post} />`
My other routes in the base component:
`<Switch>
<Route exact path="/" render={(props)=> <Home text={text} mobileNavIsOpen={hamburgerOpen} backgroundImage={background}/>} />
<Route path="/projects" component={Projects} />
<Route path="/blog" component={Blog} />
<Route component={NotFound} />
</Switch>`
I've tried placing the /blog/:blogId route in the base app along with the others - still no difference.
UPDATE:
When removing the /blog/ route tag from react router and just keeping '/blog/:blogId, it has the same effect.
UPDATE/PARTLY SOLVED:
Adding (\\d+) to my react router path: path={/blog/:id(\\d+)} rightly took me to the nested component. It did also load the blade view content, however, so as a temporary fix I have taken out the blade content that was displayed. Would be good to see if anyone has another way around it. Thanks.
Try this
Route::get('/{any}', 'ProjectController#index')->where('any', '.*');
This is basically added to the end of the routes/web.php, since most probably you are trying to build a SPA and you want all http requests to be handled by react router.
Update:
Based on your updates I understand that you want both /blog and /blog/:ID to be handled by the same method. That can be done like this
Route::get('blog/{id?}', 'ProjectController#index')->where('id', '[0-9]+');
If you need the ID in the index method give it as the first argument to the method and send it to the view.

How to configure symfony to work with Vue.js in HTML5 History mode

I have followed the tutorial on how to integrate Vue into Symfony (3.3), and it's working just fine.
I'd like to however use vue-router in HTML5 History mode, so with "real" urls instead of hashes. The problem is while that works well when initially loading the index page, that it won't work to open a page with a Vue URL that symfony doesn't know, cause symfony will throw a 404 error and not load the index view with the Vue app.
I'd like to only use symfony for specific route prefixes, like /blog, /api, and for all other routes load the index route that does nothing but load the vue app, but I don't really know where to start.
I assume I either have to change the .htaccess (currently using the exact one that came with the symfony installation) or somehow "catch" routes symfony doesn't know and redirect to the index page - however I'm stuck here since I'd want routes that are not found within the range of the few route prefixes I want symfony to use to still throw a 404 error.
For those who prefer using annotations [Symfony 3.x, 4.x]
You could use the following Routing in Symfony.
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
* #Route("/{route}", name="vue_pages", requirements={"route"=".+"})
*/
public function indexAction(Request $request)
{
return $this->render('default/index.html.twig', []);
}
}
And In VueJS, you can Vue-Router to display a 404 page for routes not found via a wildcard as shown below,
import '...'; // import required components
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'homepage',
component: home
},
{
path: '/hello',
name: 'hello',
component: hello
},
{
path: '*', // wildcard
name: 'notfound',
component: notfound
}
]
});
You could check this Reference tutorial and the source code for a step-by-step setup.
Tested with Symfony 3.x, 4.x, VueJS 2.5.x, VueRouter 3.x
Had the Same issue. Symfony is simultaneously delivering a Vue driven frontend and implementing an Rest-API. I solved it using some sort of PageNotFound-Fallback, so basically every route that was not found by the Symfony Router will be forwarded/redirected to the Frontend. So the FrontendController looks like this:
class FrontendController extends Controller{
public function indexAction(Request $request)
{
$base=$request->getBaseUrl();
return $this->render('default/index.html.twig',['basePath'=>$base]);
}
public function pageNotFoundAction()
{
return $this->forward('AppBundle:Frontend:index');
}
}
With an additional configuration in the routing.yml (see: Redirect with Event Listener for all "No route found 404 Not Found - NotFoundHttpException")
pageNotFound:
path: /{path}
defaults: { _controller: AppBundle:Frontend:pageNotFound, path: '' }
requirements:
path: .*
Finally, the VueRouter needs to be configured, so it keeps the correct environment, simply by adding the base Property in the Router constructor. If the frontend component is not displayed correctly, you can use router.push('some-route') to manually adjust it.
Keep in mind that there will be no more 404 Errors, since they are all forwarded to the frontend, which can lead to bad scenarios using ajax on page load...
Altough it feels like a hack, I hope this helps. Open for better solutions.
EDIT Symfony version 3.4.3, Vue version 2.5.1

Categories