commadelimited
commadelimited

Reputation: 5119

Triggering the display of a View from within a template

In my application I display a list of accounts like so:

<script type="text/x-handlebars" data-template-name="accounts">
{{#each account in controller}}
    {{#linkTo "account" account class="item-account"}}
        <div>
            <p>{{account.name}}</p>
            <p>@{{account.username}}</p>
            <i class="settings" {{ action "openPanel" account }}></i>
        </div>
    {{/linkTo}}
{{/each}}
</script>

Each account has a button which allows users to open a settings panel containing settings just for that account. as you can see in this quick screencast:

http://screencast.com/t/tDlyMud7Yb7e

I'm currently triggering the opening of the panel from within a method located on the AccountsController:

Social.AccountsController = Ember.ArrayController.extend({
    openPanel: function(account){
        console.log('trigger the panel');
    }
});

But I feel that it's more appropriate to open the panel from within a View that I've defined for this purpose. This would give me access to the View so that I can perform manipulations on the DOM contained within it.

Social.MainPanelView = Ember.View.extend({
    id: 'panel-account-settings',
    classNames: ['panel', 'closed'],
    templateName: 'mainPanel',
    openPanel: function(){
        console.log('opening the panel');
    }
});

<script type="text/x-handlebars" data-template-name="mainPanel">
    <div id="panel-account-settings" class="panel closed">
        <div class="panel-inner">
            <a href="#" class="button button-close"><i class="icon-cancel"></i>close</a>
            <h3>Account Settings</h3>
            <a href="/accounts/social/connections/" class="button button-disconnect">Disconnect Account</a>
        </div>
    </div>
</script>

The problem I'm encountering is that I don't see how I can trigger a method on the Social.MainPanelView from the context of the AccountsController. Is there a better solution?

UPDATE 1

I've worked up a Fiddle to illustrate what I'm talking about:

http://jsfiddle.net/UCN6m/

You can see that when you click the button it calls the showPanel method found on App.IndexController. But I want to be able to call the showPanel method found on App.SomeView instead.

Upvotes: 1

Views: 193

Answers (2)

Mudassir Ali
Mudassir Ali

Reputation: 8041

Update:

Approach One:

Simplest of all

Social.AccountsController = Ember.ArrayController.extend({
  openPanel: function(account){
    /* we can get the instance of a view, given it's id using Ember.View.views Hash
       once we get the view instance we can call the required method as follows
    */
    Ember.View.views['panel-account-settings'].openPanel();
  }
});

Fiddle

Approach Two:(Associating a controller, Much Cleaner)

Using the Handlebars render helper: what this helper does is it associates a controller to the view to be displayed, so that we can handle all our logic related to the view in this controller, The difference is

 {{partial "myPartial"}}

just renders the view, while

{{render "myPartial"}}

associates App.MyPartialController for the rendered view besides rendering the view, Fiddle

now you can update your code as follows

application.handlebars(The place you want to render the view)

{{render "mainPanel"}}

accounts controller

Social.AccountsController = Ember.ArrayController.extend({
  openPanel: function(account){
    this.controllerFor("mainPanel").openPanel();
  }
});

main panel view

Social.MainPanelView = Ember.View.extend({
  id: 'panel-account-settings',
  classNames: ['panel', 'closed']
});

main panel controller

Social.MainPanelController = Ember.Controller.extend({
  openPanel: function(){
    console.log('opening the panel');
  }
})


Approach Three: This one is the manual way of accomplishing Approach Two

Social.MainPanelView = Ember.View.extend({
  id: 'panel-account-settings',
  controllerBinding: 'Social.MainPanelController',
  classNames: ['panel', 'closed'],
  templateName: 'mainPanel'
});

Social.MainPanelController = Ember.Controller.extend({
  openPanel: function(){
    console.log('opening the panel');
  }
})

use this.controllerFor("mainPanel").openPanel()

Upvotes: 1

buuda
buuda

Reputation: 1427

You need to use the action helper rather than directly coding the links. The action helper targets the controller by default, but you can change it to target the view instead:

<a {{action openPanel target="view"}}></a>

Your second link should be a linkTo a route, since you are specifying a link to another resource. The whole snippet, revised:

Social.MainPanelView = Ember.View.extend({
    id: 'panel-account-settings',
    classNames: ['panel', 'closed'],
    templateName: 'mainPanel',
    openPanel: function(){
        console.log('opening the panel');
    }
});

<script type="text/x-handlebars" data-template-name="mainPanel">
    <div id="panel-account-settings" class="panel closed">
        <div class="panel-inner">
            <a {{action openPanel target="view"} class="button button-close"><i class="icon-cancel"></a></i>
            <h3>Account Settings</h3>
            {{#linkTo "connections"}}Disconnect Account{{/linkTo}}
        </div>
    </div>
</script>

Upvotes: 1

Related Questions