4

I am working on my first AngularJS application in order to learn the framework.

I am currently hiting a wall finding the idiomatic way to handle nested resources.

I have areas containing buildings containing flats. One flat is only inside one building, which is turn in only inside one area.

In my database model I do not need to store the area Id together with the flat object, its parent (building Id) is enough.

Below is a minimal example I wrote to illustrate the concept. I based it on what I saw on the video from the Google I/O: http://www.youtube.com/watch?v=HCR7i5F5L8c

My question is: how can I instantiate a specific Flat resource? I have all the information needed in the URL but it doesn't strictly correspond to my model (area Id is missing).

var app = angular.module('neighborhoodApp', [
  'ngResource',
  'ngRoute'
]);

angular.module('neighborhoodApp')
  .factory('Area', function ($resource) {
    return $resource('/areas/:id', {
      'id': '@_id'
    });
  });

angular.module('neighborhoodApp')
  .factory('Building', function ($resource) {
    return $resource('/areas/:aid/buildings/:id', {
      'id': '@_id',
      'aid': '@area_id'
    });
  });

angular.module('neighborhoodApp')
  .factory('Flat', function ($resource) {
    return $resource('/areas/:aid/buildings/:id/flats/:id', {
      'id': '@_id',
      'bid': '@building_id'
      // 'aid': '@area_id' => my model doesn't have an area id, having a building id attached to a flat is enough to find the area
    });
  });

angular.module('neighborhoodApp')
  .controller('AreaListCtrl', function (Area) {
    this.areas = Area.query();
  });

angular.module('neighborhoodApp')
  .controller('AreaShowCtrl', function ($routeParams, Area) {
    this.area = Area.get({
      id: $routeParams.aid
    });
  });

angular.module('neighborhoodApp')
  .controller('BuildingListCtrl', function (Building) {
    this.buildings = Building.query();
  });

angular.module('neighborhoodApp')
  .controller('BuildingShowCtrl', function ($routeParams, Building) {
    this.building = Building.get({
      aid: $routeParams.aid,
      id: $routeParams.rid
    });
  });

angular.module('neighborhoodApp')
  .controller('FlatShowCtrl', function (Flat) {
    this.flats = Flat.query();
  });

// What is the idiomatic way to pass the area id (from $routeParams.aid)
// so that the server can be queried successfully
angular.module('neighborhoodApp')
  .controller('FlatListCtrl', function ($routeParams, Flat) {
    this.flat = Flat.get({
      bid: $routeParams.bid,
      id: $routeParams.rid
    });
  });

app.config(function ($routeProvider) {
  $routeProvider
    .when('/areas', {
      templateUrl: 'views/area/list.html',
      controller: 'AreaListCtrl',
      controllerAs: 'list'
    })
    .when('/areas/:aid', {
      templateUrl: 'views/area/show.html',
      controller: 'AreaShowCtrl',
      controllerAs: 'show'
    })
    .when('/areas/:aid/buildings', {
      templateUrl: 'views/building/list.html',
      controller: 'BuildingListCtrl',
      controllerAs: 'list'
    })
    .when('/areas/:aid/buildings/:bid', {
      templateUrl: 'views/building/show.html',
      controller: 'BuildingShowCtrl',
      controllerAs: 'show'
    })
    .when('/areas/:aid/buildings/:bid/flats', {
      templateUrl: 'views/flat/list.html',
      controller: 'FlatShowCtrl',
      controllerAs: 'list'
    })
    .when('/areas/:aid/buildings/:bid/flats/:fid', {
      templateUrl: 'views/flat/show.html',
      controller: 'FlatListCtrl',
      controllerAs: 'show'
    })
    .otherwise({
      redirectTo: '/areas'
    });
});
Thomas
  • 1,360
  • 1
  • 9
  • 15
  • it looks like api is Restful. If so, I would highly recommend Restangular library... very streamlined work flow. I am just learning angular also on my first project. Im about 2mo in. Restangular is very slick. When you fetch a resource, it returns you with a js object, you modify that js object, and it already knows how to save itself back to the api.. ie "myRestObj.post()" https://github.com/mgonto/restangular – timh Mar 21 '14 at 07:13
  • So, you are passing the `bid` and `rid` to your route, and both of those are enough to instance a specific `Flat`? – J.Wells Apr 13 '14 at 20:09

1 Answers1

1

I dont think you need the areaId at all, when retrieving a flat, all you need is the flatId.

However, when saving a new flat, then you may add the buildingId as part of the details of the flat (in the model)

.factory('Flat', function ($resource) {
    return $resource('/flats/:id', {

but when you query flats e.g. all flats in area 1

Flat.query({aid=1})

which will translate to

www.yourapp.com/flat?aid=1

you do not have to add it to your model because it is not part of the model.

sawe
  • 1,141
  • 14
  • 24