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.
July 30th, 2009 at 6:25 am
[...] A further discussion of using this convention can be found in the discussion about composite views. [...]
July 30th, 2009 at 4:28 pm
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?
July 31st, 2009 at 5:49 am
@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
August 3rd, 2009 at 11:38 am
So how to enhance this to indicate what sort of binding to make from the path (e.g., oneWay)?
August 3rd, 2009 at 2:46 pm
@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:
But you should probably do this at the internal to the view to for better control.