From 266314a536f0c29ddcaf248dde573d58e6562fe3 Mon Sep 17 00:00:00 2001 From: Louis LIN Date: Thu, 21 Aug 2014 10:13:17 +0200 Subject: [PATCH] Correct the empty result display in the "Angular way" #43 --- dist/angular-datatables.js | 21 ++++++++-- dist/angular-datatables.min.js | 2 +- src/angular-datatables.directive.js | 11 +++-- src/angular-datatables.util.js | 16 +++++++- test/spec/angular-datatables.util.spec.js | 50 +++++++++++++++-------- 5 files changed, 74 insertions(+), 26 deletions(-) diff --git a/dist/angular-datatables.js b/dist/angular-datatables.js index b95b40530..84af57513 100644 --- a/dist/angular-datatables.js +++ b/dist/angular-datatables.js @@ -359,12 +359,16 @@ }(angular)); (function (angular) { 'use strict'; - angular.module('datatables.directive', ['datatables.options']).directive('datatable', [ + angular.module('datatables.directive', [ + 'datatables.options', + 'datatables.util' + ]).directive('datatable', [ 'DT_DEFAULT_OPTIONS', '$timeout', '$DTBootstrap', 'DTLoadingTemplate', - function (DT_DEFAULT_OPTIONS, $timeout, $DTBootstrap, DTLoadingTemplate) { + '$DTPropertyUtil', + function (DT_DEFAULT_OPTIONS, $timeout, $DTBootstrap, DTLoadingTemplate, $DTPropertyUtil) { var $loading = angular.element(DTLoadingTemplate.html), _showLoading = function ($elem) { $elem.after($loading); $elem.hide(); @@ -434,7 +438,10 @@ return { options: options, render: function ($scope, $elem) { - var _this = this; + var _this = this, parentScope = $scope.$parent, dataProp = $DTPropertyUtil.findDataPropFromScope(parentScope); + if (parentScope[dataProp].length === 0) { + _doRenderDataTable($elem, _this.options, $scope); + } $scope.$on(DT_DEFAULT_OPTIONS.lastRowKey, function () { _doRenderDataTable($elem, _this.options, $scope); }); @@ -991,6 +998,14 @@ result = angular.copy(target); } return result; + }, + findDataPropFromScope: function (scope) { + for (var prop in scope) { + if (prop.indexOf('$', 0) !== 0 && scope.hasOwnProperty(prop) && angular.isArray(scope[prop])) { + return prop; + } + } + throw new Error('Cannot find the data property from the scope'); } }; }); diff --git a/dist/angular-datatables.min.js b/dist/angular-datatables.min.js index fdfbe4a8a..9698419a6 100644 --- a/dist/angular-datatables.min.js +++ b/dist/angular-datatables.min.js @@ -3,4 +3,4 @@ * https://github.com/l-lin/angular-datatables * License: MIT */ -!function(a,b,c,d){"use strict";d.module("datatables.bootstrap.tabletools",["datatables.bootstrap.options","datatables.util"]).service("$DTBootstrapTableTools",["$DTPropertyUtil","$DTBootstrapDefaultOptions",function(a,b){var e=!1,f={},g=function(){c.fn.DataTable.TableTools&&(f.TableTools={classes:d.copy(c.fn.DataTable.TableTools.classes),oTags:d.copy(c.fn.DataTable.TableTools.DEFAULTS.oTags)})};this.integrate=function(d){if(!e){if(g(),c.fn.DataTable.TableTools){var f=a.overrideProperties(b.getOptions().TableTools,d?d.TableTools:null);c.extend(!0,c.fn.DataTable.TableTools.classes,f.classes),c.extend(!0,c.fn.DataTable.TableTools.DEFAULTS.oTags,f.DEFAULTS.oTags)}e=!0}},this.deIntegrate=function(){e&&c.fn.DataTable.TableTools&&f.TableTools&&(c.extend(!0,c.fn.DataTable.TableTools.classes,f.TableTools.classes),c.extend(!0,c.fn.DataTable.TableTools.DEFAULTS.oTags,f.TableTools.oTags),e=!1)}}]),d.module("datatables.bootstrap.colvis",["datatables.bootstrap.options","datatables.util"]).service("$DTBootstrapColVis",["$DTPropertyUtil","$DTBootstrapDefaultOptions",function(a,b){var d=!1;this.integrate=function(e,f){if(!d){var g=a.overrideProperties(b.getOptions().ColVis,f?f.ColVis:null);c.fn.DataTable.ColVis&&e(function(){c(".ColVis_MasterButton").attr("class","ColVis_MasterButton "+g.classes.masterButton),c(".ColVis_Button").removeClass("ColVis_Button")}),d=!0}},this.deIntegrate=function(){d&&c.fn.DataTable.ColVis&&(d=!1)}}]),d.module("datatables.bootstrap",["datatables.bootstrap.options","datatables.bootstrap.tabletools","datatables.bootstrap.colvis"]).service("$DTBootstrap",["$DTBootstrapTableTools","$DTBootstrapColVis","$DTBootstrapDefaultOptions",function(a,e,f){var g=!1,h=[],i={},j=function(){i.oStdClasses=d.copy(c.fn.dataTableExt.oStdClasses),i.fnPagingInfo=c.fn.dataTableExt.oApi.fnPagingInfo,i.renderer=d.copy(c.fn.DataTable.ext.renderer),c.fn.DataTable.TableTools&&(i.TableTools={classes:d.copy(c.fn.DataTable.TableTools.classes),oTags:d.copy(c.fn.DataTable.TableTools.DEFAULTS.oTags)})},k=function(){c.extend(c.fn.dataTableExt.oStdClasses,i.oStdClasses),c.fn.dataTableExt.oApi.fnPagingInfo=i.fnPagingInfo,c.extend(!0,c.fn.DataTable.ext.renderer,i.renderer)},l=function(){c.extend(c.fn.dataTableExt.oStdClasses,{sWrapper:"dataTables_wrapper form-inline",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm",sFilter:"dataTables_filter",sLength:"dataTables_length"})},m=function(){c.fn.dataTableExt.oApi.fnPagingInfo=function(a){return{iStart:a._iDisplayStart,iEnd:a.fnDisplayEnd(),iLength:a._iDisplayLength,iTotal:a.fnRecordsTotal(),iFilteredTotal:a.fnRecordsDisplay(),iPage:-1===a._iDisplayLength?0:Math.ceil(a._iDisplayStart/a._iDisplayLength),iTotalPages:-1===a._iDisplayLength?0:Math.ceil(a.fnRecordsDisplay()/a._iDisplayLength)}}},n=function(){c.extend(!0,c.fn.DataTable.ext.renderer,{pageButton:{_:function(a,d,e,f,g,h){var i,j,k=a.oClasses,l=a.oLanguage.oPaginate,m=0,n=c("",{"class":"pagination"}),o=function(b,d){var f,p,q,r,s=function(b){b.preventDefault(),c.fn.DataTable.ext.internal._fnPageChange(a,b.data.action,!0)};for(f=0,p=d.length;p>f;f++)if(r=d[f],c.isArray(r)){r.DT_el="li";var t=c("<"+(r.DT_el||"div")+"/>").appendTo(n);o(t,r)}else{i="",j="";var u,v=c("
  • ");switch(r){case"ellipsis":n.append('
  • ');break;case"first":i=l.sFirst,j=r,0>=g&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"previous":i=l.sPrevious,j=r,0>=g&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"next":i=l.sNext,j=r,g>=h-1&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"last":i=l.sLast,j=r,g>=h-1&&(v.addClass(k.sPageButtonDisabled),u=!0);break;default:i=r+1,j="",g===r&&v.addClass(k.sPageButtonActive)}i&&(v.appendTo(n),q=c("",{href:"#","class":j,"aria-controls":a.sTableId,"data-dt-idx":m,tabindex:a.iTabIndex,id:0===e&&"string"==typeof r?a.sTableId+"_"+r:null}).html(i).appendTo(v),c.fn.DataTable.ext.internal._fnBindAction(q,{action:r},s),m++)}};try{var p=c(b.activeElement).data("dt-idx"),q=c(d).empty();n.appendTo(q),o(q,f),null!==p&&c(d).find("[data-dt-idx="+p+"]").focus()}catch(r){}}}})},o=function(a){d.isFunction(a)&&h.push(a)},p=function(){g||(j(),l(),m(),n(),o(function(){c("div.dataTables_filter").find("input").addClass("form-control"),c("div.dataTables_length").find("select").addClass("form-control")}),g=!0)},q=function(a){if(!a.hasOverrideDom){var b=f.getOptions().dom;return a.hasColReorder&&(b="R"+b),a.hasColVis&&(b="C"+b),a.hasTableTools&&(b="T"+b),b}return a.sDom};this.integrate=function(b){p(),a.integrate(b.bootstrap),e.integrate(o,b.bootstrap),b.sDom=q(b),d.isUndefined(b.fnDrawCallback)&&(b.fnDrawCallback=function(){for(var a=0;a<'col-xs-6'f>r>t<'row'<'col-xs-6'i><'col-xs-6'p>>"}).service("$DTBootstrapDefaultOptions",["$DTDefaultOptions","$DTPropertyUtil","DT_BOOTSTRAP_DEFAULT_OPTIONS",function(a,b,c){this.getOptions=function(){return b.overrideProperties(c,a.bootstrapOptions)}}])}(angular),function(a){"use strict";a.module("datatables.directive",["datatables.options"]).directive("datatable",["DT_DEFAULT_OPTIONS","$timeout","$DTBootstrap","DTLoadingTemplate",function(b,c,d,e){var f=a.element(e.html),g=function(a){a.after(f),a.hide()},h=function(a){a.show(),f.hide()},i=function(a,b,c){var d=a.DataTable(b);return c.$emit("event:dataTableLoaded",{id:a.attr("id")}),d},j=function(a,b,d){c(function(){h(a),i(a,b,d)},0,!1)},k=function(b){return a.isDefined(b)&&a.isFunction(b.fnClearTable)},l=function(b){return a.isDefined(b.fnReloadAjax)&&a.isFunction(b.fnReloadAjax)},m={fromOptions:function(b,c){return c?new o(b):a.isDefined(b)?a.isDefined(b.fnPromise)&&null!==b.fnPromise?new p(b):a.isDefined(b.sAjaxSource)&&null!==b.sAjaxSource||a.isDefined(b.ajax)&&null!==b.ajax?new q(b):new n(b):new n}},n=function(a){return{options:a,render:function(a,b){j(b,this.options,a)}}},o=function(a){return{options:a,render:function(a,c){var d=this;a.$on(b.lastRowKey,function(){j(c,d.options,a)})}}},p=function(b){var d,e=function(a,b,e,f){a.aaData=e,c(function(){h(b),a.bDestroy=!0,d?k(d)?(d.fnClearTable(),d.fnDraw(),d.fnAddData(a.aaData)):(d.clear(),d.rows.add(a.aaData).draw()):d=i(b,a,f)},0,!1)};return{options:b,render:function(b,c){var d=this,f=null,h=function(a){e(d.options,c,a,b),f=null},i=function(b){f=a.isFunction(b)?b():b,g(c),f.then(h)},j=function(a){f?f.then(function(){i(a)}):i(a)};b.$watch("dtOptions.fnPromise",function(b){if(!a.isDefined(b))throw new Error("You must provide a promise or a function that returns a promise!");j(b)}),b.$watch("dtOptions.reload",function(a){a&&(b.dtOptions.reload=!1,j(b.dtOptions.fnPromise))})}}},q=function(d){var e,f=function(a,b,d){a.bDestroy=!0,c(function(){if(h(b),e)if(l(e))e.fnReloadAjax(a.sAjaxSource);else{if(k(e))throw new Error('Reload Ajax not supported. Please use the plugin "fnReloadAjax" (https://next.datatables.net/plug-ins/api/fnReloadAjax) or use a more recent version of DataTables (v1.10+)');var c=a.sAjaxSource||a.ajax.url||a.ajax;e.ajax.url(c).load()}else e=i(b,a,d)},0,!1)};return{options:d,render:function(c,e){var g=this;a.isUndefined(g.options.sAjaxDataProp)&&(g.options.sAjaxDataProp=b.sAjaxDataProp),a.isUndefined(g.options.aoColumns)&&(g.options.aoColumns=b.aoColumns),c.$watch("dtOptions.sAjaxSource",function(b){a.isDefined(b)&&(g.options.sAjaxSource=b,a.isDefined(g.options.ajax)&&(a.isObject(g.options.ajax)?g.options.ajax.url=b:g.options.ajax={url:b})),f(d,e,c)}),c.$watch("dtOptions.reload",function(a){a&&(c.dtOptions.reload=!1,f(d,e,c))})}}};return{restrict:"A",scope:{dtOptions:"=",dtColumns:"=",dtColumnDefs:"=",datatable:"@"},link:function(b,c){g(c);var e,f=b.datatable&&"ng"===b.datatable;a.isDefined(b.dtOptions)&&(e={},a.extend(e,b.dtOptions),a.isArray(b.dtColumns)&&(e.aoColumns=b.dtColumns),a.isArray(b.dtColumnDefs)&&(e.aoColumnDefs=b.dtColumnDefs),e.integrateBootstrap?d.integrate(e):d.deIntegrate()),m.fromOptions(e,f).render(b,c)}}}]).directive("dtRows",["$rootScope","DT_DEFAULT_OPTIONS",function(a,b){return{restrict:"A",link:function(c){c.$last===!0&&a.$broadcast(b.lastRowKey)}}}])}(angular),function(a,b){"use strict";b.module("datatables.factory",["datatables.bootstrap","datatables.options"]).factory("DTOptionsBuilder",["DT_DEFAULT_OPTIONS",function(a){var c=function(a){this.obj=a,this.isPresent=function(){return b.isDefined(this.obj)&&null!==this.obj},this.orEmptyObj=function(){return this.isPresent()?this.obj:{}},this.or=function(a){return this.isPresent()?this.obj:a}},d=function(a){return new c(a)},e={integrateBootstrap:!1,hasColVis:!1,hasColReorder:!1,hasTableTools:!1,hasOverrideDom:!1,reloadData:function(){return this.reload=!0,this},withOption:function(a,c){return b.isString(a)&&(this[a]=c),this},withSource:function(a){return this.sAjaxSource=a,this},withDataProp:function(a){return this.sAjaxDataProp=a,this},withFnServerData:function(a){if(!b.isFunction(a))throw new Error("The parameter must be a function");return this.fnServerData=a,this},withPaginationType:function(a){if(!b.isString(a))throw new Error("The pagination type must be provided");return this.sPaginationType=a,this},withLanguage:function(a){return this.oLanguage=a,this},withLanguageSource:function(a){return this.withLanguage({sUrl:a})},withDisplayLength:function(a){return this.iDisplayLength=a,this},withFnPromise:function(a){return this.fnPromise=a,this},withDOM:function(a){return this.sDom=a,this.hasOverrideDom=!0,this},withBootstrap:function(){return this.integrateBootstrap=!0,b.isObject(this.oClasses)?this.oClasses.sPageButtonActive="active":this.oClasses={sPageButtonActive:"active"},this},withBootstrapOptions:function(a){return this.bootstrap=a,this},withColReorderOption:function(a,c){return b.isString(a)&&(this.oColReorder=d(this.oColReorder).orEmptyObj(),this.oColReorder[a]=c),this},withColReorder:function(){var b="R";return this.sDom=b+d(this.sDom).or(a.dom),this.hasColReorder=!0,this},withColReorderOrder:function(a){return b.isArray(a)&&this.withColReorderOption("aiOrder",a),this},withColReorderCallback:function(a){if(!b.isFunction(a))throw new Error("The reorder callback must be a function");return this.withColReorderOption("fnReorderCallback",a),this},withColVisOption:function(a,c){return b.isString(a)&&(this.oColVis=d(this.oColVis).orEmptyObj(),this.oColVis[a]=c),this},withColVis:function(){var b="C";return this.sDom=b+d(this.sDom).or(a.dom),this.hasColVis=!0,this},withColVisStateChange:function(a){if(!b.isFunction(a))throw new Error("The state change must be a function");return this.withColVisOption("fnStateChange",a),this},withTableToolsOption:function(a,c){return b.isString(a)&&(this.oTableTools=d(this.oTableTools).orEmptyObj(),this.oTableTools[a]=c),this},withTableTools:function(c){var e="T";return this.sDom=e+d(this.sDom).or(a.dom),this.hasTableTools=!0,b.isString(c)&&this.withTableToolsOption("sSwfPath",c),this},withTableToolsButtons:function(a){return b.isArray(a)&&this.withTableToolsOption("aButtons",a),this}};return{newOptions:function(){return Object.create(e)},fromSource:function(a){var b=Object.create(e);return b.sAjaxSource=a,b},fromFnPromise:function(a){var b=Object.create(e);return b.fnPromise=a,b}}}]).factory("DTColumnBuilder",function(){var a={withOption:function(a,c){return b.isString(a)&&(this[a]=c),this},withTitle:function(a){return this.sTitle=a,this},withClass:function(a){return this.sClass=a,this},notVisible:function(){return this.bVisible=!1,this},notSortable:function(){return this.bSortable=!1,this},renderWith:function(a){return this.mRender=a,this}};return{newColumn:function(c,d){if(b.isUndefined(c))throw new Error('The parameter "mData" is not defined!');var e=Object.create(a);return e.mData=c,e.sTitle=d||"",e},DTColumn:a}}).factory("DTColumnDefBuilder",["DTColumnBuilder",function(a){return{newColumnDef:function(c){if(b.isUndefined(c))throw new Error('The parameter "targets" must be defined! See https://datatables.net/reference/option/columnDefs.targets');var d=Object.create(a.DTColumn);return d.aTargets=b.isArray(c)?c:[c],d}}}]).factory("DTLoadingTemplate",function(){return{html:'

    Loading...

    '}})}(jQuery,angular),function(a){"use strict";a.module("datatables",["datatables.directive","datatables.factory","datatables.bootstrap"])}(angular),function(a){"use strict";a.module("datatables.options",[]).constant("DT_DEFAULT_OPTIONS",{lastRowKey:"datatable:lastRow",dom:"lfrtip",sAjaxDataProp:"",aoColumns:[]}).service("$DTDefaultOptions",function(){this.bootstrapOptions={},this.setLanguageSource=function(a){return $.extend($.fn.dataTable.defaults,{oLanguage:{sUrl:a}}),this},this.setLanguage=function(a){return $.extend(!0,$.fn.dataTable.defaults,{oLanguage:a}),this},this.setDisplayLength=function(a){return $.extend($.fn.dataTable.defaults,{iDisplayLength:a}),this},this.setBootstrapOptions=function(a){return this.bootstrapOptions=a,this}})}(angular),function(a){"use strict";a.module("datatables.util",[]).factory("$DTPropertyUtil",function(){return{overrideProperties:function(b,c){var d=a.copy(b);if((a.isUndefined(d)||null===d)&&(d={}),a.isUndefined(c)||null===c)return d;if(a.isObject(c))for(var e in c)c.hasOwnProperty(e)&&(d[e]=this.overrideProperties(d[e],c[e]));else d=a.copy(c);return d}}})}(angular); \ No newline at end of file +!function(a,b,c,d){"use strict";d.module("datatables.bootstrap.tabletools",["datatables.bootstrap.options","datatables.util"]).service("$DTBootstrapTableTools",["$DTPropertyUtil","$DTBootstrapDefaultOptions",function(a,b){var e=!1,f={},g=function(){c.fn.DataTable.TableTools&&(f.TableTools={classes:d.copy(c.fn.DataTable.TableTools.classes),oTags:d.copy(c.fn.DataTable.TableTools.DEFAULTS.oTags)})};this.integrate=function(d){if(!e){if(g(),c.fn.DataTable.TableTools){var f=a.overrideProperties(b.getOptions().TableTools,d?d.TableTools:null);c.extend(!0,c.fn.DataTable.TableTools.classes,f.classes),c.extend(!0,c.fn.DataTable.TableTools.DEFAULTS.oTags,f.DEFAULTS.oTags)}e=!0}},this.deIntegrate=function(){e&&c.fn.DataTable.TableTools&&f.TableTools&&(c.extend(!0,c.fn.DataTable.TableTools.classes,f.TableTools.classes),c.extend(!0,c.fn.DataTable.TableTools.DEFAULTS.oTags,f.TableTools.oTags),e=!1)}}]),d.module("datatables.bootstrap.colvis",["datatables.bootstrap.options","datatables.util"]).service("$DTBootstrapColVis",["$DTPropertyUtil","$DTBootstrapDefaultOptions",function(a,b){var d=!1;this.integrate=function(e,f){if(!d){var g=a.overrideProperties(b.getOptions().ColVis,f?f.ColVis:null);c.fn.DataTable.ColVis&&e(function(){c(".ColVis_MasterButton").attr("class","ColVis_MasterButton "+g.classes.masterButton),c(".ColVis_Button").removeClass("ColVis_Button")}),d=!0}},this.deIntegrate=function(){d&&c.fn.DataTable.ColVis&&(d=!1)}}]),d.module("datatables.bootstrap",["datatables.bootstrap.options","datatables.bootstrap.tabletools","datatables.bootstrap.colvis"]).service("$DTBootstrap",["$DTBootstrapTableTools","$DTBootstrapColVis","$DTBootstrapDefaultOptions",function(a,e,f){var g=!1,h=[],i={},j=function(){i.oStdClasses=d.copy(c.fn.dataTableExt.oStdClasses),i.fnPagingInfo=c.fn.dataTableExt.oApi.fnPagingInfo,i.renderer=d.copy(c.fn.DataTable.ext.renderer),c.fn.DataTable.TableTools&&(i.TableTools={classes:d.copy(c.fn.DataTable.TableTools.classes),oTags:d.copy(c.fn.DataTable.TableTools.DEFAULTS.oTags)})},k=function(){c.extend(c.fn.dataTableExt.oStdClasses,i.oStdClasses),c.fn.dataTableExt.oApi.fnPagingInfo=i.fnPagingInfo,c.extend(!0,c.fn.DataTable.ext.renderer,i.renderer)},l=function(){c.extend(c.fn.dataTableExt.oStdClasses,{sWrapper:"dataTables_wrapper form-inline",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm",sFilter:"dataTables_filter",sLength:"dataTables_length"})},m=function(){c.fn.dataTableExt.oApi.fnPagingInfo=function(a){return{iStart:a._iDisplayStart,iEnd:a.fnDisplayEnd(),iLength:a._iDisplayLength,iTotal:a.fnRecordsTotal(),iFilteredTotal:a.fnRecordsDisplay(),iPage:-1===a._iDisplayLength?0:Math.ceil(a._iDisplayStart/a._iDisplayLength),iTotalPages:-1===a._iDisplayLength?0:Math.ceil(a.fnRecordsDisplay()/a._iDisplayLength)}}},n=function(){c.extend(!0,c.fn.DataTable.ext.renderer,{pageButton:{_:function(a,d,e,f,g,h){var i,j,k=a.oClasses,l=a.oLanguage.oPaginate,m=0,n=c("
      ",{"class":"pagination"}),o=function(b,d){var f,p,q,r,s=function(b){b.preventDefault(),c.fn.DataTable.ext.internal._fnPageChange(a,b.data.action,!0)};for(f=0,p=d.length;p>f;f++)if(r=d[f],c.isArray(r)){r.DT_el="li";var t=c("<"+(r.DT_el||"div")+"/>").appendTo(n);o(t,r)}else{i="",j="";var u,v=c("
    • ");switch(r){case"ellipsis":n.append('
    • ');break;case"first":i=l.sFirst,j=r,0>=g&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"previous":i=l.sPrevious,j=r,0>=g&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"next":i=l.sNext,j=r,g>=h-1&&(v.addClass(k.sPageButtonDisabled),u=!0);break;case"last":i=l.sLast,j=r,g>=h-1&&(v.addClass(k.sPageButtonDisabled),u=!0);break;default:i=r+1,j="",g===r&&v.addClass(k.sPageButtonActive)}i&&(v.appendTo(n),q=c("",{href:"#","class":j,"aria-controls":a.sTableId,"data-dt-idx":m,tabindex:a.iTabIndex,id:0===e&&"string"==typeof r?a.sTableId+"_"+r:null}).html(i).appendTo(v),c.fn.DataTable.ext.internal._fnBindAction(q,{action:r},s),m++)}};try{var p=c(b.activeElement).data("dt-idx"),q=c(d).empty();n.appendTo(q),o(q,f),null!==p&&c(d).find("[data-dt-idx="+p+"]").focus()}catch(r){}}}})},o=function(a){d.isFunction(a)&&h.push(a)},p=function(){g||(j(),l(),m(),n(),o(function(){c("div.dataTables_filter").find("input").addClass("form-control"),c("div.dataTables_length").find("select").addClass("form-control")}),g=!0)},q=function(a){if(!a.hasOverrideDom){var b=f.getOptions().dom;return a.hasColReorder&&(b="R"+b),a.hasColVis&&(b="C"+b),a.hasTableTools&&(b="T"+b),b}return a.sDom};this.integrate=function(b){p(),a.integrate(b.bootstrap),e.integrate(o,b.bootstrap),b.sDom=q(b),d.isUndefined(b.fnDrawCallback)&&(b.fnDrawCallback=function(){for(var a=0;a<'col-xs-6'f>r>t<'row'<'col-xs-6'i><'col-xs-6'p>>"}).service("$DTBootstrapDefaultOptions",["$DTDefaultOptions","$DTPropertyUtil","DT_BOOTSTRAP_DEFAULT_OPTIONS",function(a,b,c){this.getOptions=function(){return b.overrideProperties(c,a.bootstrapOptions)}}])}(angular),function(a){"use strict";a.module("datatables.directive",["datatables.options","datatables.util"]).directive("datatable",["DT_DEFAULT_OPTIONS","$timeout","$DTBootstrap","DTLoadingTemplate","$DTPropertyUtil",function(b,c,d,e,f){var g=a.element(e.html),h=function(a){a.after(g),a.hide()},i=function(a){a.show(),g.hide()},j=function(a,b,c){var d=a.DataTable(b);return c.$emit("event:dataTableLoaded",{id:a.attr("id")}),d},k=function(a,b,d){c(function(){i(a),j(a,b,d)},0,!1)},l=function(b){return a.isDefined(b)&&a.isFunction(b.fnClearTable)},m=function(b){return a.isDefined(b.fnReloadAjax)&&a.isFunction(b.fnReloadAjax)},n={fromOptions:function(b,c){return c?new p(b):a.isDefined(b)?a.isDefined(b.fnPromise)&&null!==b.fnPromise?new q(b):a.isDefined(b.sAjaxSource)&&null!==b.sAjaxSource||a.isDefined(b.ajax)&&null!==b.ajax?new r(b):new o(b):new o}},o=function(a){return{options:a,render:function(a,b){k(b,this.options,a)}}},p=function(a){return{options:a,render:function(a,c){var d=this,e=a.$parent,g=f.findDataPropFromScope(e);0===e[g].length&&k(c,d.options,a),a.$on(b.lastRowKey,function(){k(c,d.options,a)})}}},q=function(b){var d,e=function(a,b,e,f){a.aaData=e,c(function(){i(b),a.bDestroy=!0,d?l(d)?(d.fnClearTable(),d.fnDraw(),d.fnAddData(a.aaData)):(d.clear(),d.rows.add(a.aaData).draw()):d=j(b,a,f)},0,!1)};return{options:b,render:function(b,c){var d=this,f=null,g=function(a){e(d.options,c,a,b),f=null},i=function(b){f=a.isFunction(b)?b():b,h(c),f.then(g)},j=function(a){f?f.then(function(){i(a)}):i(a)};b.$watch("dtOptions.fnPromise",function(b){if(!a.isDefined(b))throw new Error("You must provide a promise or a function that returns a promise!");j(b)}),b.$watch("dtOptions.reload",function(a){a&&(b.dtOptions.reload=!1,j(b.dtOptions.fnPromise))})}}},r=function(d){var e,f=function(a,b,d){a.bDestroy=!0,c(function(){if(i(b),e)if(m(e))e.fnReloadAjax(a.sAjaxSource);else{if(l(e))throw new Error('Reload Ajax not supported. Please use the plugin "fnReloadAjax" (https://next.datatables.net/plug-ins/api/fnReloadAjax) or use a more recent version of DataTables (v1.10+)');var c=a.sAjaxSource||a.ajax.url||a.ajax;e.ajax.url(c).load()}else e=j(b,a,d)},0,!1)};return{options:d,render:function(c,e){var g=this;a.isUndefined(g.options.sAjaxDataProp)&&(g.options.sAjaxDataProp=b.sAjaxDataProp),a.isUndefined(g.options.aoColumns)&&(g.options.aoColumns=b.aoColumns),c.$watch("dtOptions.sAjaxSource",function(b){a.isDefined(b)&&(g.options.sAjaxSource=b,a.isDefined(g.options.ajax)&&(a.isObject(g.options.ajax)?g.options.ajax.url=b:g.options.ajax={url:b})),f(d,e,c)}),c.$watch("dtOptions.reload",function(a){a&&(c.dtOptions.reload=!1,f(d,e,c))})}}};return{restrict:"A",scope:{dtOptions:"=",dtColumns:"=",dtColumnDefs:"=",datatable:"@"},link:function(b,c){h(c);var e,f=b.datatable&&"ng"===b.datatable;a.isDefined(b.dtOptions)&&(e={},a.extend(e,b.dtOptions),a.isArray(b.dtColumns)&&(e.aoColumns=b.dtColumns),a.isArray(b.dtColumnDefs)&&(e.aoColumnDefs=b.dtColumnDefs),e.integrateBootstrap?d.integrate(e):d.deIntegrate()),n.fromOptions(e,f).render(b,c)}}}]).directive("dtRows",["$rootScope","DT_DEFAULT_OPTIONS",function(a,b){return{restrict:"A",link:function(c){c.$last===!0&&a.$broadcast(b.lastRowKey)}}}])}(angular),function(a,b){"use strict";b.module("datatables.factory",["datatables.bootstrap","datatables.options"]).factory("DTOptionsBuilder",["DT_DEFAULT_OPTIONS",function(a){var c=function(a){this.obj=a,this.isPresent=function(){return b.isDefined(this.obj)&&null!==this.obj},this.orEmptyObj=function(){return this.isPresent()?this.obj:{}},this.or=function(a){return this.isPresent()?this.obj:a}},d=function(a){return new c(a)},e={integrateBootstrap:!1,hasColVis:!1,hasColReorder:!1,hasTableTools:!1,hasOverrideDom:!1,reloadData:function(){return this.reload=!0,this},withOption:function(a,c){return b.isString(a)&&(this[a]=c),this},withSource:function(a){return this.sAjaxSource=a,this},withDataProp:function(a){return this.sAjaxDataProp=a,this},withFnServerData:function(a){if(!b.isFunction(a))throw new Error("The parameter must be a function");return this.fnServerData=a,this},withPaginationType:function(a){if(!b.isString(a))throw new Error("The pagination type must be provided");return this.sPaginationType=a,this},withLanguage:function(a){return this.oLanguage=a,this},withLanguageSource:function(a){return this.withLanguage({sUrl:a})},withDisplayLength:function(a){return this.iDisplayLength=a,this},withFnPromise:function(a){return this.fnPromise=a,this},withDOM:function(a){return this.sDom=a,this.hasOverrideDom=!0,this},withBootstrap:function(){return this.integrateBootstrap=!0,b.isObject(this.oClasses)?this.oClasses.sPageButtonActive="active":this.oClasses={sPageButtonActive:"active"},this},withBootstrapOptions:function(a){return this.bootstrap=a,this},withColReorderOption:function(a,c){return b.isString(a)&&(this.oColReorder=d(this.oColReorder).orEmptyObj(),this.oColReorder[a]=c),this},withColReorder:function(){var b="R";return this.sDom=b+d(this.sDom).or(a.dom),this.hasColReorder=!0,this},withColReorderOrder:function(a){return b.isArray(a)&&this.withColReorderOption("aiOrder",a),this},withColReorderCallback:function(a){if(!b.isFunction(a))throw new Error("The reorder callback must be a function");return this.withColReorderOption("fnReorderCallback",a),this},withColVisOption:function(a,c){return b.isString(a)&&(this.oColVis=d(this.oColVis).orEmptyObj(),this.oColVis[a]=c),this},withColVis:function(){var b="C";return this.sDom=b+d(this.sDom).or(a.dom),this.hasColVis=!0,this},withColVisStateChange:function(a){if(!b.isFunction(a))throw new Error("The state change must be a function");return this.withColVisOption("fnStateChange",a),this},withTableToolsOption:function(a,c){return b.isString(a)&&(this.oTableTools=d(this.oTableTools).orEmptyObj(),this.oTableTools[a]=c),this},withTableTools:function(c){var e="T";return this.sDom=e+d(this.sDom).or(a.dom),this.hasTableTools=!0,b.isString(c)&&this.withTableToolsOption("sSwfPath",c),this},withTableToolsButtons:function(a){return b.isArray(a)&&this.withTableToolsOption("aButtons",a),this}};return{newOptions:function(){return Object.create(e)},fromSource:function(a){var b=Object.create(e);return b.sAjaxSource=a,b},fromFnPromise:function(a){var b=Object.create(e);return b.fnPromise=a,b}}}]).factory("DTColumnBuilder",function(){var a={withOption:function(a,c){return b.isString(a)&&(this[a]=c),this},withTitle:function(a){return this.sTitle=a,this},withClass:function(a){return this.sClass=a,this},notVisible:function(){return this.bVisible=!1,this},notSortable:function(){return this.bSortable=!1,this},renderWith:function(a){return this.mRender=a,this}};return{newColumn:function(c,d){if(b.isUndefined(c))throw new Error('The parameter "mData" is not defined!');var e=Object.create(a);return e.mData=c,e.sTitle=d||"",e},DTColumn:a}}).factory("DTColumnDefBuilder",["DTColumnBuilder",function(a){return{newColumnDef:function(c){if(b.isUndefined(c))throw new Error('The parameter "targets" must be defined! See https://datatables.net/reference/option/columnDefs.targets');var d=Object.create(a.DTColumn);return d.aTargets=b.isArray(c)?c:[c],d}}}]).factory("DTLoadingTemplate",function(){return{html:'

      Loading...

      '}})}(jQuery,angular),function(a){"use strict";a.module("datatables",["datatables.directive","datatables.factory","datatables.bootstrap"])}(angular),function(a){"use strict";a.module("datatables.options",[]).constant("DT_DEFAULT_OPTIONS",{lastRowKey:"datatable:lastRow",dom:"lfrtip",sAjaxDataProp:"",aoColumns:[]}).service("$DTDefaultOptions",function(){this.bootstrapOptions={},this.setLanguageSource=function(a){return $.extend($.fn.dataTable.defaults,{oLanguage:{sUrl:a}}),this},this.setLanguage=function(a){return $.extend(!0,$.fn.dataTable.defaults,{oLanguage:a}),this},this.setDisplayLength=function(a){return $.extend($.fn.dataTable.defaults,{iDisplayLength:a}),this},this.setBootstrapOptions=function(a){return this.bootstrapOptions=a,this}})}(angular),function(a){"use strict";a.module("datatables.util",[]).factory("$DTPropertyUtil",function(){return{overrideProperties:function(b,c){var d=a.copy(b);if((a.isUndefined(d)||null===d)&&(d={}),a.isUndefined(c)||null===c)return d;if(a.isObject(c))for(var e in c)c.hasOwnProperty(e)&&(d[e]=this.overrideProperties(d[e],c[e]));else d=a.copy(c);return d},findDataPropFromScope:function(b){for(var c in b)if(0!==c.indexOf("$",0)&&b.hasOwnProperty(c)&&a.isArray(b[c]))return c;throw new Error("Cannot find the data property from the scope")}}})}(angular); \ No newline at end of file diff --git a/src/angular-datatables.directive.js b/src/angular-datatables.directive.js index 92dad4210..b6f3b1b3b 100644 --- a/src/angular-datatables.directive.js +++ b/src/angular-datatables.directive.js @@ -1,8 +1,8 @@ (function(angular) { 'use strict'; - angular.module('datatables.directive', ['datatables.options']). - directive('datatable', function(DT_DEFAULT_OPTIONS, $timeout, $DTBootstrap, DTLoadingTemplate) { + angular.module('datatables.directive', ['datatables.options', 'datatables.util']). + directive('datatable', function(DT_DEFAULT_OPTIONS, $timeout, $DTBootstrap, DTLoadingTemplate, $DTPropertyUtil) { var $loading = angular.element(DTLoadingTemplate.html), _showLoading = function ($elem) { $elem.after($loading); @@ -79,7 +79,12 @@ return { options: options, render: function ($scope, $elem) { - var _this = this; + var _this = this, + parentScope = $scope.$parent, + dataProp = $DTPropertyUtil.findDataPropFromScope(parentScope); + if (parentScope[dataProp].length === 0) { + _doRenderDataTable($elem, _this.options, $scope); + } $scope.$on(DT_DEFAULT_OPTIONS.lastRowKey, function () { _doRenderDataTable($elem, _this.options, $scope); }); diff --git a/src/angular-datatables.util.js b/src/angular-datatables.util.js index 8fae80d06..5db5ad402 100644 --- a/src/angular-datatables.util.js +++ b/src/angular-datatables.util.js @@ -15,7 +15,7 @@ if (angular.isUndefined(result) || result === null) { result = {}; } - if (angular.isUndefined(target) || target === null) { + if (angular.isUndefined(target) || target === null) { return result; } if (angular.isObject(target)) { @@ -28,6 +28,20 @@ result = angular.copy(target); } return result; + }, + /** + * Find the first array data property from the given scope. + * It + * @param scope the scope + * @returns {string} the property + */ + findDataPropFromScope: function (scope) { + for (var prop in scope) { + if (prop.indexOf('$', 0) !== 0 && scope.hasOwnProperty(prop) && angular.isArray(scope[prop])) { + return prop; + } + } + throw new Error('Cannot find the data property from the scope'); } }; }); diff --git a/test/spec/angular-datatables.util.spec.js b/test/spec/angular-datatables.util.spec.js index 2d9e67999..987d7580e 100644 --- a/test/spec/angular-datatables.util.spec.js +++ b/test/spec/angular-datatables.util.spec.js @@ -28,27 +28,41 @@ describe('datatables.service', function () { $DTPropertyUtil = $injector.get('$DTPropertyUtil'); })); - it('should overrides the properties', function () { - var result = $DTPropertyUtil.overrideProperties(source, target); - expect(result).not.toBeNull(); - expect(result).toEqual({ - a: 'ta', - b: 'b', - c: { - c1: 'tc1', - c2: 'c2' - }, - d: 'td', - e: { - e1: 'te1', - e2: 'te2' - } + describe(', when overriding the properties,', function () { + it('should overrides the properties', function () { + var result = $DTPropertyUtil.overrideProperties(source, target); + expect(result).not.toBeNull(); + expect(result).toEqual({ + a: 'ta', + b: 'b', + c: { + c1: 'tc1', + c2: 'c2' + }, + d: 'td', + e: { + e1: 'te1', + e2: 'te2' + } + }); + }); + + it('should return the source if the target is null or undefined', function () { + expect($DTPropertyUtil.overrideProperties(source)).toEqual(source); + expect($DTPropertyUtil.overrideProperties(source, null)).toEqual(source); }); }); - it('should return the source if the target is null or undefined', function () { - expect($DTPropertyUtil.overrideProperties(source)).toEqual(source); - expect($DTPropertyUtil.overrideProperties(source, null)).toEqual(source); + describe(', when fetching the data array from the scope,', function () { + it('should fetch the correct data array', inject(function ($rootScope) { + var scope = $rootScope.$new(); + scope.persons = ['foo', 'bar']; + expect($DTPropertyUtil.findDataPropFromScope(scope)).toBe('persons'); + })); + it('should throw an error if the scope does not contain any array', inject(function ($rootScope) { + var scope = $rootScope.$new(); + expect(function() {$DTPropertyUtil.findDataPropFromScope(scope);}).toThrow(new Error('Cannot find the data property from the scope')); + })); }); }); });