21

I am dealing with a threaded comments collection, and when I delete a comment that has children, I do model.destroy() for this comment, and on the server side all its branches get deleted.

I wrote a function that once a node is deleted from the tree, looks for all orphans and removes them too. So when I find orphans, I run model.destroy() on them too but because they're already deleted on the server, sync returns errors.

Is there a way to disable sync for some destroy() calls?

mvbl fst
  • 5,213
  • 8
  • 42
  • 59
  • I'm curious whether overriding `.sync()` and adding some extra logic for the `delete` method would be overkill for this, or if there is a cleaner way. – Colin Brock Apr 18 '12 at 22:05
  • Well I hoped NOT to override .sync() But I can't see any native way of doing it. I can hack by triggering 'destroy' events and splicing the model from collection but that does not sound kosher. – mvbl fst Apr 18 '12 at 22:08

5 Answers5

33

Since all the destroy method does is send a DELETE request and triggers destroy, simply triggering destroy is exactly what you're looking for.

model.trigger('destroy', model, model.collection, options);

Yeah, it feels a bit hackish, but that's pretty much all the Backbone code does anyway. If you want, and if you have a base model you extend from, you could add this as a method on that base model, and it might not feel quite so hackish.

Edward M Smith
  • 10,627
  • 2
  • 46
  • 50
  • Thanks @Edward. I ended up simply deleting them from the collection. – mvbl fst Apr 18 '12 at 23:31
  • 4
    @forresto - that works if the model is only in a single collection. If you have the model is multiple collections, you'd have to know which collections the model is in and do that to every collection - which means tracking in the model which collections it belongs to. That's kind of backwards. By triggering 'destroy' on the model, any collections it is in will remove it, and you don't have to track which collections the model is in. – Edward M Smith Mar 01 '13 at 14:05
  • 5
    @EdwardMSmith Wouldn't be enough to call model.trigger('destroy')? Is it necessary to pass model, model.collection and options parameters? Thanks for your answer. – suat May 10 '13 at 10:24
  • 1
    In fact, from the backbone source, there is also a `this.model.stopListening();` before triggering the destroy event. Then, the destroy event will trigger the collection.remove() function. – Luca Reghellin Sep 29 '15 at 09:19
2

This is kind of late but might work as an alternate solution for other people having the same problem.

Confronted with a very similar problem, I ended up setting all the children IDs to null before calling destroy on them. This way, backbone thinks that they are new and doesn't spawn a DELETE HTTP request to the server upon removal.

deleteParent: function() {
  this.model.children.each(function(child) {
    // Set to null so that it doesn't try to spawn a 'DELETE' http request 
    // on 'destroy' since thinks its new (hack).
    child.id = null; 
    child.destroy();
  });
  // This one DOES result in a 'DELETE' http request since it has an ID.
  this.model.destroy();
},
fcarriedo
  • 176
  • 6
  • Well so what would be a purpose of destroying without actually deleting from the server? – mvbl fst Jun 01 '12 at 18:54
  • If I understood your question correctly, when you deleted the parent from the server, you also deleted all its children (maybe on a transaction), so when you remove (*destroy*) the child orphans from the UI you don't want to make a call to the server to delete each or the orphans since they don't exist anymore. This achieves the desired behavior. – fcarriedo Jun 01 '12 at 21:29
2

This allows you to respect the destroy call, including any success handlers

Backbone.Model.extend({
    destroy: function (options) {
       // don't make a server call, just delete from collection and call success
       this.trigger('destroy', this, this.collection, options);
       if (options && options.success) {
              options.success();
       }
    }
});
Community
  • 1
  • 1
Jesse Suero
  • 21
  • 1
  • 3
1

Ran into this same problem.

Using the model's link to its containing collection to remove the model from that collection was my preferred solution since this was exactly what I wanted to do and very clear in the code:

// From the view
this.model.collection.remove(this.model);
Chris Dutrow
  • 48,402
  • 65
  • 188
  • 258
  • 1
    Although this removes the model from the collection, this won't trigger the destroy event which can cause problems if you have any event listening to it. – Yahya Uddin Jul 03 '16 at 02:53
1

Building on fcarriedo's answer, just override the destroy method in your Model's declaration:

Models.YourModelName = Backbone.Model.extend({
    destroy: function () {
        this.id = null;
        Backbone.Model.prototype.destroy.apply(this, arguments);
    }
});
Sam
  • 5,375
  • 2
  • 45
  • 54