2

I am currently working on a search bar that lists three types of objects: users, records and locations. Each has its own model and such defined, with corresponding controllers. What I need to do is to check which type of object it is because I need the HTML that renders with it to be different.

{{#each mainUserSearchResults}}
              {{#link-to 'user' this.userID}}

                <div class="row mainListSeperator" {{action "getapplicantUserID" this target="view"}}>
                  <img class="applicantsIcon" src="">
                  <div class="applicantsName">
                    {{unbound this.firstName}}&nbsp;{{unbound this.lastName}}
                  </div>
                  <div class="applicantsTitle">
                    User
                  </div>
                </div>

              {{/link-to}}
            {{/each}}

The only issue I am having is that I need it to print this.firstName & this.lastName if it is a user, but I cannot do that for records. For records, I would have to render another property - this.recordID - in the same manner as I did this.firstName. The way to do this would be an if conditional, but I cannot find anything in HandleBars that allows me to check whether the data coming in from mainUserSearchResults is a user or a record.

The mainUserSearchResults is a property in my controller that returns an array of objects: currently it return a concatenated array of user objects and record objects.

Darshan
  • 827
  • 2
  • 13
  • 26

2 Answers2

0

Assuming there is some way to easily distinguish between the 2+ types of objects, you can use an if statement and render a different template (or even use a different partial, http://emberjs.com/guides/templates/rendering-with-helpers/)

  <script type="text/x-handlebars" data-template-name="index">
    <ul>
    {{#each item in model}}
    <li>

    {{#if item.foo}}
      {{render 'foo' item}}
    {{/if}}

    {{#if item.cow}}
      {{render 'cow' item}}
    {{/if}}
    </li>

    {{/each}}
    </ul>
  </script>


  <script type="text/x-handlebars" data-template-name="foo">
    I'm a foo: {{foo}}
  </script>

  <script type="text/x-handlebars" data-template-name="cow">
    I'm a cow: {{cow}}
  </script>

http://emberjs.jsbin.com/qinilege/1/edit

Or if you need more advanced checking you can use an item controller and add the logic in there

{{#each item in model itemController='checker'}}
  <li>

  {{#if item.isFooBar}}
    {{render 'foo' item.model}}
  {{/if}}

  {{#if item.isFooBaz}}
    {{render 'fooz' item.model}}
  {{/if}}


  {{#if item.isCow}}
    {{render 'cow' item.model}}
  {{/if}}
  </li>
{{/each}}


App.CheckerController = Em.ObjectController.extend({
  isFooBar: Ember.computed.equal('foo', 'bar'),
  isCow: Ember.computed.notEmpty('cow'),
  isFooBaz: Ember.computed.equal('foo', 'baz')
});

http://emberjs.jsbin.com/qinilege/2/edit

Kingpin2k
  • 47,007
  • 10
  • 75
  • 96
0

Handlebars is a logicless template, so you really can't perform computations, like type-checking. There are some pretty good reasons for this. If it were me, I'd push that responsibility elsewhere, probably all the way to your model, for two reasons:

  1. Any conditionals you put in the DOM are SLOW. The problem only gets compounded when you're on slow devices (most notably, mobile).
  2. Every time you add a new searchable thing, you're going to have to update your templates. Over time, you'll end up with:

    {{#if ...}}
      ...
    {{/if}}
    
    {{#if ...}}
      ...
    {{/if}}
    
    {{#if ...}}
      ...
    {{/if}}
    
    {{#if ...}}
      ...
    {{/if}}
    

Delegate instead. For example, in your User model, add

formattedName: (function() {
  return [this.get('firstName'), this.get('lastName')].join(' ');
}).property('firstName', 'lastName')

Do the same for your records and locations.

Then, change your template from

{{unbound this.firstName}}&nbsp;{{unbound this.lastName}}

to

{{unbound this.formattedName}}

Now, if you add new types to your searches, you have a completely generic solution that only needs the model to implement the formattedName property.

Some would would say my suggestion is a bad one, because it mixes the business-logic responsibility of a model with display logic. In this case, I'm guessing you're displaying {{firstName}} {{lastName}} in more than one place, so I think the benefits of keeping your code DRY outweigh moving this to, e.g., a controller. Your call.

Community
  • 1
  • 1
Travis
  • 1,353
  • 10
  • 12
  • Thank you very much! I sort of get the hesitancy of mixing business and display logic, and it bothers me as well that the formattedName Property needs to be extra, but it seems to work effortlessly. At least for now, this has been the most efficient way for me to do this. – Darshan Jun 25 '14 at 16:37