I'm trying to create an application similar to a floor plan editor in Backbone.js and Raphael. I'm not sure if what I'm doing is structured correctly or not.

I'm not using the Backbone routing, just the basic Models/Collections/Views.

My views are simple enough. A Building contains a collection of floors, and a floor contains a collection of rooms. The building model is populated by a JSON feed.

Building: Backbone.Model.extend({
    initialize: function() {
      this.set({
        floors: new Floors(this.get("floors"))
      });
    }
});

Floor: Backbone.Model.extend({
    initialize: function() {
      this.set({
        rooms: new Rooms(this.get("rooms"))
      });
    }
});

Room: Backbone.Model.extend({
    initialize: function() {
      // This is what contains the Raphael attributes that is necessary
      // to render the object. pathString, transformString, fill and stroke colors, etc.
    },
    render: function() { }
});

Now from all the examples I've seen, a Backbone view is supposed to be tied to an element. However since I'm using Raphael and require additional objects (when rendering a FloorView I also render an edit and delete button, labels for the name and dimensions, etc.), I bind a view to a Raphael set instead.

BuildingView : Backbone.View.extend({
   layout: null,
   initialize: function() {
      this.el = Raphael("building", 600, 600);
      this.layout = this.el.set();
      // Backbone Event Handler for all views
      this.eventAggregator.on("floorRemoved", this.removeFloor, this);
   },
   removeFloor: function(floor) {
     // Remove the nested Raphael set
     this.layout.splice($.inArray(floorView.el, this.layout), 1);
     // Remove from the model
     this.model.get("floors").remove(floorView.model);
   }
});

FloorView : Backbone.View.extend({
  initialize: function() {
    // Pass in the paper object from the BuildingView initialize method
    this.el = this.options.paper.set();
    var self = this;
    this.model.get("rooms").each(function(room) {
      var rv = new RoomView({
        model: room,
        paper: this.options.paper
    });

    var self = this;
    // delete object gets added here
    // ...
    deleteObj.click(function() {
      self.eventAggregator.trigger("floorRemoved", self);
      self.el.remove();
    });
  }
});

This setup seems to work fine, but I am running into some issues on how to handle removing a floor. So the click function on the delete floor method will trigger an event to let the building know to remove it from the parent Raphael set and the floors model collection, this seems to clean up the Raphael/model side nicely. I'm not sure what to do when it comes to the views though.

I need to do two things:

  1. Properly remove the view that was deleted, as well as the child views
  2. Reposition/re-render all the remaining views

Do I need my BuildingView and FloorView to keep track of the child views so that it can loop through to call a render method on them? Then my BuildingView would have two collections, one for the views and one for the models. Is this the right way to go about handling nested views?

share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.