2

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?

2
  • you might need to do some js manipulation there. Commented Feb 22, 2014 at 23:15
  • Javascript? That doesn't sound right. I want the server side to respond to ANY URL the user types in with the angular client. And by this, I thought I needed to make apache think that any url should be index.php, make laravel think that any url should be the client, and NOT redirect (which rewrites the url in a destructive manor(?)), but forward the entire url to the client. Do you know of a way to get the original url once redirected via javascript? Commented Feb 23, 2014 at 7:14

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

Fixed! :-)

Since I generally want to just forward requests to angular when no route is found on server, I just invoke the applications ONLY view creating controller.

start/global.php

App::error(function(NotFoundHttpException $exception, $code) {
    $allowed = array("api","css","fonts","html","img","js","scripts");
    if(0 == count(array_intersect(array_map('strtolower', explode(' ', Request::path())), $allowed))) {
        // Only return the view response if the request does not specifically ask for a json response.
        if (!Request::wantsJson()) {
            // Instead of performing a redirect here, pretend everything is 
            // normal and act as if the 'home' route has been called.
            $controller = new HomeController();
            return $controller->callAction('getHome', array());//Redirect::route('home');
        }
    }
});

Probably a dirty hack, but I will mark this as a solution if nobody comes up with anything better. :-)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.