5

I am building a blog with angular and am currently working on the routes. I have the routes working with routeParams but angular gives it a random number and the url ends like http://localhost/kensproblems/#/posts/2

I want it to either automatically grab the title and use it as the parameter on the URL or use the property called id on the json file such as http://localhost/kensproblems/#/posts/title-of-post

Is this possible with $routeParams?

app.js

angular.module('app', [
    'ngRoute',
    'app.controllers',
    'ui.router',
    'ngSanitize'
])

.config(['$routeProvider', '$urlRouterProvider', function($routeProvider, $urlRouterProvider){
    $routeProvider
    .when('/posts', {
        templateUrl: 'views/posts.html',
        controller: 'PostListController'
    })
    .when('/posts/:id', {
        templateUrl: 'views/singlepost.html',
        controller: 'PostDetailController'
    })
        .otherwise({
        redirectTo: '/'
    });
}]);

controllers.js

angular.module('app.controllers', ['app.directives'])
    /* Controls the Blog */
    .controller('PostListController', ['$scope', '$http', function($scope, $http){
        $http.get('data/posts.json').success(function(response){
            $scope.posts = response;
        });
    }])

    .controller('PostDetailController', ['$scope', '$http', '$routeParams', '$sce', function($scope, $http, $routeParams, $sce){
        $http.get('data/posts.json').success(function(response){
            $scope.post = response[$routeParams.id];
            console.log($routeParams.id);
            console.log($scope.post.id);
        });
    }])

posts.html

<div class="container" id="postList">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <div ng-repeat="post in posts | orderBy:post.date" class="post">
                <h2 class="blog-title"><a href="#/posts/{{posts.indexOf(post)}}">{{post.title}}</a></h2>
                <span class="date">Posted on {{post.date | date:'MMM dd, yyyy'}}</span>
                <div class="row top10">
                    <div class="col-md-8">
                        <div class="post-content">{{post.headline}}</div>
                        <a class="read-more" href="#/posts/{{posts.indexOf(post)}}">Read more</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

singlepost.html

<div class="container" id="singlePost">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <h1>{{post.id}}</h1>
            <h1>{{post.title}}</h1>
            <span class="date">Posted on {{post.date | date:'MMM dd, yyyy'}}</span>

            <h3>{{post.headline}}</h3>
            <div class="postContent" ng-bind-html="post.content"></div>
        </div>
    </div>
</div>
Lucio
  • 4,753
  • 3
  • 48
  • 77
Ken Ryan
  • 539
  • 1
  • 10
  • 31

2 Answers2

3

You will need to change two main things, first how the URLs are generated, and second how the post is recovered.

Generate URL from title

Not any title will be valid as URL, so you need to use slugs.

In the view:

<a class="read-more" href="#/posts/{{getSlug(post.title)}}">Read more</a>

In the controller:

$scope.getSlug = function(text){
  return text.replace(/\W+/g, '-');
};

Search post from slug

Currently, you are just fetching the post from the array as an index, which is conceptually wrong (you will notice this after remove one post). Instead, make a search through the array. This will be really simple if you use lodash.

Something like this would work:

$scope.post = _.find(response, function(post) {
  return post.title.replace(/\W+/g, '-') === $routeParams.id;
});
Community
  • 1
  • 1
Lucio
  • 4,753
  • 3
  • 48
  • 77
  • Thank you Lucio! I followed exactly as you said and it worked :) Thank you so much! I like this lodash library – Ken Ryan Oct 08 '15 at 16:41
0

Stack Overflow won't let me comment yet so I'll post here. I looks like your passing the index of the post in the array instead of one of the properties. Look at changing:

href="#/posts/{{posts.indexOf(post)}}"

To something like:

ng-href="#/posts/{{post.title}}"
Tyler Jennings
  • 8,761
  • 2
  • 44
  • 39
  • When I do that, the original content of that specific post isn't passed to the singlepost.html view. The body, content, etc isn't there. Does the config file with the routeProvider need to change? – Ken Ryan Oct 08 '15 at 00:13
  • I don't think so. In your Controller you would use the $routeParams.id (which presumably if you passing post.title) use the title to then pull the details of the post with an http request. I'd also recommend moving your http requests to services instead of your controllers. Here is an excellent Angular styleguide: https://github.com/johnpapa/angular-styleguide – Tyler Jennings Oct 08 '15 at 00:21