Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
646 views
in Technique[技术] by (71.8m points)

angularjs - How to implement path aliases in ui-router

I'm trying to find a way to implement route aliases in Angular.js using ui-router.

Let's say I have a state with the url article/:articleId and I want to have /articles/some-article-title redirected (internally) to /article/76554 without changing the browser location.

Could this be done with ui-router?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I. Doubled state mapping (reuse of controller, views)

NOTE: This is original answer, showing how to solve the issue with two states. Below is another approach, reacting on the comment by Geert

There is a plunker with working example. Say we have this two objects (on a server)

var articles = [
  {ID: 1, Title : 'The cool one', Content : 'The content of the cool one',},
  {ID: 2, Title : 'The poor one', Content : 'The content of the poor one',},
];

And we would like to use URL as

// by ID
../article/1
../article/2

// by Title
../article/The-cool-one
../article/The-poor-one

Then we can create this state definitions:

// the detail state with ID
.state('articles.detail', {
    url: "/{ID:[0-9]{1,8}}",
    templateUrl: 'article.tpl.html',
    resolve : {
      item : function(ArticleSvc, $stateParams) {

        return ArticleSvc.getById($stateParams.ID);
      },
    },
    controller:['$scope','$state','item',
      function ( $scope , $state , item){ 

        $scope.article = item;
    }],
  })

// the title state, expecting the Title to be passed
.state('articles.title', {
    url: "/{Title:[0-9a-zA-Z-]*}",
    templateUrl: 'article.tpl.html',
    resolve : {
      item : function(ArticleSvc, $stateParams) {

        return ArticleSvc.getByTitle($stateParams.Title);
      },
    },
    controller:['$scope','$state','item',
      function ( $scope , $state , item){ 

        $scope.article = item;
    }],
  })

As we can see, the trick is that the Controller and the Template (templateUrl) are the same. We just ask the Service ArticleSvc to getById() or getByTitle(). Once resolved, we can work with the returned item...

The plunker with more details is here

II. Aliasing, based on native UI-Router functionality

Note: This extension reacts on Geert appropriate comment

So, there is a UI-Router built-in/native way for route aliasing. It is called

$urlRouterProvider - .when()

I created working plunker here. Firstly, we will need only one state defintion, but without any restrictions on ID.

.state('articles.detail', {
    //url: "/{ID:[0-9]{1,8}}",
    url: "/{ID}",

We also have to implement some mapper, converting title to id (the alias mapper). That would be new Article service method:

var getIdByTitle = function(title){
   // some how get the ID for a Title
   ...
}

And now the power of $urlRouterProvider.when()

 $urlRouterProvider.when(/article/[a-zA-Z-]+/,
  function($match, $state, ArticleSvc) {

    // get the Title 
    var title = $match.input.split('article/')[1];
    // get some promise resolving that title
    // converting it into ID
    var promiseId = ArticleSvc.getIdByTitle(title);

    promiseId.then(function(id){

      // once ID is recieved... we can go to the detail
      $state.go('articles.detail', { ID: id}, {location: false}); 
    })

    // essential part! this will instruct UI-Router, 
    // that we did it... no need to resolve state anymore
    return true;
  }
);

That's it. This simple implementation skips error, wrong title... handling. But that is expected to be implemented anyhow... Check it here in action


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...