29

I am interested in moving a lot of my client's "logic" away from Rails routing to AngularJS. I have slight confusion in one topic and that is linking. Now, I do understand there's more than one way to handle this, but what is the common practice in the AngularJS community for handling URLs on handling CRUD for resources. Imagine in the case of an athlete we have a URL such as the following to list all athletes:

http://example.com/athletes

To view an individual athlete:

http://example.com/athletes/1

To edit an individual athlete:

http://example.com/athletes/1/edit

To create a new athlete:

http://example.com/athletes/new

In AngularJS, is it common practice to reroute to similar URLs to create/edit/update? Would you just have one URL handle all of the CRUD type actions in one interface and never change the URL? If you were to change the URL, does that get handled via ng-click and in the click event would you use the $location object to change URLs? I'd love to be able to read up on common practices such as these, but having a difficult time in finding more recent literature on it in an AngularJS context.

** NOTE **

I totally get that you can still use RESTful routes to the backend in order to interact with server-side resources. My question is, what is the style that is recommended to use when updating URLs on the client-side. Are you using AngularJS to do that for each of the CRUD operations?

Umar Khan
  • 1,381
  • 11
  • 18
randombits
  • 47,058
  • 76
  • 251
  • 433
  • 1
    angular has `$resource` (http://docs.angularjs.org/api/ngResource.$resource) that supports CRUD operations. – akonsu Aug 01 '13 at 19:47
  • Could you clarify if you mean front-end or API? That is, AngularJS' `$routeProvider` URLs or URLs that you pass to `$http`/`$resource`? – Steve Klösters Aug 01 '13 at 19:53
  • 1
    All I'm really trying to ask here is if Angular developers tend to use tools like $routeProvider to ensure the URL in the browser (maybe for bookmarking or linking purposes) is updated to the same URL they're calling via XHR in order to interact with a resource. – randombits Aug 02 '13 at 15:03

5 Answers5

45

I would definitely recommend separate URLs for each operation (to enable direct linking). The ones you suggest look fine.

In AngularJS you can use the $route service in combination with the ngView directive to load the appropriate template for each operation and handle the browser location and history mechanics for you.

Step 7 of the AngularJS tutorial gives an example of using Views, Routing and Templates the way I describe here. The following is a simplified version for your example:

Define the routes

In your main application script (e.g. app.js):

angular.module('AthletesApp', []).
  config(['$routeProvider', function($routeProvider, $locationProvider) {
  // Configure routes
  $routeProvider.
      when('/athletes', {templateUrl: 'partials/athletes-list.html',   controller: AthleteListCtrl}).
      when('/athletes/:athleteId', {templateUrl: 'partials/athlete-detail.html', controller: AthleteDetailCtrl}).
      when('/athletes/:athleteId/edit', {templateUrl: 'partials/athlete-edit.html', controller: AthleteEditCtrl}).
      when('/athletes/:athleteId/new', {templateUrl: 'partials/athlete-new.html', controller: AthleteNewCtrl}).
      otherwise({redirectTo: '/athletes'});
  // Enable 'HTML5 History API' mode for URLs.
  // Note this requires URL Rewriting on the server-side. Leave this
  // out to just use hash URLs `/#/athletes/1/edit`
  $locationProvider.html5Mode(true);
}]);

We also enable 'HTML Mode' for URLs, see note below.

2. Add an ngView directive to your HTML

In your main index.html you specify where the selected partial template will go in the overall layout:

<!doctype html>
<html ng-app="AthletesApp">
...
   <!-- Somewhere within the <body> tag: -->
   <div ng-view></div>
...
</html>

3. Create templates and controllers

Then you create the partial view templates and matching controllers for each of the operations. E.g. for the athlete detail view:

partials/athelete-detail.html:

<div>
    ... Athete detail view here
</div>

athleteDetailCtrl.js:

angular.module('AthletesApp').controller('AtheleteDetailCtrl',
    function($scope, $routeParams) {
        $scope.athleteId = $routeParams.athleteId;
        // Load the athlete (e.g. using $resource) and add it
        // to the scope.
    }

You get access to the route parameter (defined using :athleteId in the route config) via the $routeParams service.

4. Add links

The final step is to actually have links and buttons in your HTML to get to the different views. Just use standard HTML and specify the URL such as:

<a href="/athletes/{{athleteId}}/edit">Edit</a>

Note: Standard vs Hash URLs

In older browsers that don't support the HTML5 History API your URLs would look more like http://example.com/#/athletes and http://example.com/#/athletes/1.

The $location service (used automatically by $route) can handle this for you, so you get nice clean URLs in modern browsers and fallback to hash URLs in older browsers. You still specify your links as above and $location will handle rewriting them for older clients. The only additional requirement is that you configure URL Rewriting on the server side so that all URLs are rewritten to your app's main index.html. See the AngularJS $location Guide for more details.

  • Quick question. Often with New and Edit templates and controllers there is a lot of overlap. Is there a way of reusing the template and/or controllers? So if you added a new field you wouldn't have to do the update in two places? – uriDium Sep 10 '13 at 07:04
  • 1
    @uriDium You could reuse the whole template by just pointing `templateUrl` in the `edit` and `new` routes to the same file. More commonly you might need some differences between the views in which case you could extract out common parts into separate template(s) and use the ngInclude directive to include them in the `new.html` and `end.html` templates. For the controllers I extract common functionality into a _service_ that can be injected into both controllers. – Derek Hinchliffe Sep 20 '13 at 14:17
  • 2
    What is not clear is the athlete id that is used for the new route, when you are creating a new entity you don't still have the id unless you are generating the id by code, and is not recommended to do that on javascript, perhaps a better approach would be `/athletes/new` instead of `/athletes/:id/new` – Nico Sep 11 '14 at 21:01
  • What if I don't want to use Angular routings but simple server side routings to handle requestes? – Andrea Turri Dec 19 '14 at 14:29
16

The angular way is the restful way:

GET all http://example.com/athletes
GET one http://example.com/athletes/1
POST new http://example.com/athletes
PUT edit http://example.com/athletes/1
DELETE remove http://example.com/athletes/1

Note that $resource also expects a few other things, like resource URLs not ending with a slash, PUT requests returning the updated resource, etc.

If your API doesn't meet these criteria, or you simply need more flexibility, you can build your own $resource-like CRUD service based on the lower-level $http service. One way of doing the latter is explained here

Community
  • 1
  • 1
holographic-principle
  • 19,688
  • 10
  • 46
  • 62
  • 1
    I have used a `$resource` factory to make calls to a ServiceStack API. Just so you are aware it is a seperate module that needs loaded into your own application module. (_It does not come in the default angularjs files_) – Malkus Aug 01 '13 at 19:58
  • 1
    I'd just like to add - this doesn't have to do as much with REST as with working correctly with the HTTP protocol and using its correct verbs for the appropriate actions. – Benjamin Gruenbaum Aug 01 '13 at 20:07
  • What are you using to explicitly route to these URLs before calling a server-side API, though? $resource is mostly for server-side communication. are you explicitly using $routeProvider to change to these URLs first? – randombits Aug 01 '13 at 20:09
  • So if the user types http://example.com/athletes/1 in the URL, do you display the GET template (for displaying) or the PUT template (for editing)? How do you differentiate the two just from the URL? – Prabhu Sep 24 '14 at 05:04
  • @Prabhu when you load a page in the browser, the default action is GET. To send a PUT request you would need to use some kind of an HTTP client. – holographic-principle Sep 24 '14 at 13:20
  • @finishingmove so if the user needs to fill out the form before they can submit the PUT request, what URL will load the form for the user? – Prabhu Sep 24 '14 at 18:46
  • @Prabhu whatever you want, it doesn't have to correspond to any of these. But you can say `/athletes/1` for example. – holographic-principle Sep 26 '14 at 13:42
5

Option 1: $http service

AngularJS provides the $http service that does exactly what you want: Sending AJAX requests to web services and receiving data from them, using JSON (which is perfectly for talking to REST services).

To give an example (taken from the AngularJS documentation and slightly adapted):

$http({ method: 'GET', url: '/foo' }).
  success(function (data, status, headers, config) {
    // ...
  }).
  error(function (data, status, headers, config) {
    // ...
  });

Option 2: $resource service

Please note that there is also another service in AngularJS, the $resource service which provides access to REST services in a more high-level fashion (example again taken from AngularJS documentation):

var Users = $resource('/user/:userId', { userId: '@id' });
var user = Users.get({ userId: 123 }, function () {
  user.abc = true;
  user.$save();
});

Option 3: Restangular

Moreover, there are also third-party solutions, such as Restangular. See its documentation on how to use it. Basically, it's way more declarative and abstracts more of the details away from you.

Golo Roden
  • 140,679
  • 96
  • 298
  • 425
2

In AngularJS you can definitely use RESTful server side data sources, there is build in service called $resource.

Alternatively you can also use restangular which has additional features over $resource.

If you want to have full control you can always use $http service which is low level angular component for interacting with http.

T W
  • 6,267
  • 2
  • 26
  • 33
0

Simply implement something that is RESTful, that is the angularJS way. If you have no idea what RESTful is or, know a little and want to know a lot more, then I would recommend that you read this article.

Basically, REST is what is understood to be, an intuitive implementation of WEB URIs, it also makes use of all HTTP verbs, their correct use actually. REST is an approach, and architecture to building web apps.

Games Brainiac
  • 80,178
  • 33
  • 141
  • 199