Backbone JS: how to disable sync for delete?
Asked Answered
A

5

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?

Awning answered 18/4, 2012 at 21:50 Comment(2)
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.Aa
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.Awning
G
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.

Galacto answered 18/4, 2012 at 22:27 Comment(4)
Thanks @Edward. I ended up simply deleting them from the collection.Awning
@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.Galacto
@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.Stablish
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.Mirepoix
J
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();
},
Jolie answered 1/6, 2012 at 2:57 Comment(2)
Well so what would be a purpose of destroying without actually deleting from the server?Awning
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.Jolie
D
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();
       }
    }
});
Dirigible answered 15/5, 2015 at 16:3 Comment(0)
A
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);
Aymer answered 4/11, 2013 at 5:58 Comment(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.Kassie
U
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);
    }
});
Unidirectional answered 3/5, 2015 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.