Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render a (Twitter Bootstrap) grid using Ember.js and Handlebars.js?

I’m having a hard time figuring a way to render the following markup using Ember.Handlebars:

<div class="row-fluid">
  <div class="span4">Item #1 (row #1 / column #1)</div>
  <div class="span4">Item #2 (row #1 / column #2)</div>
  <div class="span4">Item #3 (row #1 / column #3)</div>
</div>
<div class="row-fluid">
  <div class="span4">Item #4 (row #2 / column #1)</div>
  <div class="span4">Item #5 (row #2 / column #2)</div>
  <div class="span4">Item #6 (row #2 / column #3)</div>
</div>
<div class="row-fluid">
  <div class="span4">Item #7 (row #3 / column #1)</div>
</div>

Using pure JavaScript, I’d have done something like this:

var array = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7'],
    output = '<div class="row-fluid">';

for (var i = 0, j = array.length; i < j; i++) {
  output += '<div class="span4">' + i + '</div>';

  if ((i + 1) % 3 == 0) {
    output += '</div><div class="row-fluid">';
  }
}

output += '</div>';

Ideally, I’d put this in a custom Handlebars helper (thus removing the logic from the template) but Ember documentation only explains how to write simple helpers and I really don’t know how to write a more complex block helper without losing the property bindings.

Does anyone know the best way to use Twitter Bootstrap’s grid system with a collection of Ember models?

Thank you in advance! Best regards,

David

like image 417
davidg Avatar asked Apr 22 '13 20:04

davidg


2 Answers

G'day Dave

Instead of useing rows and div to make a block grid try using an "unordered list"

The HTML

<ul class="row-fluid block-grid-3">
  <li>Item #1 (row #1 / column #1)</li>
  <li>Item #2 (row #1 / column #2)</li>
  <li>Item #3 (row #1 / column #3)</li>
  <li>Item #4 (row #2 / column #1)</li>
  <li>Item #5 (row #2 / column #2)</li>
  <li>Item #6 (row #2 / column #3)</li>
  <li>Item #7 (row #3 / column #1)</li>
</ul>

Then the CSS would look like this.

ul.block-grid-3 {
   display: block;
   overflow: hidden;
   padding: 0;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
}
ul.block-grid-3 > li {
   width: 33.33333%;
   float: left;
   padding: 0 12px 12px;
   display: block;
   height: auto;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
}
ul.block-grid-3 > li:nth-of-type(3n+1) {
   clear: left;
}

Then if you wanted to change to four blocks you can can change the css to:

ul.block-grid-4 > li {
   width: 25%;
   float: left;
   padding: 0 12px 12px;
   display: block;
   height: auto;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
}  
ul.block-grid-4 > li:nth-of-type(4n+1) {
   clear: left;
}

jsfiddle example a more robust solution.

You can also check out this ember app Open-pos the products are layout using this method.

Zurb's css framework "foundation" as great solution called block-grid. This there system it is super easy to change the 3 up grid other number with just a small change in the css. you could drop in the block grid code into your bootstrap scss. If you have any questions let me know.

Cheers

like image 149
kiwiupover Avatar answered Nov 01 '22 13:11

kiwiupover


For those interested, here is a pretty clean way to handle this scenario.

Here is the template:

{{#each post in posts}}
  {{#if post.first}}
    <div class="row-fluid">
  {{/if}}
    <div class="span4">
      <div class="post">
        {{post.title}}
      </div>
    </div>
  {{#if post.lastOfRow}}
    </div>
    <div class="row-fluid">
  {{/if}}
  {{#if post.last}}
    </div>
  {{/if}}
{{/each}}

And the corresponding controller:

App.PostsController = Ember.ArrayController.extend({
  posts: function () {
    var length = this.get('length');

    return this.map(function (post, i) {
      // Checks if it’s the last post
      if ((i + 1) == length) {
        post.last = true;
      } else {
        post.last = false;

        // Checks if it’s the first post
        if (i == 0) {
          post.first = true;
        } else {
          post.first = false;
        }

        // Checks if it’s the last post of a row
        if ((i + 1) % 3 == 0) {
          post.lastOfRow = true;
        } else {
          post.lastOfRow = false;
        }
      }

      return post;
    });
  }.property('content.@each')
});

This may also be useful to generate tables (with <td> nested in <tr>)… Even though I ended up using kiwiupover’s solution! ;-)

Regards,

D.

like image 43
davidg Avatar answered Nov 01 '22 12:11

davidg