I have an issue with Bootstrap panels with AngularJS. I'm not able align correctly my panels. I want to display my panels into 2 columns.

I have the following HTML code:

<div class="row">
  <div class="col-lg-3 col-sm-3 col-xs-3">
    <span>Some stuffs</span>
  </div>
  <div class="col-lg-9 col-sm-9 col-xs-9">
    <div class="row">
       <div class="col-lg-6 col-sm-6 col-xs-6"
            ng-repeat="i in items">
         <div  class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">{{i.title}}</h3>
          </div>
          <div class="panel-body">
            {{i.content}}
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Basic case: Let's say, I have 3 items. The 2 first items will be displayed in the first row. - item1: row0/col0 - item2: row0/col1 The last item should be displayed in the 2nd row and first column - item3: row1/col0

It works fine when the height of the panels are the same.

My use case: My panel content can be different from each other. So, when my first panel content is bigger than the others, the third item goes to the col1. - item3: row1/col1

It leaves a big space and then if I want to add a 4th item...it becomes ugly :(

I've created a demo showing the issue: http://plnkr.co/edit/TZDck5b9G9Ap32KlPk4q?p=preview

Thanks in advance

NB: uploading images are not allowed with credit less than 10...so my apologies...

3 Answers

0
Exlord On
<div ng-repeat="..." ng-class="{clear_right:$odd}">
    //your panel content here   
</div>

.clear_right{clear:right;}
.clear_right:after{content:" ";display:block;}
1
Christina On

The only solution I can think of to correctly display the 3rd div regardless of its size is to use one row for the first 2 divs and another for the next 2 (and so on and so forth). You can do this by putting the ng-repeat iteration outside the row div and assigning the row class conditionally when the iteration is on an add element.

<div ng-repeat="i in items">
    <div ng-if="$even" class="row">
      <div class="col-lg-6 col-sm-6 col-xs-6">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">{{i.title}}</h3>
          </div>
          <div class="panel-body">
            {{i.content}}
          </div>
        </div>
      </div>
      <div class="col-lg-6 col-sm-6 col-xs-6" ng-if="items[$index + 1]">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">{{items[$index + 1].title}}</h3>
          </div>
          <div class="panel-body">
            {{items[$index + 1].content}}
          </div>
        </div>
      </div>
    </div>
</div>

The downside is of course that you are duplicating the markup for the column (the one that shows the actual pannel), which can be avoided if you create a directive for this part. I get that Exlord's solution is simpler, however I have the feeling that this is closer to the Angular / Bootstrap way, since otherwise you are effectively overriding Bootstrap's row system by "forcing" the row's columns to break in more than one row (using clear:right).

See updated plunkr here: http://plnkr.co/edit/7KMZdzcpR7Ff2D6pExVB?p=preview

0
Krolock On

@Christina: Nice solution, but you lost your scope. In my complex template html I need access to the parent scope. I changed the directive to building a new scope that inherits from the parent, see the plunker fork http://plnkr.co/edit/CCwbnZCE7e8ej2fFBi2e?p=preview

app.directive('panelContent', function(){
 return {
  restrict: 'E',
  scope: true,
  templateUrl: 'panel-content.html',
  link: function(scope, element, attributes){
    scope.item = scope.$eval(attributes["item"]);
  }
 };
})

Update 03.06.15:

The {{$index +1}} solution will cause problems if you add or remove items. In this case anguluar gets problem with data-binding and does not update the view to the modified collection.

Now I solved the problem with a

   <div ng-if="$even" style="clear: both;"></div> 

in the ng-repeat block

 <div ng-repeat="item in myItems">
      <div ng-if="$even" style="clear: both;"></div>
      <item-content /> <!-- directive that adds the content for each item ( or direct html if you want)-->
 </div>