Composite Views

by Evin

In my last post on bindings, I talked about Rule #2 (The ‘-Path’ Convention) which started a bit of buzz on when and why it is used. First off, it is a naming convention that my team and I have come up with to deal with passing binding paths around in a composite view. A composite view is just a custom view that is made up of using other views in some special way. Composite Views are a great organizational construct but they can be easily misused…

What is a Composite View?

As stated before, a composite view is a custom view that you build that is mainly made up of other views that operates in a special way. You would often use this when you are developing a structure of views in your ‘.lproj’ layer and you find yourself repeating a paradigm or wanting a group of views or view structure to operate in a specific manner. Examples of these can be a composite view made up of a textfield, labels, buttons that change the look and appearance of view. View that have special mouse functionality like a popup window or similar structure that makes passing some simple information for bindings or content to a internal child view.

Example

I will use a very simplistic example of a composite view for a master list view with a search bar. I call this composite view the MasterView and it will consist of a SC.TextFieldView and a SC.ListView. You usually don’t want to do such a simplistic view as this, but it will work for the purposes of illustration. The code might look like this:

myApp.MasterView = SC.View.extend(
/** @scope myApp.MasterView.prototype */ {
 
  classNames: ['master-view'],
 
  /**
    Necessary config elements to set up binding in the composite view
  */
  contentPath: '',      // Binding Path for the content of the ListView
  selectionPath: '',    // Binding Path for the selection on the ListView
  searchPath: '',       // Binding Path for the text searching
  contentValueKey: '',  // ContentValueKey to be passed to the ListView
 
  /**
    Overwritten createChildView where you set up all 
    the internal child view and where we are
    going to use the Binding Paths
  */
  createChildViews: function() {
    var childViews = [], view;
 
    //Add the search text field
    view = this.createChildView(
      SC.TextFieldView.design({
        layout: {/* layout here */},
        valueBinding: this.get('searchPath')
      }),
      { rootElementPath: [0] }
    );
    childViews.push(view);
 
    view = this.createChildView(
      SC.ListView.design({
        layout: { /* layout here */ }, 
        contentValueKey: this.get('contentValueKey'),
        contentBinding: this.get('contentPath'),
        selectionBinding: this.get('selectionPath'),
      }),
      { rootElementPath: [1] }
    );
    childViews.push(view);
 
    this.set('childViews', childViews); 
  },
 
  /* Do Special Stuff as Needed */
});

Then, as you need to create instances of your composite view in the ‘.lproj’ layer it would look something like this:

  aRealMasterView: myApp.MasterView.design({
    layout: { /* layout here */ },
    contentPath: 'myApp.myRecordsController.arrangedObjects',
    selectionPath: 'myApp.myRecordsController.selection',
    searchPath: 'myApp.myRecordsController.search',
    contentValueKey: 'name'
  })

Conclusion

Its as simple as this. Now you are able to pass your bindings around without creating superfluous bindings that have to be updated, but have no real using in your composite view layer. The ‘-Binding’ convention is a great convenience, but unless you specifically want to create a binding in that view layer it is easily misuse and can cause performance hits.

This entry was posted on Wednesday, July 29th, 2009 at 6:52 am and is filed under Best Practices, Coding Tutorials, Sproutcore. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

5 Responses to “Composite Views”

  1. It’s Got What Plants Crave » Blog Archive » Bindings Unleashed Says:

    [...] A further discussion of using this convention can be found in the discussion about composite views. [...]

  2. Fredrik W Says:

    This may be me not fully grasping the SproutCore internals, but how will this increase performance?

    All you’re doing is making the (name) coupling between views weaker (by passing it to the parent which is in turn responsible for creating its child views). The -Paths are only strings, so the bindings will be set up for each child view anyway, right? Or am I missing something here?

  3. Evin Says:

    @Fredrik W

    You’re right there is no magic here…it is just a naming convention. The convention is more for readability and to make sure you DON’T pass bindings around with the ‘-Binding’ convention which is a performance hit. ‘-Binding’ convention should ONLY be used when you are actually setting a binding up not to pass the string.

    The composite view is a the more important construct. This is very helpful when you have to make views that have popups or other special characteristics

  4. Suvajit Gupta Says:

    So how to enhance this to indicate what sort of binding to make from the path (e.g., oneWay)?

  5. Evin Says:

    @Suvajit Gupta:

    It acts exactly like a normal SC.Binding so you can pass a string or you can pass an SC.Binding protocol like:

     namePath: SC.Binding.from('myApp.myRecordController.name').oneWay()

    But you should probably do this at the internal to the view to for better control.

Leave a Reply