Reputation: 2169
I'm building an app with Bootstrap and AngularJS. At some point I have an ng-repeat on a col-md-3, listing products. My problem is that I want to be able to insert a collapse into the grid, but as the columns are automatically generated, I don't really know how to do it.
Here's a diagram to understand it better: First, the grid of .col-md-3 is populated from the ng-repeat.
And what I'm trying to achieve, is to add a .col-md-12 that appears right under the row of the .col-md-3 that gets clicked on.
My initial thought was to add an empty .col-md-12 dynamically after each group of 4 .col-md-3, but I wouldn't know how to do so, and it kinda seems to be that it would be a rather dull approach. Any ideas?
Here's the relevant html:
<div class="infinite" infinite-scroll="loadDetails()">
<div class="col-xs-3 col-md-3" ng-repeat="release in main.releases | filter:main.album">
<release release="release" artist="main.artist" class="dropdown"></release>
</div>
</div>
EDIT: Here's a working Plunker including tasseKATTs solution.
Upvotes: 1
Views: 2610
Reputation: 9497
This question is easier to answer in an angular way if you follow the bootstrap convention using 12 columns per a row:
Grid columns are created by specifying the number of twelve available columns you wish to span. For example, three equal columns would use three .col-xs-4.
In your case, this means each row can have up to 4 .col-xs-3
columns, or just 1 .col-xs-12
. You can prep your data to be displayed this way by splitting it into an array of smaller arrays.
$scope.getRows = function(array) {
var rows = [];
//https://stackoverflow.com/questions/8495687/split-array-into-chunks
var i,j,temparray,chunk = 4;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
rows.push(temparray);
}
return rows;
};
$scope.rows = $scope.getRows($scope.main.releases);
Then you can nest ngRepeat
to achieve the desired layout, using ng-if
to only create a col-xs-12
when a corresponding .col-xs-3
is clicked.
<div ng-repeat="row in rows">
<div class="row">
<div class="col-xs-3" ng-repeat="release in row" ng-click="main.releaseClicked=release">
<div class="release">{{release}}</div>
</div>
</div>
<div class="row" ng-repeat="release in row" ng-if="main.releaseClicked==release">
<div class="col-xs-12">
<div class="detail">Release detail: {{release}}</div>
</div>
</div>
</div>
This leaves you with a more declarative view that describes how the app works, and doesn't require jQuery to do DOM manipulation.
Here is a working demo: http://plnkr.co/ujlpq5iaX413fThbocSj
Upvotes: 2
Reputation: 38490
Place a custom directive on your inner element together with a position counter that starts with 1 and a marker describing if it's the last element:
<div ng-repeat="item in items" class="col-xs-3">
<div class="item" the-directive position="{{ $index + 1 }}" last="{{ $last }}">
</div>
</div>
Create the directive with an isolated scope, bind scope properties to the values of the position and last attributes and attach a click event handler to the element:
app.directive('theDirective', function() {
return {
restrict: 'A',
scope: { position: '@', last: '@' },
link: function(scope, element, attrs) {
element.bind('click', function() {
...
});
}
};
});
In the click handler first create the collapse element or select it if it already exists:
var collapseQuery = document.querySelector('#collapse');
var collapse = collapseQuery === null ?
angular.element('<div id="collapse" class="col-xs-12"><div class="twelve"></div></div>') :
angular.element(collapseQuery);
Based on the position of the clicked element calculate the rounded number up to the nearest multiple of four:
var calculatedPosition = Math.ceil(scope.position / 4) * 4;
Get the element at the calculated position or the last one if the position is out of range:
var calculatedQuery = document.querySelector('[position="' + calculatedPosition + '"]');
if (calculatedQuery === null) calculatedQuery = document.querySelector('[last="true"]');;
var calculatedElement = angular.element(calculatedQuery);
Insert the collapse element after the element at the calculated position:
calculatedElement.parent().after(collapse);
Could use some optimizations, but hopefully puts you on the right track.
Demo with some extra visuals: http://plnkr.co/edit/fsC51vS7Ily3X3CVmxSZ?p=preview
Upvotes: 3