9
votes

I am using AngularJS to create a page of articles with links for details for the individual articles. The links are based on the ID to ensure they are unique, but I would like the URLs to be the title with dashes (much more SEO/user friendly) rather than the ID. Here is the Angular Example where the product details are clean titles:

http://angular.github.io/angular-phonecat/step-11/app/#/phones

My current URLs are linked by ID so they appear as article/66D5069C-DC67-46FC-8A51-1F15A94216D4

I want them to display as the article title such as article/start-investing and ensure they are SEO friendly.

My concern is that if two articles by separate authors have the same title (ex. Learn about investing), that I will get errors if I try to link/lookup by title versus an ID that is unique per article.

Here are my controllers:

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

pfcControllers.controller('pfcCtrl', ['$scope', 'pfcArticles', function ($scope, pfcArticles) {
$scope.articles = pfcArticles.query();
}]);

pfcControllers.controller('pfcCtrl2', ['$scope', '$routeParams', 'pfcArticles', function ($scope, $routeParams, pfcArticles) {
$scope.article = pfcArticles.get({ articleID: $routeParams.articleID });
}]);

Here is my router:

var pfcModule = angular.module('pfcModule', ['ngRoute', 'pfcServices', 'pfcControllers']); pfcModule.config(['$routeProvider', function ($routeProvider) { $routeProvider. when('/home', { templateUrl: './views/home.html'}). when('/categories', { templateUrl: './views/categories.html', controller: 'pfcCtrl' }). when('/article/:articleID', { templateUrl: './views/articles.html', controller: 'pfcCtrl2' }). otherwise({ redirectTo: '/home' }); }]);

Here are my two partials:

Categories.html (multiple articles)

<div class="row">
<div class="col-md-4">
    <h2>Heading</h2>
    <table class="table table-striped">
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Category ID</th>
            <th>Link</th>
        </tr>
        <tr ng-repeat="article in articles">
            <td>{{article.id}}</td>
            <td>{{article.articletitle}}</td>
            <td>{{article.articlecategoryid}}</td>
            <td><a href="#articles/{{article.id}}">Link</a></td>
        </tr>
    </table>
</div>

Article.html (individual article)

<div class="row">
<div class="col-md-4">
    <h2>Heading</h2>
    <table class="table table-striped">
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Category ID</th>
            <th>Summary</th>
        </tr>
        <tr>
            <td>{{article.id}}</td>
            <td>{{article.articletitle}}</td>
            <td>{{article.articlecategoryid}}</td>
            <td>{{article.articlesummary}}</td>
        </tr>
    </table>
</div>

Here is a sample of my JSON output:

[{"id":"66D5069C-DC67-46FC-8A51-1F15A94216D4","articletitle":"Start Investing","articlecategoryid":1,"articlesummary":"Investing is not gambling, but many people treat it with fear, excitement and apprehension like they are playing a game of chance. They act under the assumption that an investor was born with money and understands rules that are not known by anyone else. While it is true that some of the biggest risks hold the largest gains, you can take a controlled and planned approach. There is nothing wrong with a long term reasonable gain on an investment. Question: It seems so complicated, how does someone start investing? Answer: In fact, it is easy start investing, without taking giant risks, and with a plan in place. The key is \"3D Investing\"; Diversify, Dollar Cost Averaging, and Determination. Need motivation? Use The Investing Calculator to determine your future value with compound interest. ","articlelink":"http://www.thebudgetcalculator.com/start-investing.html"},{"id":"4E94D4A5-15A3-4D3D-BAD5-C1E9264145A2","articletitle":"Why Budget","articlecategoryid":2,"articlesummary":"A budget is one of the most overlooked, yet powerful tools in a financial plan. You have to know what you have, what you don't have, and follow a \"road-map\" in order to get where you want to be! If you stick to your budget, it will be the best friend you have, because a lot of financial stress comes from not knowing where your finances are, and not having a plan. In your budget is where you lay out your plan of how your dollars are spent, what debts are being paid down (read about debt), and how much you can save for the future. Question: So why do so few people actually sit down and do a budget? Answer: Many people just don't know where to start. ","articlelink":"http://www.thebudgetcalculator.com/why-budget.html"},{"id":"E1E90A53-1839-4F1E-9C69-EFD1F77DD322","articletitle":"Managing Debt","articlecategoryid":3,"articlesummary":"Debt is both physical and emotional, because it not only affects both all physical finances and value, but also weighs on us through stress and uncertainty. A lot of this uncertainty comes from not knowing where you stand each month, and that is why a budget is so important to determine what you can and cannot spend. But let’s be realistic, at some point in our lives most of us have debt, whether it is in the form of credit cards, student loans, mortgage, etc. Question: So if you have debt, how do you go about paying it off? Answer: There are many approaches to paying down debt, and here are there of them. ","articlelink":"http://www.thebudgetcalculator.com/managing-debt.html"},{"id":"102CC729-465B-4893-8374-0F30AA4FC751","articletitle":"Retirement Planning","articlecategoryid":4,"articlesummary":"The word retirement sounds relaxing, but if you did not save for your golden years you had better start hoping for a miracle. If this statement does not scare you, let’s put it into proper perspective. If you do not save for retirement you will be a burden upon your loved ones, your society, and yourself. This is probably the shortest section on thebudgetcalculator.com because it is the most straightforward. Participate in your company’s retirement plan, or get an IRA (Individual Retirement Account). IRA's are offered at most banks and brokerages. So if your company does not have a retirement plan or you are self-employed, do yourself and the world a favor by starting your retirement savings today! The younger your start, the more you have at retirement, because the money put into an retirement account has more time to gain value before you need the funds.","articlelink":"http://www.thebudgetcalculator.com/retirement-planning.html"},{"id":"03119912-D732-4C68-B41E-F34B28FCD20F","articletitle":"Investing Basics","articlecategoryid":1,"articlesummary":"Learn the investing basics using these resources and start investing today. Whether you are a beginner investor, or seasoned broker, it is always valuable to understand the fundamentals of investing.","articlelink":"http://www.theinvestingcalculator.com/investing-basics.html"}]

