sproutcore/sproutcore — Issue #690: The Grand Re-unification
Author: publickeating
Created: 2012-01-16 19:31:00+00:00
State: open
Labels: proposal

In preparation for the upcoming discussions on the view layer, I wanted to collect and share some draft thoughts. These ideas aren't all fully explored by any means, so please take that into account.

# Background

I believe there are a lot of misconceptions, even among seasoned SproutCore developers, about the differences between SC.View and SC.TemplateView. The largest myth seems to be that they are irrevocably different and that you can't do what you can do with SC.View, using SC.TemplateView.

In actuality, SC.TemplateView and SC.View are not that different. Children of the same parent, SC.CoreView. So what don't they share? SC.TemplateView lacks any of the code in `core_foundation/views/view/` and SC.View obviously lacks the ability to layout views based on templates.

***

Let's look at what SC.TemplateView lacks first. First off, there is code in SC.View for changing the cursor style, accepting key events and accepting touch events. Should that code be added to SC.TemplateView? I believe it should **not be added** and **nor should it be in SC.View either**, since it is code specific to views that are also controls, not regular views. Alternatively, this code should be pulled out and mixed into views that are also controls. It would not matter if the views that mixed this code in were SC.View or SC.TemplateView subclasses. So this isn't a worthy difference.

Second, there is code in SC.View for dynamically adding or removing childViews. At first glance, this seems like an important distinction, but after searching the framework for views that actually use this, I found that maybe 10 did and of those, a few should not have been doing it and instead simply adding or removing DOM elements. This type of behaviour is necessary for collection and paging types of views, but rarely necessary in the other ~90%+ of views. Therefore, again, it probably shouldn't even be part of SC.View, but the important thing to remember is that SC.TemplateView has the same childViews, so it's a minor effort to add this code to SC.TemplateView as well. I've done it, I can do it again. What you can't do is, you can't find SC.TemplateView childViews by name, but this actually forces the developer to use bindings rather than hard coding paths to views.

Third, what about enabled and visible support? They can be added to SC.TemplateView, I believe without even changing the code. They probably weren't included in SC.CoreView, because it was questionable about the utility of that code being in every single view. This may be another debate, but definitely not an insurmountable difference between the two views. I'm actually preparing a separate proposal to add isEnabled to SC.CoreView directly (which simply adds the 'disabled' class to disabled views). Again, there is still nothing significantly unique to this code that keeps it out of SC.TemplateView except for the utility of the code.

Fourth, there is the layout and animation code. The utility of this code in SC.View is definitely debatable. Developers that use SC.TemplateView seem to manage perfectly well using CSS directly rather than the layout property. That said, it's still possible to simply add the layout code to SC.TemplateView. Where there would need to be a minor change, would be that the layout keyword would need to be recognized when used in the {{view}} helper so that it could be translated into the expected object.

Finally, there is the theming code, but I'll address that next, because that is related to the discussion on what SC.View lacks compared to SC.TemplateView. So from the SC.TemplateView side, I don't believe there is any code in SC.View that could not be applied either directly or with minor changes. In fact, if we simply added the layout support to SC.CoreView so that SC.TemplateView had it as well, SC.TemplateView would be indistinguishable from SC.View in the majority of use cases.

***

So what does SC.View lack compared to SC.TemplateView? Templates obviously. The SC.View means to describing a page, requires nesting childViews repeatedly in JavaScript. Ex.

myView1: SC.View.design({
childViews: ['myView2', 'myView3, 'myView4'],
layout: { //...
myView2: SC.LabelView.design({ // ...
layout: { // ...
myView3: SC.TextFieldView.design({ // ...
layout: { // ...
myView4: SC.View.design({
childViews: ['myView5', 'myView6'],
layout: { // ...
myView5: SC.View.design({
childViews: ['myView7'],
layout: { // ...
// ... and more

Of course, I've stripped lines and lines of code from the example that could be achieved with the following template:

{{loc myView2Label}}>
{{view SC.TextField}}

{{#view layerId="myView7"}}

But it's more than just that templates are easier to read when laying out a page, because there is no reason why you can't use SC.TemplateView in the same "nested childViews" style shown above. The real difference between the two comes down to how we write custom views. Here's the render delegate for SC.SliderView: https://github.com/sproutcore/sproutcore/blob/master/frameworks/desktop/render_delegates/slider.js

Here's the same code as a template:

Am I over-simplifying the template vs. the render/update method? No. The big difference is that THE TEMPLATE DESCRIBES WHAT IS BEING RENDERED, THE RENDER DELEGATE DOES NOT. Take a look at any of the render delegates in Desktop. They are useless at describing the HTML that they are tasked with generating and updating. How can someone write an update function without first running an app and inspecting the DOM to figure out what HTML was actually generated? This seems like a useless and harmful abstraction.

Anecdotally, I've spoken with developers that are afraid to write custom views, because they don't understand render/update and render delegates. Anedotally, I've encountered many custom views that were slow and inefficient, because the update functions were missing or poorly written. And on top of all that, using render delegates and theming is still a confusing nightmare and much too hard for new developers.

I believe these two styles are the only real difference between SC.View and SC.TemplateView and it is in the favour of SC.TemplateView.

Aside: custom render delegates is a bad idea! A lot of views expect a certain DOM layout and so a custom layout that doesn't match the original anyways, simply doesn't work.

***

I agree with some people's opinions that the framework should be opinionated about how to write views. Therefore, I propose that there is so little of importance that is different between SC.View and SC.TemplateView, that they should become a single view and that that view should be named, SC.View, but be based on SC.TemplateView instead. Don't get your hackles up, this simply means adding code from SC.View into SC.TemplateView so that it is **indistinguishable** in almost all usage. The code that should not be brought over into the **new** SC.View, is the code related strictly to controls and the render delegate code.

Theming should be achieved with a theme class name being applied to all views (exactly as it does in SC.View now), but if the developer wants to change the HTML output of a custom view, then drop-in templates would be used instead. This is still a bad idea as noted above, but that's a challenge for usability improvements to the Desktop framework.

***

What does this mean? It means that if your app uses only the "nested childViews" method of describing pages it should work without any changes and if your app uses all or a mixture of "templates" it should also work by changing all instances of the word "SC.TemplateView" to "SC.View". The only real work should be for the people that have actually written render and update functions. Fortunately, replacing render/update with a template is extremely easy and ends up with reduced code. For instance, a lof of SC.View childViews are simply wrappers used to generate a DIV element. (see the examples above)

***

If accepted, I volunteer to do this refactor. Again, I don't believe this effects any one's normal usage or coding style more than a minor bit and all for the positive. It is my hope that by uniting these two camps, we can end this confusion and progress a lot faster on other tasks.