Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Replacing Subviews - Absolutely Lost
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Tom Dale  
View profile  
 More options Mar 31 2010, 12:32 pm
From: Tom Dale <sproutc...@tomdale.net>
Date: Wed, 31 Mar 2010 09:32:33 -0700
Local: Wed, Mar 31 2010 12:32 pm
Subject: Re: [sproutcore] Replacing Subviews - Absolutely Lost

Dear Mr. Palindrome,

Please don't be embarrassed, as this was difficult for me when starting SproutCore as well.

I'd like to tackle this problem by discussing two broad concepts, so please bear with me.

The first is that we must differentiate between instances and classes. I presume that in the JavaScript that defines your custom views, you are using the extend or design methods to describe the UI.

For example, your code probably looks something like:
MyApp.CustomView = SC.View.extend({
  childViews: 'countView labelView'.w(),
  layout: { width: 300 }

});

That gives us a class for the view, not an actual instance of it. To use this custom view in the view hierarchy, we have to create an instance of it.

Now you might be thinking: "Instantiating and managing all of those views sounds like a pain in the ass." And you would be right if you had to do it yourself.

Fortunately, there exists the elegant (if strangely named) SC.Page class.

In a nutshell, an instance of SC.Page will dynamically instantiate views as they are needed, deferring the CPU and memory hit of instantiation until the very last moment possible. Here's how it does it:
1. You call get() on your page.
2. SC.Page overrides the get() method.
3. The Page version of get() retrieves the given property.
4. It checks to see if the property is an instance or a class.
5. If it is an instance, it returns the stored value. Otherwise…
6. It creates an instance of that class and replaces its own property with the instance.

The next time you call get(), it will return the same instance that it created the first time, so you're always dealing with the same object. Pretty neat, huh?

Now, the next concept to understand: SC.ContainerView.

As you've already discovered, SC.ContainerView has a property called nowShowing. When nowShowing changes, the ContainerView will replace its child view with whatever you pass in.

nowShowing can be either an SC.View or a string. Setting an SC.View is straightforward but boring; I presume the reason it didn't work for you was that it was probably handed a class instead of an instance.

More interestingly, you can also set nowShowing to a string. ContainerView will automatically evaluate that string when it changes. It supports your standard property path, so you can pass something like 'MyApp.viewsController.customView' and it will convert that to an object at runtime.

A quick aside about SC.Page: Any views instantiated from a Page have a property called page. Therefore, any view can reference the page by which it was created.

ContainerView leverages this by allowing you to set the nowShowing property to the name of another view that belongs to the same page.

What I like to do in my apps is define my mainPane in my mainPage. Usually that mainPane will have at least one container view. I then define any views I want to swap out as properties of the mainPage. Here's an example from a Twitter client I'm planning to release as sample code:

MyApp.mainPage = SC.Page.design({
  mainPane: SC.MainPane.design({
    childViews: 'contentView'.w(),

    contentView: SC.ContainerView.design({
      layout: { top: 70 }
    })
  }),

  loadingView: SC.View.design({
    childViews: 'spinner label'.w(),

    spinner: SC.ImageView.design({
      layout: { width: 32, height: 32, centerY: 0, centerX: -155 },
      value: sc_static('images/loading_large')
    }),

    label: SC.LabelView.design({
      layout: { height: 34, width: 280, centerY: 0, centerX: 20 },
      classNames: ['loading-label'],
      controlSize: SC.HUGE_CONTROL_SIZE,

      value: '_Loading Timeline…',
      localize: YES
    })
  })

});

If I set the nowShowing property of mainPage.mainPane.contentView to the string "loadingView", it will ask its page object for the property loadingView, see that it is a class, instantiate it, and replace its contents with the contents of the loadingView.

Anyway, this can be tricky because it is non-obvious, but once you figure it out I think you'll see that it's really quite powerful stuff! Hope that helped.

-Tom

On Mar 31, 2010, at 7:40 AM, BinaryPalindrome wrote:

> It would seem to be quite basic, and I have to admit to some
> embarrassment at my confusion, but I'm struggling to figure out how to
> work with replacing sub/child views. The tutorials I've been able to
> find do a great job of detailing how one goes about creating an
> effectively static page, with predefined views and child views, but
> I've not been able to find anything that speaks to my difficulty.

> Let's say that I want to have my application start up with a basic
> layout. Nothing visible save for a toolbar with buttons and an empty
> content area. I can get that going just fine.

> Depending upon what a user clicks on, there are a number of different
> views that should appear in the content area. (Ideally, the code for
> these views wouldn't load from the server until the first time they're
> used; but that's a question I'll have to figure out later) Within each
> of those potential views, there could be other user actions that could
> load yet other views as children. And so on - all in all, just a
> description of how a typical application works.

> I'm lost at loading a view as a child of an existing view based on a
> user action (in this case, clicking a toolbar button). Here's what
> I've attempted.

> After a number of dead ends and apparent mistakes, I set up a main
> view area using a ContainerView. I've tried to set the nowShowing
> property to a value ("Todos.TestView", which I've created in the views
> folder). This hasn't gotten me anything. No change, except that when I
> echo the value of the ContainerView's nowShowing property, it shows
> Todos.TestView.

> So how does one go about replacing/showing a new child view?

> --
> You received this message because you are subscribed to the Google Groups "SproutCore" group.
> To post to this group, send email to sproutcore@googlegroups.com.
> To unsubscribe from this group, send email to sproutcore+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sproutcore?hl=en.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.