Do I need to perform some sort of URL rewrite, and if so, how do I do that in Angular? Is there another way to have the link be unique with an ID, or are others just linking to the title?

4
please also post your routing setup... .when() and .otherwise() , you can set optional parameters on the route by adding ":" and the name of parameter. Also, you could use $location.search service in angular to set the id on the urlSoluableNonagon
var pfcModule = angular.module('pfcModule', ['ngRoute', 'pfcServices', 'pfcControllers']); pfcModule.config(['$routeProvider', function ($routeProvider) { $routeProvider. when('/home', { templateUrl: './views/home.html'}). when('/categories', { templateUrl: './views/categories.html', controller: 'pfcCtrl' }). when('/article/:articleID', { templateUrl: './views/articles.html', controller: 'pfcCtrl2' }). otherwise({ redirectTo: '/home' }); }]);Kode
It looks like the Angular tutorial is using the id field but the value is actually a string title. Not a true ID field IMO.Kode

4 Answers

3
votes

I would recommend to add anther route in addition to the existing route

  when('/phones/:phoneId', {
    templateUrl: 'partials/phone-detail.html',
    controller: 'PhoneDetailCtrl'
  }).
  when('/phones/:phoneId/:title', {
    templateUrl: 'partials/phone-detail.html',
    controller: 'PhoneDetailCtrl'
  })

For your case, you can have the following links which goes to the same page.

 <a href="http://my.url.com/articles/#66D5069C-DC67-46FC-8A51-1F15A94216D4">Start Investing</a>

 <a href="http://my.url.com/articles/#66D5069C-DC67-46FC-8A51-1F15A94216D4/Start+Investing">Start Investing</a>

The second will work the exactly the same as the first one

1
votes

You can use one of the following options, I have ordered them by my preference:

  1. Just use the formatted title in url and don't add anything else unless there is a collision between titles. In case of collision in title then use one of the methods below to distinguish between them. Your route would look like '/articles/:formattedTitle'. If there are multiple articles in database with same title and there is no explicit indicators of which one to pick then go ahead and pick the one created earliest.
  2. Create a new field called textKey, and auto populate that field uniquely based on the title of the article. e.g. one will result in http://my.url.com/articles/start-investing and the next one results in http://my.url.com/articles/start-investing-2. Your route would look like '/articles/:textKey'
  3. Create a new field called discriminator with default value of Null only populate it only if collision occcurs in titles. e.g. one will result in http://my.url.com/articles/start-investing and the next one results in http://my.url.com/articles/start-investing/1. Your route would look like '/articles/:formattedTitle/:discriminator'
  4. add both ID and title e.g. one will result in http://my.url.com/articles/start-investing/66D5069C-DC67-46FC-8A51-1F15A94216D4 and the next one results in http://my.url.com/articles/start-investing/AAE5069C-ABCD-46FC-8A51-1F15A94213A5. Your route would look like '/articles/:formattedTitle/:id'
1
votes

I would suggest that you use the author's username as well in the URL , so that the route will look like

.when('/article/:userID/:articletitle', { 
    templateUrl: './views/articles.html', 
    controller: 'articleCtrl' 
  })

This would solve the problem of different author having same article title (but now there would be a problem if the author publishes two articles with the same title. For this you can either introduce the year or month in the URL to make it unique)

Also you can create another view where author can see all their articles (route would be like)

.when('/article/:userID', { 
    templateUrl: './views/allArticles.html', 
    controller: 'allArticleCtrl' 
  })
0
votes

Using js to generate your page isn't very SEO compliant... and also, why is-there an "article-link" attribute in your JSON..?

If this link is not useless then you could just fetch the html content and parse the output to build your product object.

Or, better, you should rework your server-side implementation because if you are able to get an html with a GET request on http://www.thebudgetcalculator.com/start-investing.html then you should implement it the same way for JSON api calls like http://www.thebudgetcalculator.com/api/articles/start-investing