Search code examples
javascriptangularjsrestrestangularspring-data-rest

How can I add my tasks back to my list using Restangular


So here's the flow that I'd like request wise, intial page load -> get tasks -> add task. add task, should not require a subsequent fetch of it's created task or the list.

here's the relevant part of my app.js thus far

.config(function (RestangularProvider) {
RestangularProvider.setBaseUrl('http://localhost:8080');
RestangularProvider.addResponseInterceptor(function halInterceptor(data, operation, what) {
  var resp;

  if (operation === 'getList') {
    if (typeof data._embedded !== 'undefined') {
      resp = data._embedded[what];
      resp.page = data.page;
      return resp;
    }
    else {
      return [];
    }
  }

  return data;
});
})

here's my controller

'use strict';
angular.module('myTaskApp')
.controller('Task', function ($scope, Restangular) {
var tasks = Restangular.all('task');

if ( typeof $scope.tasks === 'undefined' ) {
  $scope.tasks = tasks.getList().$object;
}

$scope.add = function add() {
  tasks.post($scope.task).then(function () {
    console.log('add task: ', $scope.task);
    // MAGIC HERE
  });
 };
})
;

Here are the response headers for a create

HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-: POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Headers: content-type, x-requested-with
Access-Control-Max-Age: 3600
Location: http://localhost:8080/task/5c75235d-d9f7-4cdd-98b4-3487603d8fcb
Content-Length: 0
Date: Sat, 20 Sep 2014 06:34:59 GMT

I think that part of my problem is that the response doth not return the body, however, I can predict what that should look like, and would be easy to craft after grabbing location.

{
"description" : "better",
"_links" : {
  "self" : {
   "href" : "http://localhost:8080/task/5c75235d-d9f7-4cdd-98b4-3487603d8fcb"
  }
 }
}

how can I make it so that when I create a new resource I can then add it to the $scope.tasks list and have that reflected in my ng-repeat. Again, this should be without making further calls to the API.


Solution

  • Having updated my provider, which now contains a selfLink definition and a post handler. I retrieve the location from the response and construct a partial response object.

    .config( function ( RestangularProvider ) {
    RestangularProvider.setBaseUrl( 'http://localhost:8080' );
    RestangularProvider.setRestangularFields({ selfLink: '_links.self.href' });
    RestangularProvider.addResponseInterceptor( function halInterceptor( data, operation, what, url, res ) {
      console.log( data, operation, what, url, res );
    
      if ( operation === 'getList' ) {
        if ( typeof data._embedded !== 'undefined' ) {
          var resp = data._embedded[ what ];
          resp.page = data.page;
          return resp;
        }
        else {
          return [];
        }
      }
    
      if ( operation === 'post' && res.status == 201 ) {
        return {
          _links: {
            self: { href: res.headers('Location') }
          }
        };
      }
    
      return data;
    } );
    

    Then in my controller all I have to do is use angular.extend to combine the response and create a "smart object"

    angular.module('lifeManagerApp')
    .controller('Task', function ($scope, Restangular) {
    var tasks = Restangular.all('task');
    
    if ( typeof $scope.tasks === 'undefined' ) {
      $scope.tasks = tasks.getList().$object;
    }
    
    $scope.add = function add() {
      tasks.post($scope.task).then(function ( task ) {
        var obj = angular.extend($scope.task, task);
        console.log('add task: ', obj );
        $scope.tasks.push(obj);
      });
    };
    });
    

    It's worth noting that for my stuff I also had to update CORS and make sure my controller wasn't loading multiple times