3

I am using Angular now for about 2-3 weeks and have only used data binding and have made attempts to create directives. Now I'd like to save an object to the server.

The domain model looks like this:

public class Customer
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string CompanyName { get; set; }
    public string EmailAddress { get; set; }
    public DateTime BirthDate { get; set; }
    public string BSNNo { get; set; }
    public string IdCardNo { get; set; }
    public bool Deceased { get; set; }
    public Gender Gender { get; set; }
    public Title Title { get; set; } // Title is an enum
    internal bool IsActive { get; set; }

    public PersonName Name { get; set; } // A value object
    public PhoneNumber DayPhone { get; set; } // A value object
    public PhoneNumber OtherPhone { get; set; }

    public virtual Address Address { get; set; } // A value object
    public virtual Address PostallAddress { get; set; }
}

Now I've created a corresponding HTML form and when I submit this form, it will be handled by Angular. But now I am wondering what the best/recommended way is to save this form.

FYI: We are using ASP.NET MVC 4

Martijn
  • 24,441
  • 60
  • 174
  • 261
  • you should be using angular rest based $resource http://docs.angularjs.org/api/ngResource.$resource – Ajay Beniwal Jun 03 '13 at 11:07
  • 1
    possible duplicate of [Recommended way of getting data from the server](http://stackoverflow.com/questions/11850025/recommended-way-of-getting-data-from-the-server) – Stewie Jun 03 '13 at 12:45
  • @Stewie It looks like it is a duplicate, however, I don't care the usage of `$resource`. – Martijn Jun 03 '13 at 15:18

2 Answers2

7

We find $resource to be a great way to go. The $httpBackend service allows for easy testing as well. We have something like the following and it works well for us. You can always drop back to the $http service if you want a little more control.

View

<!DOCTYPE html >

<html ng-app="myApp">
<head>
</head>
<body ng-controller="CustomerController">
    <form name="form" novalidate>
        <input type="text" ng-model="customer.name" required />
        <input type="text" ng-model="customer.address" required />
        <button ng-click="add(customer)">Save</button>
    </form>
    <script src="~/Scripts/angular.js"></script>
    <script src="~/Scripts/angular-resource.js"></script>
    <script src="~/Scripts/app/app.js"></script>
    <script src="~/Scripts/app/services/customerResource.js"></script>
    <script src="~/Scripts/app/controllers/CustomerController.js"></script>

</body>
</html>

Service:

myApp.factory('customerResource', function($resource){
  var resource = $resource('/data/customer/:id', { id: '@id' }, { 'put' : {method:'PUT' } });

  return {
    getAll : function(){
        return resource.query();
    },
    add : function(customer){
            return resource.save(customer);
    },
    update : function(customer){
            return resource.put({ id: customer._id }, customer);
    },
    remove : function(id){
            return resource.remove( { id: id });
    }
  };
});

Controller:

myApp.controller('CustomerController', function($scope, customerResource) {

  $scope.customer = {};

  $scope.customers = customerResource.getAll();

  $scope.add = function(customer){
    $scope.customers.push(customerResource.add(customer));
  }

  $scope.update = function(customer){
    customerResource.update(customer);
  }

  $scope.remove = function(customer){
    customerResource.remove(customer._id);
    $scope.customers.splice($scope.customers.indexOf(customer), 1);
  }
});

Very basic testing:

describe('customerResource', function(){
  beforeEach(module('myApp'));

  describe('getAll', function(){

    it('should issue a GET request to /data/customer', inject(function(customerResource, $httpBackend){
      $httpBackend.expectGET('/data/customer').respond([{ level: '5'}]);

      var customers = customerResource.getAll();
      $httpBackend.flush();

      expect(customers[0].level).toBe('5');
  }));

  it('should return an array of custoemrs', inject(function(customerResource, $httpBackend){
    $httpBackend.when('GET', '/data/customer').respond([{ level: '5'}, { level: '6'}]);

    var customers = customerResource.getAll();
    $httpBackend.flush();

    expect(customers[0].level).toBe('5');
    expect(customers[1].level).toBe('6');
  }));
});

MVC Action (ADD - MVC model binders will do the work of parsing the html params into the VM):

[HttpPost]
public ActionResult Customer(Customer customer)
{
        // add the customer to the database or whatever
}

ViewModel:

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
}

The HTTP request will look something like:

Request URL:http://mywebsite/data/customer
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en;q=0.8,en-US;q=0.6
Cache-Control:no-cache
Connection:keep-alive
Content-Length:30
Content-Type:application/json;charset=UTF-8
Host:mywebsite
Origin:http://mywebsite
Pragma:no-cache
Request Payloadview source
  {name:somename, address:someaddress}
  address: "somename"
 name: "someaddress"

HTH

Sean Kenny
  • 1,626
  • 13
  • 14
  • Thanks for the code. I'm only curious on how your back end looks like. I mean, where does `/data/customer/:id` point to? And does this back-end matches the method names `getAll`, `add`, `update`, `delete`? – Martijn Jun 03 '13 at 13:33
  • The docs give the HTTP verbs - http://docs.angularjs.org/api/ngResource.$resource#Returns. So you just need an action with the name Customer as a HttpGet, or HttpPost for the add. The backend I'm using is node I'm afraid. – Sean Kenny Jun 03 '13 at 13:38
  • Just updated my answer with some backend detail. Just set up the angular side, then open the network tab in chrome and play with it. – Sean Kenny Jun 03 '13 at 14:09
  • I see, thank you very much. Do you perhaps know a tutorial or video where all this is explained? I find the Angular documentation to vaque, it's more a reference-book than a tutorial. – Martijn Jun 03 '13 at 15:17
  • Egghead.io is great and there is a detailed course on pluralsight.com. If you are happy to, can you accept this answer? – Sean Kenny Jun 03 '13 at 15:52
3

Try taking a look at breeze.js - it includes some handy change tracking and also has .Net Linq style syntax for querying a OData/WebAPI services where the query will actually be run server-side. It's like $resource but on steroids.

Phil
  • 2,232
  • 1
  • 26
  • 35
  • +1. Only caveat is that it does not work with angularjs on IE8 and below http://stackoverflow.com/questions/14238134/breeze-and-angular-todo-app-does-not-work-with-ie-8/14244011#comment19764078_14244011 – Sean Kenny Jun 04 '13 at 07:44