angularjsangular-httpbackand

Update a complex object on Backand using $http PUT


I am using Backand to provide the database and REST api for my Angular app.

I am working on a capability for users to make edits to a complex object, which should then be updated on the database. Straightforward enough...

The object looks a bit like this:

obj = {
  id: 1,    // assigned by the db
  name: "My List",
  tasks: [
    { id: 1, desc: "Task 1" },
    { id: 2, desc: "Task 2" }, 
     ... 
  ]
}

For the update ($http PUT) call, I would like to use params: { deep: true } as a shortcut to minimise code and $http calls.

The problem at the moment is that while the PUT command updates the "master" object in the database, the edited "child" objects are not updated, but appended as new child objects.

For instance, if I try to update the master and child objects in one call:

$http({
  method: 'PUT',
  url: baseUrl + 'lists/' + list.id,
  params: {
    deep: true
  },
  data: {
    id: 1,
    name: "My To Do List",
    tasks: [
      { id: 1, desc: "New Description for Task 1" },
      { id: 2, desc: "New Description for Task 2" }
    ]
  }
}).then( .... );

the database doesn't update the child objects, it appends them. Here's how the resulting object is in the database:

list = {
  id: 1,  
  name: "My To Do List",    // Updated correctly
  tasks: [
    { id: 1, desc: "Task 1" },
    { id: 2, desc: "Task 2" }, 
    { id: 3, desc: "New Description for task 1" },  // Added not updated
    { id: 4, desc: "New Description for task 2" }   // Added not updated
  ]
}

I have made sure that the child objects' ids are correct.

Is there any way to do this succinctly or am I resigned to doing it in multiple stages? Does deep = true even work with PUT? The Backand docs don't mention it.


Solution

  • Backand identifies existing objects according to their

    {
       __metadata: {id: "6"}
    } 
    

    When you "GET" an object from Backand it contains such a metadata. When you "PUT" an object without the metadata id, Backand threats it as a new object. So either use the same deep object that you originally got or add the metadata id.

    $http({
      method: 'PUT',
      url: baseUrl + 'lists/' + list.id,
      params: {
        deep: true
      },
      data: {
        "__metadata": { "id": "1" },
        id: 1,
        name: "My To Do List",
        tasks: [
          { "__metadata": { "id": "1" }, id: 1, desc: "New Description for Task 1" },
          { "__metadata": { "id": "2" }, id: 2, desc: "New Description for Task 2" }
        ]
      }
    }).then( .... );
    

    To delete tasks children in the "PUT" request you have to add overwrite=true to the params

    params: {
        deep: true,
        overwrite: true
    }