2

I'm trying to load routes into my angularJS app by running an ajax call and setting up routes on my RouteProvidor. The following is my code to do so.

var app = angular.module('app', ['ngRoute']);
var appRouteProvider;

app.config(['$routeProvider', '$locationProvider', 
                      function($routeProvider, $locationProvider) {
  $locationProvider.html5Mode({  
    enabled: true,
    requireBase: false
  });
  appRouteProvider = $routeProvider;

  appRouteProvider.when('/', {
    templateUrl : '../../app/templates/home.html',
    controller  : 'IndexController'
  });

}]).run(function($http, $route){

  url = siteApiRoot+'api/routes';

  $http.post(url, jQuery.param([]), {
      method: "POST",
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    }
  ).success(function(data){

    for(i in data){
        appRouteProvider.when(data[i].route, {
            templateUrl : data[i].template,
            controller  : data[i].controller
        });
    }

    console.log($route.routes);

  });
});

The console.log outputs a correct set of routes to the console which seems to indicate that the routes have been correctly assigned. But if I were to open any url that should be handled by the route. Nothing happens. The basic assets load i.e. navigation bar and footer which are constant throughout but the controller for the route is never called. What am I missing here guys.

-- UPDATE

Tehcnically I have routes that follow the following patterns:

List of entries:

/<city>/<category>
/<city>/<subdistrict>-<category>
/<city>/<entry-slug>

I'm not sure how well to define the above - basically the first two routes would invoke one controller and one view while the third woudl invoke another. However I'm stuck with how to define this kind of routing in AngularJS provided that etc are all slugs in a database. Pretty much left with hardcoding an array of routes but that also doesn't work as it seems.

Plus I also have other pages that are static - eg /about /site/contact - a bit lost on routing here.

Ali
  • 7,353
  • 20
  • 103
  • 161
  • Your problem is that Angular has already loaded all the routes before. You have to reload the routeService probably, but why do you even have to get your routes by ajax? That sounds like bad design to me. – Xatenev Sep 28 '16 at 11:18

2 Answers2

1

You can't change the router configuration after initialisation, but you can use a parameterized route to handle everything.

You can fetch the routing data in an external service, and find the appropiate entry for the current parameters with whatever lookup logic you need. I assume the point of this is to have different templates and controllers for these routes.

The template you can solve with a simple ng-include, but you'll have to manually instantiate the controller. Look into $injector instead of the $controller call here for more details on this one, as you'll probably need full dependency injection for them. The RouteController here just passes its own scope to the created controller (which at this point really is just like any generic service), which is already attached to the container.html by the router. Note that the ng-include creates a child scope, so you have to be careful if you want to assign new variables on the scope in templates.

(If this is a problem, you can manually fetch, build and attach the template too: take a look into $templateRequest, $templateCache and $compile services. (You will have to create a directive to attach it to the DOM))

Here is the barebones sample code:

var app = angular.module('app', ['ngRoute']);

app.service("getRouteConfig", function($http) { 

  var routeRequest = $http.post(url, jQuery.param([]), {
      method: "POST",
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    }

  return function(params) {
    return routeRequest.then(function(routes) {
      // find route entry in backend data for current city, category/slug
      return routes[params.city][params.slug];
    });
  }
})

app.controller("RouteController", function(route, $scope, $controller) { 
  $controller(route.controller, {$scope: $scope});

})

app.config(function($routeProvider) {

  $routeProvider.when('/', {
    templateUrl : '../../app/templates/home.html',
    controller  : 'IndexController'
  });
  $routeProvider.when('/:city/:url', {
    templateUrl : '../../app/templates/container.html',
    controller  : 'RouteController',
    resolve: {
      route: function(getRouteConfig, $routeParams) {
        return getRouteConfig($routeParams);
    }
   }
  });

});

container.html:

<ng-include src='$resolve.route.template'>
yscik
  • 879
  • 4
  • 7
  • I think I'm getting the gist here - technically I have a set of routes, like if you've seen the kind of routes I have. I just need to know how to decide which controller to use against which route because the routes are quite similar and can only be detected via some basic logic i.e. if /:param is an element in an array use X controller else use Y controller. Where would I put the logic for that? – Ali Oct 02 '16 at 11:16
  • 1
    Right at the comment in `getRouteConfig` service, where you get the `routes` collection from the backend and the `params` from the url pattern. (In this case the `/:city/:slug` pattern would yield a `params.city` and `params.slug` you can use for selecting the route to use) – yscik Oct 02 '16 at 19:58
  • I get it - just one thing where I'm stuck btw - the value for the routes object. What should be returned in routes[params.city][params.slug];. I've modified my code so I don't have to make an http call and instead just compare the value of the parameters against an array retrieved via a service... – Ali Oct 05 '16 at 12:59
  • I think I'll settle with not relying on an api for routes entirely - its bad design however my routes do require reliance on data that is retrieved from an api. I'll fire up another question here - thanks for the help :) – Ali Oct 05 '16 at 13:56
  • The `routes[params.city][params.slug]` was just an example for the logic used to find the matching route, returning a similar config object you had in the `data`, with the `controller` and `template` properties. But yeah, if you can find a simpler approach, definitely go with that :) – yscik Oct 05 '16 at 14:45
0

Angular config functions are for setting up configuration, which is used for initialising services. This means that trying to alter the config from the run() function will result in nothing happening, as the config has already been utilised.

One possible option is to provide the config from the server inside the actual js file sent to the client. Otherwise there is no easy way to alter config using $http.

There is more discussion here: use $http inside custom provider in app config, angular.js

Community
  • 1
  • 1
Matt Way
  • 32,319
  • 10
  • 79
  • 85