1

I have an angularjs (version 5) app running in laravels public folder. angularjs should serve the ui aka frontend. whilst laravels "only" route is the backend api access to the data(base) serving the ui at /api/.... How do I marry both?

My angularjs app resides in /public/ui/ so I currently just have a route in laravel like so:

Route::get('/', function () {
    return Redirect::to('/ui/dist');
});

This works partially. It works from within the angularjs app like expected. But when I call anuglarjs routes they will fail to display because of course they don't exist in laravel. Going with the angularjs tutorial for example: If I call /ui/dist/heroes it will display a 404 instead of the angularjs app.

Note: Laravels public folder is symlinked to the webroot.

Edit: I redirect to /ui/dist as I use angulars builder to build its files and these are reflected in the index.html also generated with the builder. The index.html looks like this:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Ui</title>
    <base href="./">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
    <link href="styles.5cf98968a6d57e778c48.bundle.css" rel="stylesheet"/><!-- the hash changes on every build -->
</head>
<body>
<app-root></app-root>
<script type="text/javascript" src="inline.2379cc013d19d70a8003.bundle.js"></script> <!-- the hash changes on every build -->
<script type="text/javascript" src="polyfills.ad37cd45a71cb38eee76.bundle.js"></script> <!-- the hash changes on every build -->
<script type="text/javascript" src="main.99c0191843a51dda5d54.bundle.js"></script> <!-- the hash changes on every build -->
</body>
</html>
steros
  • 1,794
  • 2
  • 26
  • 60
  • why you are trying to use laravel urls in angular application? i think you need to define "/ui/dist/heroes" in angular config as a state. – Gaurav Srivastava Dec 04 '17 at 13:04
  • not according to the angular tutorial, I think it should work as such. but it won't work as laravels routing comes before angulars routing. I think I would just have to generate a wildcard route in laravel. – steros Dec 04 '17 at 13:15

2 Answers2

0

Here is how you can integrate laravel and angular routing.

In your routes.php, add this route:

Route::get('{slug}', function () {
    return view('index');
}); // this will ensure all routes will serve index.php file


Route::get('/', function () {
    return view('index');
});

In your index.php of laravel view, add all necessary angular js config and controller like normally you do with angular projects.

Note: for each $http request urls you have to define it in laravel route file.

Now when any url is hit, it will serve the index.php file and then angular routing will serve the correct file.

Gaurav Srivastava
  • 3,232
  • 3
  • 16
  • 36
  • Thanks for your answer. How do you handle angular building with this? Upon building file names change and you would have to adapt laravels view for it, wouldn't you? That's what I tried to prevent and thus redirected to the dist folder simply. – steros Dec 04 '17 at 13:26
  • what do you mean by file names change? in your index.php you will serve the angular state as you normally do, every file will be served(mapped with angular state) from laravel public folder. – Gaurav Srivastava Dec 04 '17 at 13:32
  • sorry I might not get you. my angular entry is the index.html generated by angular builder in the dist folder of the angular project. the index.html contains script tags to several angular js files. these file names change with every build but the index.html is changed. if I put those script tags into the laravel view I would have to change file names every time I build angular. and it wouldn't work with automated deployment. or maybe I'm not getting it right. – steros Dec 04 '17 at 13:38
  • can you share a bit of index.html file code ( what is changed every time after new build) ? – Gaurav Srivastava Dec 04 '17 at 13:41
  • sure, I edited my question. I saw several posts that redirect to a catchall route which will return a laravel view. but I think my problem is that I can't use a laravel view. but these posts are all about older angular versions. – steros Dec 04 '17 at 13:44
  • check this post: https://stackoverflow.com/questions/39718803/custom-generated-filename-with-angular-cli, i am not sure it will help you directly but there must be some way you can prevent the building tool to generate new file name everytime. – Gaurav Srivastava Dec 04 '17 at 13:47
  • sorry for the misunderstanding but I want different hashes all the time because of browser caching of course. but actually I have an idea now, maybe I can tell the angular builder to build .php files instead of .html? then I could use that as a laravel view. or alternatively I tell laravel to use a .html as a view not .php... – steros Dec 04 '17 at 13:52
  • I understand but I think hashing is used for production build not for development. you can use your browser console to prevent caching. – Gaurav Srivastava Dec 04 '17 at 13:54
  • yes I'm talking about production and build automation :) – steros Dec 04 '17 at 13:55
  • May be i am not getting you but you are supposed to change the file name for every production build so that your users don't get the old file. – Gaurav Srivastava Dec 04 '17 at 13:57
  • there is a file called `index.html` generated by the angularjs builder in the angular project folder called `dist` that contains script tags for all the necessary angularjs files which are also in the dist folder and get new hashes on every build. So I can't use those paths in a laravel view as they will change on every build, which they should. – steros Dec 04 '17 at 14:28
0

In order to make the routing systems of Angular (7+) and Laravel (5.8) coexist effectively is to redirect all the 404 errors that Laravel intercepts to the Angular router.

You have to edit the render function in app/Exceptions/Handler.php:

public function render($request, Exception $e)
{
    // handle Angular routes
    if ($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {

        $url = parse_url($request->url());

        $angular_url = $url['scheme'] . '://' . $url['host'] . '/#' . $url['path'];

        return response()->redirectTo($angular_url);
    }


    return parent::render($request, $e);
}

Now, let's say that you want to show a login form using angular navigating to /auth/login. When you hit that route Laravel will kick in, and not recognising the route will then pass the control to the Exception Handler. What we're doing in the render() function is simply tell Laravel to rewrite the URL and redirect to /#/auth/login.

Then, you have to enable to enable HashLocationStrategy in your Angular application, like so:

RouterModule.forRoot(routes, {useHash: true})
sentenza
  • 1,608
  • 3
  • 29
  • 51