-
-
Save mbemowski/3737358 to your computer and use it in GitHub Desktop.
Angular Grid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Grid directive for angularJS, based on dalcib's Angular Grid https://gist.github.com/2630138 | |
* It's events are more angular-style and it operates on special object NavigationVector. It allows | |
* to select a row and to add custom rows at the bottom (for example to notify, that there are no rows found) | |
* When creating NavigationVector object you should pass the scope in which it will be declared in order | |
* to properly bind $watch expressions. Thanks to this you will be able to update index, selected or even | |
* items properties and other properties will be updated to match the change you made. | |
* | |
* Example: | |
<table ng-grid="" width="100%"> | |
<tr ng-repeat="emp in empNavigation.items"> | |
<td title="Surname">{{emp.surname}}</td> | |
<td title="Name">{{emp.name}}</td> | |
<td title="Second name">{{emp.secondName}}</td> | |
</tr> | |
<tr> | |
<td ng-show="empNavigation.items.length==0" colspan="3" style="text-align: center;">No employees found.</td> | |
</tr> | |
</table> | |
*/ | |
(function(angular) { | |
angular.module('ui.filters').filter('skip', function() { | |
return function(array, skipAt) { | |
return array.slice(skipAt); | |
}; | |
}); | |
angular.module('ui.directives').directive('ngGrid', function($filter) { | |
return { | |
compile: function compile(tElement, tAttrs) { | |
//HEADER | |
var header = angular.element('<thead><tr></tr></thead>'), | |
headerRow = header.children('tr'), | |
tr = $(tElement.children('tbody').children('tr')[0]), | |
expa = tr.attr('ng-repeat'); | |
navigationVectorName = expa.match(/^\s*(.+)\s+in\s+(.*)\.(.*)\s*$/)[2]; | |
tr.attr('ng-repeat', expa + '| skip:ngGridSortPagination.skipAt | limitTo:ngGridSortPagination.limit'); | |
tr.attr('ng-class',"$gridSelectedClass(emp)"); | |
tr.attr('ng-click',"$gridSelect(emp)"); | |
var count = 0; | |
angular.forEach(tr.children('td'), function(elm) { | |
var column = angular.element(elm), | |
expc = column.html(), | |
exp = expc.replace(/[{}\s]/g, ""), | |
name = exp.split(/\.(.+)?/)[1] ? exp.split(/\.(.+)?/)[1].split(/\|/)[0] : exp, | |
filter = exp.split(/\.(.+)?/)[1] ? exp.split(/\.(.+)?/)[1].split(/\|/)[1] : exp, | |
filterAttrib = (!filter) ? "" : ' filter="' + filter + '"', | |
title = column.attr('title') || name, | |
width = column.attr('width') || 100; | |
headerRow.append('<th name="' + name + '"' + filterAttrib + '" style="cursor: pointer;width: ' + width + 'px; font-weight:bold"><span style="display:inline-block"> </span>' + title + '</th>'); | |
column.addClass('ui-widget-content'); | |
column.attr('title', null); | |
count++; | |
}); | |
// tElement.addClass('ui-widget'); | |
tElement.prepend(header); | |
//PAGINATION | |
var footer = '<tfoot class="ui-state-default"><tr><td align="center" colspan="'+count+'"><span style="cursor: pointer; display:inline-block; margin: 0 5px; vertical-align:middle" class="ui-icon ui-icon-seek-first" ng-class="$gridPrevClass()" ng-click="ngGridSortPagination.page=1"></span><span style="cursor: pointer; display:inline-block; margin: 0 5px; vertical-align:middle" class="ui-icon ui-icon-seek-prev" ng-class="$gridPrevClass()" ng-click="ngGridSortPagination.page=ngGridSortPagination.page-1"></span><span style="display:inline-block; margin:0 5px;" class="ui-state-disabled">|</span><span>Page <input style="margin-bottom: 5px" ng-model="ngGridSortPagination.page" class="ui-pg-input" type="text" size="2" maxlength="4" value="0"/> of <span>{{ngGridSortPagination.lastPage}}</span></span><span style="display:inline-block; margin:0 5px;" class="ui-state-disabled">|</span><span style="cursor: pointer; display:inline-block; vertical-align:middle; margin: 0 5px;" class="ui-icon ui-icon-seek-next" ng-class="$gridNextClass()" ng-click="ngGridSortPagination.page=ngGridSortPagination.page+1"></span><span style="cursor: pointer; display:inline-block; vertical-align:middle; margin: 0 5px;" class="ui-icon ui-icon-seek-end" ng-class="$gridNextClass()" ng-click="ngGridSortPagination.page=ngGridSortPagination.lastPage"></span><span style="display:inline-block; margin-left:10px;" ><select ng-model="ngGridSortPagination.limit" style="position:relative;top:5px"><option value="5">5</option><option value="10">10</option><option value="20">20</option><option value="30">30</option></select></span><span style="margin:0 5px">Znaleziono {{'+navigationVectorName+'.items.length}} obiektów</span></td></tr></tfoot>'; | |
tElement.append(footer); | |
// tElement.find('.ui-state-default, .ui-widget-content').css('font-size', '0.91em'); | |
return { | |
pre: function($scope, linkElement) { | |
$scope.ngGridSortPagination = {}; | |
var grid = $scope.ngGridSortPagination; | |
grid.limit = 5; | |
grid.page = 1; | |
// grid.lastPage = Math.ceil(count / grid.limit); | |
// grid.skipAt = ((grid.page - 1) * grid.limit); | |
//ORDER | |
var listenerOrder = function(ev) { | |
var sort = angular.element(this).children('span'); | |
grid.predicate = angular.element(this).attr('name'); | |
grid.reverse = false; | |
if (!sort.hasClass('ui-icon-triangle-1-n') && !sort.hasClass('ui-icon-triangle-1-s')) { | |
headerRow.children('th').children('span').removeClass('ui-icon ui-icon-triangle-1-n ui-icon-triangle-1-s'); | |
sort.addClass('ui-icon ui-icon-triangle-1-n'); | |
grid.reverse = false; | |
} else { | |
if (sort.hasClass('ui-icon-triangle-1-n')) { | |
grid.reverse = true; | |
} else { | |
grid.reverse = false; | |
} | |
sort.toggleClass('ui-icon-triangle-1-n'); | |
sort.toggleClass('ui-icon-triangle-1-s'); | |
} | |
$scope[navigationVectorName].items = $filter('orderBy')($scope[navigationVectorName].items,grid.predicate,grid.reverse); | |
// console.log('orderBy :' + grid.predicate + ' order: ' + grid.reverse); | |
$scope.$digest(); | |
}; | |
angular.forEach(linkElement.children('thead').children('tr').children('th'), function(elm) { | |
elm.addEventListener('click', listenerOrder); | |
}); | |
}, | |
post: function postLink($scope, element, attrs, controller) { | |
//colResizable - by Alvaro Prieto Lauroba - MIT & GPL | |
//http://quocity.com/colresizable/ | |
(function(a){function h(b){var c=a(this).data(q),d=m[c.t],e=d.g[c.i];e.ox=b.pageX;e.l=e[I]()[H];i[D](E+q,f)[D](F+q,g);P[z](x+"*{cursor:"+d.opt.dragCursor+K+J);e[B](d.opt.draggingClass);l=e;if(d.c[c.i].l)for(b=0;b<d.ln;b++)c=d.c[b],c.l=j,c.w=c[u]();return j}function g(b){i.unbind(E+q).unbind(F+q);a("head :last-child").remove();if(l){l[A](l.t.opt.draggingClass);var f=l.t,g=f.opt.onResize;l.x&&(e(f,l.i,1),d(f),g&&(b[G]=f[0],g(b)));f.p&&O&&c(f);l=k}}function f(a){if(l){var b=l.t,c=a.pageX-l.ox+l.l,f=b.opt.minWidth,g=l.i,h=1.5*b.cs+f+b.b,i=g==b.ln-1?b.w-h:b.g[g+1][I]()[H]-b.cs-f,f=g?b.g[g-1][I]()[H]+b.cs+f:h,c=s.max(f,s.min(i,c));l.x=c;l.css(H,c+p);if(b.opt.liveDrag&&(e(b,g),d(b),c=b.opt.onDrag))a[G]=b[0],c(a)}return j}function e(a,b,c){var d=l.x-l.l,e=a.c[b],f=a.c[b+1],g=e.w+d,d=f.w-d;e[u](g+p);f[u](d+p);a.cg.eq(b)[u](g+p);a.cg.eq(b+1)[u](d+p);if(c)e.w=g,f.w=d}function d(a){a.gc[u](a.w);for(var b=0;b<a.ln;b++){var c=a.c[b];a.g[b].css({left:c.offset().left-a.offset()[H]+c.outerWidth()+a.cs/2+p,height:a.opt.headerOnly?a.c[0].outerHeight():a.outerHeight()})}}function c(a,b){var c,d=0,e=0,f=[];if(b)if(a.cg[C](u),a.opt.flush)O[a.id]="";else{for(c=O[a.id].split(";");e<a.ln;e++)f[y](100*c[e]/c[a.ln]+"%"),b.eq(e).css(u,f[e]);for(e=0;e<a.ln;e++)a.cg.eq(e).css(u,f[e])}else{O[a.id]="";for(e in a.c)c=a.c[e][u](),O[a.id]+=c+";",d+=c;O[a.id]+=d}}function b(b){var e=">thead>tr>",f='"></div>',g=">tbody>tr:first>",i=">tr:first>",j="td",k="th",l=b.find(e+k+","+e+j);l.length||(l=b.find(g+k+","+i+k+","+g+j+","+i+j));b.cg=b.find("col");b.ln=l.length;b.p&&O&&O[b.id]&&c(b,l);l.each(function(c){var d=a(this),e=a(b.gc[z](w+"CRG"+f)[0].lastChild);e.t=b;e.i=c;e.c=d;d.w=d[u]();b.g[y](e);b.c[y](d);d[u](d.w)[C](u);if(c<b.ln-1)e.mousedown(h)[z](b.opt.gripInnerHtml)[z](w+q+'" style="cursor:'+b.opt.hoverCursor+f);else e[B]("CRL")[A]("CRG");e.data(q,{i:c,t:b[v](o)})});b.cg[C](u);d(b);b.find("td, th").not(l).not(N+"th, table td").each(function(){a(this)[C](u)})}var i=a(document),j=!1,k=null,l=k,m=[],n=0,o="id",p="px",q="CRZ",r=parseInt,s=Math,t=a.browser.msie,u="width",v="attr",w='<div class="',x="<style type='text/css'>",y="push",z="append",A="removeClass",B="addClass",C="removeAttr",D="bind",E="mousemove.",F="mouseup.",G="currentTarget",H="left",I="position",J="}</style>",K="!important;",L=":0px"+K,M="resize",N="table",O,P=a("head")[z](x+".CRZ{table-layout:fixed;}.CRZ td,.CRZ th{padding-"+H+L+"padding-right"+L+"overflow:hidden}.CRC{height:0px;"+I+":relative;}.CRG{margin-left:-5px;"+I+":absolute;z-index:5;}.CRG .CRZ{"+I+":absolute;background-color:red;filter:alpha(opacity=1);opacity:0;width:10px;height:100%;top:0px}.CRL{"+I+":absolute;width:1px}.CRD{ border-left:1px dotted black"+J);try{O=sessionStorage}catch(Q){}a(window)[D](M+"."+q,function(){for(a in m){var a=m[a],b,c=0;a[A](q);if(a.w!=a[u]()){a.w=a[u]();for(b=0;b<a.ln;b++)c+=a.c[b].w;for(b=0;b<a.ln;b++)a.c[b].css(u,s.round(1e3*a.c[b].w/c)/10+"%").l=1}d(a[B](q))}});a.fn.extend({colResizable:function(c){c=a.extend({draggingClass:"CRD",gripInnerHtml:"",liveDrag:j,minWidth:15,headerOnly:j,hoverCursor:"e-"+M,dragCursor:"e-"+M,postbackSafe:j,flush:j,marginLeft:k,marginRight:k,disable:j,onDrag:k,onResize:k},c);return this.each(function(){var d=c,e=a(this);if(d.disable){if(e=e[v](o),(d=m[e])&&d.is(N))d[A](q).gc.remove(),delete m[e]}else{var f=e.id=e[v](o)||q+n++;e.p=d.postbackSafe;if(e.is(N)&&!m[f])e[B](q)[v](o,f).before(w+'CRC"/>'),e.opt=d,e.g=[],e.c=[],e.w=e[u](),e.gc=e.prev(),d.marginLeft&&e.gc.css("marginLeft",d.marginLeft),d.marginRight&&e.gc.css("marginRight",d.marginRight),e.cs=r(t?this.cellSpacing||this.currentStyle.borderSpacing:e.css("border-spacing"))||2,e.b=r(t?this.border||this.currentStyle.borderLeftWidth:e.css("border-"+H+"-"+u))||1,m[f]=e,b(e)}})}})})(jQuery) | |
$(document).ready(function(){element.colResizable({liveDrag:true,minWidth:100});}); | |
$scope.$watch(navigationVectorName+'.items',function(newVal, oldVal){ | |
// console.log(attrs.ngGrid + ".items changed"); | |
// console.log($scope[attrs.ngGrid].items); | |
if(newVal == oldVal) | |
return; | |
$scope.ngGridSortPagination.lastPage = Math.ceil(newVal.length / $scope.ngGridSortPagination.limit); | |
}); | |
$scope.$watch(navigationVectorName+'.items.length',function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
// console.log("length changed to " + newVal) | |
$scope.ngGridSortPagination.lastPage = Math.ceil(newVal / $scope.ngGridSortPagination.limit); | |
}); | |
$scope.$watch(navigationVectorName+'.index',function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
// console.log("Page change by index " + newVal + " to " + Math.ceil((newVal+1) / $scope.ngGridSortPagination.limit)) | |
$scope.ngGridSortPagination.page = Math.ceil((newVal+1) / $scope.ngGridSortPagination.limit); | |
}); | |
$scope.$watch('ngGridSortPagination.page',function(newVal, oldVal){ | |
// console.log("page changed from " + oldVal + " to " + newVal) | |
if(newVal == oldVal || newVal==="") | |
return; | |
if(newVal <= $scope.ngGridSortPagination.lastPage && (newVal >=1)) | |
$scope.ngGridSortPagination.skipAt = (($scope.ngGridSortPagination.page - 1) * $scope.ngGridSortPagination.limit); | |
else | |
if($scope.ngGridSortPagination.lastPage == 0) | |
$scope.ngGridSortPagination.page = 0; | |
else | |
$scope.ngGridSortPagination.page = oldVal==="" ? 1 : oldVal; | |
}); | |
$scope.$watch('ngGridSortPagination.limit',function(newVal, oldVal){ | |
// console.log("limit changed to " + newVal); | |
$scope.ngGridSortPagination.lastPage = Math.ceil($scope[navigationVectorName].items.length / newVal); | |
$scope.ngGridSortPagination.page = 1; | |
}); | |
$scope.$gridSelect = function(obj){ | |
$scope[navigationVectorName].selected = obj; | |
}; | |
$scope.$gridSelectedClass = function(obj){ | |
if(obj == $scope[navigationVectorName].selected) | |
return "ng-grid-selected"; | |
else | |
return ""; | |
}; | |
$scope.$gridPrevClass = function(){ | |
if($scope.ngGridSortPagination.page <= 1) | |
return "ui-state-disabled"; | |
else | |
return ""; | |
}; | |
$scope.$gridNextClass = function(){ | |
if($scope.ngGridSortPagination.page >= $scope.ngGridSortPagination.lastPage || $scope.ngGridSortPagination.page == "") | |
return "ui-state-disabled"; | |
else | |
return ""; | |
}; | |
} | |
} | |
} | |
}; | |
}); | |
})(window.angular); | |
/** | |
* Object used by ngGrid | |
* items - array of items displayed in ngGrid | |
* selected - currently selected object | |
* index - index in the array of the currently selected object | |
* | |
* @param $scope - scope in which the NavigationVector is defined | |
*/ | |
function NavigationVector($scope){ | |
var self = this; | |
this.$scope = $scope; | |
this.items = []; | |
this.selected = null; | |
this.index = null; | |
$scope.$watch(function(){return self.selected;},function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
self.index = self.items.indexOf(newVal); | |
if(self.index == -1){ | |
self.index = null; | |
} | |
}); | |
$scope.$watch(function(){return self.index;},function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
if(self.items) | |
self.selected = self.items[newVal]; | |
else | |
self.selected = null; | |
}); | |
$scope.$watch(function(){return self.items;},function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
if(self.items){ | |
self.index = self.items.indexOf(self.selected); | |
if(self.index == -1) | |
if(self.items.length == 0){ | |
self.index = null; | |
}else{ | |
self.index = 0; | |
self.selected = self.items[0]; | |
} | |
}else{ | |
self.items = []; | |
self.index = null; | |
self.selected = null; | |
} | |
}); | |
$scope.$watch(function(){return self.items.length;},function(newVal, oldVal){ | |
if(newVal == oldVal) | |
return; | |
self.index = self.items.indexOf(self.selected); | |
if(self.index == -1){ | |
if(self.items.length == 0){ | |
self.index = null; | |
}else{ | |
self.index = 0; | |
self.selected = self.items[0]; | |
} | |
} | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tr.ng-grid-selected td{ | |
background: #BCBFE6; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment