2
votes

I've got an app with basic functionality built out. I'm not going through and adding additional features. In this case I need to convert a simple button, currently using linkTo, to a View. Problem is that I'm not sure how to convert one to the other and still keep the link intact.

How do I do this conversion? Here's the code I have now:

<script type="text/x-handlebars" data-template-name="accountItem">
{{#each account in controller}}
    {{#linkTo "account" account}}
        <img {{bindAttr src="account.icon"}} />
    {{/linkTo}}
{{/each}}
</script>

and here's the code I'm going to have:

<script type="text/x-handlebars" data-template-name="accountItem">
{{#each account in controller}}
    {{#view "Social.AccountButtonView"}}
        <img {{bindAttr src="account.icon"}} />
    {{/view}}
{{/each}}
</script>

Social.AccountButtonView = Ember.View.extend({
    tagName: 'a',
    classNames: ['item-account'],
    click: function(){
        // do something
    }
});

I would assume that I'd be building on top of the click handler in the View, but I'm not sure how to pass the reference to item being iterated over, nor how to reference the correct route within the View.

Assistance please?

Update 1

The first version renders an href attribute with a value of #/accounts/4 based on the Router I have set up:

Social.Router.map(function() {
    this.resource('accounts', function(){
        this.resource('account', { path: ':account_id'});
    });
});

When I convert the current code to a view, how do I mimic the functionality that linkTo provides?

1

1 Answers

1
votes

You can define a property binding for account in your handlebars template. This binding works like this:

<script type="text/x-handlebars">
    <h1>App</h1> 
    {{#each item in controller}}
        {{#view App.AccountView accountBinding="item"}}
            <a {{bindAttr href="view.account.url"}} target="_blank">
                {{view.account.name}}
            </a>
        {{/view}}
    {{/each}}
</script>

Note that I added accountBinding, so the general rule is propertyName and Binding as a suffix. And remember that when you add a property to a view, you will not be able to access it directly, instead you will have to access it with view.propertyName as shown above.

Just keep in mind that you must have a View class when using the {{view}} helper:

window.App = Em.Application.create();
App.AccountView = Em.View.extend(); // this must exist
App.ApplicationRoute = Em.Route.extend({
    model: function() {
        return [
            {id: 1, name: 'Ember.js', url: 'http://emberjs.com'}, 
            {id: 2, name: 'Toronto Ember.js', url: 'http://torontoemberjs.com'}, 
            {id: 3, name: 'JS Fiddle', url: 'http://jsfiddle.com'}];    
    }
})

Working fiddle: http://jsfiddle.net/schawaska/PFxHx/

In Response to Update 1:

I found myself in a similar scenario, and ended up creating a child view to mimic the {{linkTo}} helper. I don't really know/think it's the best implementation tho. You can see my previous code here: http://jsfiddle.net/schawaska/SqhJB/

At that time I had created a child view within the ApplicationView:

App.ApplicationView = Em.View.extend({
  templateName: 'application',
  NavbarView: Em.View.extend({
    init: function() {
      this._super();
      this.set('controller', this.get('parentView.controller').controllerFor('navbar'))
    },
    selectedRouteName: 'home',
    gotoRoute: function(e) {
      this.set('selectedRouteName', e.routeName);
      this.get('controller.target.router').transitionTo(e.routePath);
    },
    templateName: 'navbar',
    MenuItemView: Em.View.extend({
      templateName:'menu-item',
      tagName: 'li',
      classNameBindings: 'IsActive:active'.w(),
      IsActive: function() {
        return this.get('item.routeName') === this.get('parentView.selectedRouteName');
      }.property('item', 'parentView.selectedRouteName')
    })
  })
});

and my Handlebars looks like this:

<script type="text/x-handlebars" data-template-name="menu-item">
  <a {{action gotoRoute item on="click" target="view.parentView"}}>
  {{item.displayText}}
  </a>
</script>

<script type="text/x-handlebars" data-template-name="navbar">
  <ul class="left">
    {{#each item in controller}}
      {{view view.MenuItemView itemBinding="item"}}
    {{/each}}
  </ul>
</script>

I'm sorry I can't give you a better answer. This is what I could come up with at the time and haven't touched it ever since. Like I said, I don't think this is the way to handle it. If you are willing to take a look into the {{linkTo}} helper source code, you'll see a modular and elegant implementation that could be the base of your own implementation. I guess the part you're looking for is the href property which is being defined like so:

var LinkView = Em.View.extend({
...
    attributeBindings: ['href', 'title'],   
    ... 
    href: Ember.computed(function() {
      var router = this.get('router');
      return router.generate.apply(router, args(this, router));
    })
...
});

So I guess, from there you can understand how it works and implement something on your own. Let me know if that helps.