In my previous post on how to start creating a custom view in SproutCore, I built a simple user summary view that displayed a name, a description and an age. After I added the post to my blog I got a lot of great response. Two of the responses I want to expand on.

The first response was from Evin where he mentioned that you don’t have to create an extra wrapping div for a view since you can just take advantage of the view’s inherit div that the render context supplies. So the code I originally had was the following:


MyApp.UserSummaryView = SC.View.extend({

  name: '',

  description: '',

  age: 0,

  displayProperties: ['name', 'description', 'age'],

  render: function(context, firstTime) {
    var name = this.get('name');
    var description = this.get('description');
    var age = this.get('age');

    context = context.begin('div').addClass('user-summary-view');
    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();
    context = context.end();

    sc_super();
  }

});

The lines in bold above are where I added an extra wrapping div. We can remove those two lines and modify the view’s classNames property to include user-summary-view. So the updated view now is the following:


MyApp.UserSummaryView = SC.View.extend({

  classNames: ['user-summary-view'],

  name: '',

  description: '',

  age: 0,

  displayProperties: ['name', 'description', 'age'],

  render: function(context, firstTime) {
    var name = this.get('name');
    var description = this.get('description');
    var age = this.get('age');

    context = context.begin('div').addClass('user-summary-view-name').push(name).end();
    context = context.begin('div').addClass('user-summary-view-desc').push(description).end();
    context = context.begin('div').addClass('user-summary-view-age');
    context = context.begin('div').addClass('user-summary-view-age-value').push(age).end();
    context = context.begin('div').addClass('user-summary-view-age-capt').push('age').end();
    context = context.end();
    
    sc_super();
  }

});

This simplifies things for us. So remember that the context object given to you in the render method is acting on the view’s inherit div outer element. Also note that div is a view’s default outer element. If you need the view’s container element to be something else you can modify it by setting the view’s tagName property, such as tagName: 'h1'.

Now on to the second response from Joshua where he explained why I wasn’t getting the view to update after I would modify the view’s property in the JavaScript console, such as when you type myView.set('name', 'foo'). By setting a view’s property with just the set() method you are not invoking SproutCore’s run loop mechanism. Joshua noted that in order to make sure view does update correctly you have to use the run loop’s begin() and end() method. So if you run the SproutCore application again and open up a interactive JavaScript console you would first enter the following:

SC.RunLoop.begin()

You would then go ahead and modify the view’s properties in the console like so:

view.set('name', 'John Doe') // var view = MyApp.mainPage.mainPane.userSummaryView
view.set('description', 'some text goes here')
view.set('age', 45)

Once entered you then finish by entering the following:

SC.RunLoop.end()

The last statement then invokes the run loop to tell view to update, and the view will pick up on the changes you made. Go ahead and give it a try.

Joshua also mentioned the alternative to invoking the run loop by calling the SC.run() method. So if you wanted to modify the property name you would do the following in the JavaScript console:

SC.run(function() { view.set('name', 'John Doe') })

Note how you have to pass in an anonymous function to the run() method. The run() method is mainly intended for testing purposes.

Thanks to Evin, Joshua and everyone else for great feedback!

Advertisements