How to create a 'url_for' link helper in AngularjJS
Asked Answered
M

4

12

In .NET MVC there is @Url.Action() and in RoR there is url_for()

I could not find similar url building helper in angularjs.

I'm already providing everything that is needed to build url to $routeProvider so something like: $routeProvider.urlFor("MyCtrl", {id: 5}) could be nice to have.

My main goal here is to avoid hardcoded urls in viewes and other places and to avoid repeating url/routes patterns twice.

UPDATE:

Seems like it's hard to explain what i want so here is exact example of what i want:

Instead of writing this in viewes:

<a ng-href="/product/5">foo</a>

I want to write this:

<a ng-href="urlFor("ProductCtrl", {id:5})">foo</a>

So if later i decide to change path of ProductCtrl I would not have to update url in this a element.

What would be good solution for my goals?

Milldam answered 10/3, 2013 at 15:41 Comment(0)
M
15

You could try with something like the following (just came up with it) inside your main module's run() block:

app.run(function($route, $rootScope)
{
  $rootScope.path = function(controller, params)
  {
    // Iterate over all available routes

    for(var path in $route.routes)
    {
      var pathController = $route.routes[path].controller;

      if(pathController == controller) // Route found
      {
        var result = path;

        // Construct the path with given parameters in it

        for(var param in params)
        {
          result = result.replace(':' + param, params[param]);
        }

        return result;
      }
    }

    // No such controller in route definitions

    return undefined;
  };
});

This will extend the root scope of the application with the new path() function - so it can be used anywhere in the application. It uses the $route service to get the controller names and the corresponding paths, so you won't have to repeat yourself.

Example usage:

{{ path('LibraryController', { bookId : 'x', chapterId : 'y' }) }}

Live example at: http://plnkr.co/edit/54DfhPK2ZDr9keCZFPhk?p=preview

Mathematics answered 17/3, 2013 at 15:52 Comment(2)
This solution struggled when multiple routes used the same controller. I updated it to find the first route where the passed params satisfy the required params, and then I changed the order of my routes to make sure the most specific routes were defined first. Also updated to Angular 1.2.21. Thanks for the solid starting point @mirrormx! Code here: plnkr.co/edit/05ilcKRf3Zcm1XXYhz9i?p=previewSancha
Yes! now how do we push this to the next version of angular?Mandal
F
2

There are numerous approaches...a custom directive or ng-click to modify $location, or using a function in ng-href to parse the url from object and have it placed as href in an <a> tag.

Example using ng-href:

HTML:

<li ng-repeat="item in items">
    <a ng-href="{{url(item)}}">{{item.txt}}</a>
</li>

JS:

function Ctrl($scope){
  $scope.items=[
    {id:1,txt:'foo'},
    {id:2,txt:'bar'}
 ];

  $scope.url=function(item){
    return '#/'+item.id
  }
}

Example using ng-click and $location

HTML:

<a ng-click="newPath(item)">{{item.txt}}</a>

JS:

function Ctrl($scope){
  $scope.items=[
    {id:1,txt:'foo'},
    {id:2,txt:'bar'}
 ];  

  $scope.newPath=function(item){
   $location.path('/'+item.id)
  }  
}

DEMO: http://jsbin.com/ovemaq/3

Fishmonger answered 10/3, 2013 at 17:9 Comment(4)
My main goal is to avoid hardcoded urls in viewes and other places and to avoid repeating url/routes patterns twice. you example repeats route pattern that was already written/configured in $routeMilldam
not clear what your question is then. Provide a demo that outlines issue more clearly, or a better explanation. $routeprovider will manage changes to url, but highly likely view will have to make the actual changes based on user interactionFishmonger
In .NET MVC there is @Url.Action() and in RoR there is url_for(). I want same functionality in angular. It is helper method that would use your routes configuration to give you links to your controllers.Milldam
ok..so question is about automatically defining controller within $routeProvider? You can use variables in path in $routeProvider if that helps. Need to create a demo that shows where your problem liesFishmonger
C
1

In one of recent project I came up to this solution it helped me to solve my needs right in time. It will be interesting to help you to improve it to fit your usecase.

1. Move routes definition to config:

...
ROUTES: {
    PAGE1: '/page1/:id',
    PAGE2: '/page2/:id/:name'
},
...

2. Define routes, using values from config:

app.config(['$routeProvider', 'config', function ($routeProvider, config) {
    $routeProvider.when('/', {
        templateUrl: 'partials/home.html',
        controller: 'HomeCtrl'
    });

    $routeProvider.when(config.ROUTES.PAGE1, {
        templateUrl: 'partials/page1.html',
        controller: 'PageOneCtrl'
    });

    ...

    $routeProvider.otherwise({
        redirectTo: '/'
    });

}]);

3. Set up service to provide functionality to create urls:

services.factory('routes', function (config) {

    // populates `:param` placeholder in string with hash value
    var parseString = function (string, parameters) {
        if (!string) return '';
        if (!parameters) return string;

        for (var index in parameters) {
            if (!parameters.hasOwnProperty(index)) continue;

            string = string.replace(':' + index, parameters[index]);
        }

        return string;
    };

    return {
        getPage1Link: function (urlParams) {
            return '#' + parseString(config.ROUTES.PAGE1, urlParams);
        }
    };
});

== Drawbacks ==

With this approach I had to define getter for each route (there were less then 5, and development speed was vital)

Countercharge answered 18/3, 2013 at 20:32 Comment(0)
T
0

It appears that what you want is the ui-route directive which has just been recently added to the angularui project. There is a nice set of out-of-the-box options.

Thaumatology answered 15/3, 2013 at 5:5 Comment(1)
ui-route looks interesting, but looking at examples i don't think it is what i want. It looks like i have hard time trying to explain what functionality i'm after, i will update question with more info.Milldam

© 2022 - 2024 — McMap. All rights reserved.