Search code examples
phpangularjslaravel.htaccess

Laravel + AngularJS passing routes on to angular


I'm trying to code an app with a RESTful API in Laravel and a rich client in angular. This works out great by the way. Laravel does the initial route and kicks off the Angular client, which then finds it needs authentication and redirects to /login. From here on, it's pure client-side communicating with backend async via REST. Beautiful if you ask me. However; If the user at some point wants to refresh the browser, or send the URL as a link to someone - it breaks. BAD!

Refresh on /signup/ for instance, would result in Laravel first picking up the ball and redirecting to the default route via

start/global.php

App::error(function(NotFoundHttpException $exception, $code) {
    $allowed = array("api","css","fonts","html","img","js");
    if(0 == count(array_intersect(array_map('strtolower', explode(' ', Request::path())), $allowed))) {
        return Redirect::route('home');
    }
});

Which caused me to lose where the user was originally trying to reach. Once angular gets control, the original route is lost and it can do nothing but present /login again. I'm guessing I can lose the error handler if I do some magic in .htaccess, which for the time being is being held by the standard HTML5 boilerplate .htaccess +

<IfModule mod_rewrite.c>
    Options +FollowSymlinks
    Options -MultiViews
  # Options +SymLinksIfOwnerMatch
    IndexIgnore */*

    RewriteEngine On
    RewriteBase /

    # If a directory or a file exists, use it directly
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]

    # Otherwise forward it to index.php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>

.htaccess and Apache configuration is a big black hole for me. I do not find it intuitive at all.

For single-page apps running on Laravel, how can I ensure the user gets to the correct angular view when the user refreshes or starts on a URL directly?


Solution

  • If I understood your issue correctly, this is how I do it:

    I group all Laravel's RESTful API routes under an /api/ directory as follows:

    Route::group(array('prefix' => 'api'), function()
    {
        Route::resource('users', 'UsersController');
        Route::resource('products', 'ProductController');
        ...
    }
    

    This directory could, of course, be called anything. But importantly, it means that you can separate Angular routes from Laravel's API routes, as long as the user doesn't try and directly access the /api/ directory.

    This then frees up all other routes to be handled by Angular. This is how the rest of my Laravel routes.php file looks:

    // index route
    Route::get('/', function()
    {
        return View::make('index'); // redirect to AngularJS
    });
    
    // catch-all -- all routes that are not index or api will be redirected
    App::missing(function()
    {
        return View::make('index'); // should also redirect to AngularJS
    }
    

    That last function is important. Taking your use case as an example, if a user was to refresh on /signup/ then Laravel would simply pass the route onto Angular (the index page), which would in turn detect a match amongst its routes and send the user to the intended page. If the user was to try and navigate to a non-existent page, for example /nothingtoseehere/, exactly the same would occur - they would just be sent to the index page. From here you could handle the error with Angular.

    Hope that's of some use.