My project uses AngularJS + Django Tasypie. I'm handling form submissions with the CoffeeScript code I posted bellow. Since I'm just starting to develop with Angular, I would like suggestions for improving. Maybe the use of a service and/or $resource? It's important to notice that the "Project" entity has a oneToMany "Client" relation.
Thank you.
Generic model class:
class window.Model
constructor: (options) ->
@$scope = options.$scope
@$http = options.$http
@id = if options.id? then options.id
fetch: (cb= ->) =>
@$http.get(@url + '/' + @id).success (data) =>
@toScope(data)
cb(data)
fetchAll: (cb= ->) =>
@$http.get(@url).success (data) =>
@toScopeAll(data)
cb(data)
save: (data, cb= ->) ->
@update data, cb if @id? else @create data, cb
create: (cb= ->) ->
@$http.post(@url + '/', @fromScope()).success cb
update: (cb= ->) =>
@$http.put(@url + '/' + @id, @fromScope()).success cb
remove: (cb= ->) ->
@$http.delete(@url + '/' + @id).success cb
Project / Client model class:
class window.ProjectModel extends Model
url: '/api/project'
toScope: (data) =>
@$scope.project = data
@$scope.client = @$scope.project.client.id
fromScope: (data) =>
id: @$scope.project.id
name: @$scope.project.name
client: id: @$scope.client
class window.ClientModel extends Model
url: '/api/client'
toScopeAll: (data) =>
@$scope.clients = [id: '0', name: 'Choose...'].concat data.objects
Controller code:
window.ProjectCtrl = ($scope, $routeParams, $http) ->
redirect = -> window.location = '#/projects'
$scope.save = -> project.save redirect
$scope.delete = -> project.remove redirect
$scope.cancel = redirect
$scope.client = '0'
client = new ClientModel($scope: $scope, $http: $http)
client.fetchAll()
project = new ProjectModel($scope: $scope, $http: $http)
if $routeParams.projectId?
$scope.formType = 'update'
project.id = $routeParams.projectId
project.fetch()
It feels like you're getting hung up on one-route-per-data-entity, and this is probably stemming from your coupling the serialization layer to the data model. I would suggest you reconsider your approach here. This feels like poorly-motivated inheritance.
Try keeping your models simple, logic-less JavaScript objects. Then, you should get by with a single serialization/persistence layer which will work for all data structures. Try avoiding inheritance, it isn't helping here. As a rule of thumb, I prefer composition over inheritance.
Finally, it appears that you need to do a bulk transaction. Since your persistence layer is now separate, you can modify your persistence layer to update multiple javascript objects at a time! Then, you can create a transaction route on the server, accepting a data structure similar to the following:
[
['create', 'project', {project_name: ...}]
['create', 'client', {client_attrs}]
]
As an added bonus, since a single call can handle the whole transaction, you can handle roll-back on the server should one of the operations fail business logic.
I just realized that you need to associate the client with the project-id. If you can generate your IDs on the client (using UUIDs?), this approach would work as is.
Otherwise, you can go down the whole "nested-attributes" route where you submit a data-structure for the project with the clients embedded, as follows:
{
project_name: "...",
clients: [{client1_attrs}, ...]
}
This approach is often used, but I don't like it because in my experience it rarely works great. (how do you handle deletions? Do you need to specify all of the attributes and update every associated client every time? What if the client is associated with multiple projects? You can see how quickly it falls apart.)
I think the approach I would prefer, given UUIDs are not a possibility, would be to give your transaction server controller the ability to set values returned by earlier steps:
This data-structure would tell the transaction controller to look up the field 'id' for the data entity serialized in the 0th position of the transaction list, and set it as project_id for this client prior to serialization.
[
['create', 'project', {project_name: ...}]
['create', 'client', {client_attrs}, {project_id: [0, 'id']}]
]