Skip to content
This repository was archived by the owner on Feb 2, 2025. It is now read-only.

Commit 2cddcca

Browse files
committed
Resolve Maximum call stack #110
* Add .esformatter * Upgrade angular version dependency to 1.3.0+ * Resolve the maximum call stack when loading the options with promise
1 parent 093c4a3 commit 2cddcca

File tree

203 files changed

+25290
-36488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

203 files changed

+25290
-36488
lines changed

.esformatter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"preset" : "default",
3+
"indent": {
4+
"value": " "
5+
}
6+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Notes
77

88
The required dependencies are:
99

10-
* [AngularJS](http://angular.org) (tested with version 1.2.6+)
10+
* [AngularJS](http://angular.org) (tested with version 1.3.0+)
1111
* [jQuery](http://jquery.com) (tested with version 1.11.0)
1212
* [Datatables](https://datatables.net) (tested with version 1.10+)
1313

bower.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@
3030
"archives.json"
3131
],
3232
"dependencies": {
33-
"angular": ">=1.2.6",
33+
"angular": ">=1.3.0",
3434
"jquery": ">=1.11.0",
35-
"datatables": ">=1.9.4"
35+
"datatables": ">=1.10.0"
3636
},
3737
"devDependencies": {
38-
"angular-mocks": "1.2.6",
39-
"bootstrap": "3.0.1",
40-
"angular-bootstrap": "0.10.0"
38+
"angular-mocks": ">=1.3.0",
39+
"bootstrap": ">=3.0.1",
40+
"angular-bootstrap": ">=0.10.0"
4141
}
4242
}

demo/partials/gettingStarted.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ <h3>Dependencies</h3>
99
The <strong>required dependencies</strong> are:
1010
</p>
1111
<ul>
12-
<li><a href="http://angular.org">AngularJS</a> (tested with version 1.2.6)</li>
13-
<li><a href="http://jquery.com">JQuery</a> (tested with version 1.11.0)</li>
14-
<li><a href="https://datatables.net">Datatables</a> (tested with version 1.9.4 and 1.10+)</li>
12+
<li><a href="http://angular.org">AngularJS</a> version 1.3.0+</li>
13+
<li><a href="http://jquery.com">JQuery</a> version 1.11.0+</li>
14+
<li><a href="https://datatables.net">Datatables</a> version 1.10+</li>
1515
</ul>
1616
<p>
1717
This module has been tested with the following datatables modules:
1818
</p>
1919
<ul>
20-
<li><a href="https://datatables.net/extras/colreorder/">ColReorder</a> with version 1.1.0</li>
21-
<li><a href="https://datatables.net/extras/colvis/">ColVis</a> with version 1.1.0</li>
22-
<li><a href="https://datatables.net/extras/tabletools/">TableTools</a> with version 2.2.0</li>
20+
<li><a href="https://datatables.net/extras/colreorder/">ColReorder</a> with version 1.1.0+</li>
21+
<li><a href="https://datatables.net/extras/colvis/">ColVis</a> with version 1.1.0+</li>
22+
<li><a href="https://datatables.net/extras/tabletools/">TableTools</a> with version 2.2.0+</li>
2323
</ul>
2424
</section>
2525
<hr />

dist/angular-datatables.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,14 +354,16 @@
354354
'use strict';
355355
angular.module('datatables.directive', [
356356
'datatables.renderer',
357-
'datatables.options'
357+
'datatables.options',
358+
'datatables.util'
358359
]).directive('datatable', [
359360
'$q',
360361
'DT_DEFAULT_OPTIONS',
361362
'DTBootstrap',
362363
'DTRendererFactory',
363364
'DTRendererService',
364-
function ($q, DT_DEFAULT_OPTIONS, DTBootstrap, DTRendererFactory, DTRendererService) {
365+
'DTPropertyUtil',
366+
function ($q, DT_DEFAULT_OPTIONS, DTBootstrap, DTRendererFactory, DTRendererService, DTPropertyUtil) {
365367
return {
366368
restrict: 'A',
367369
scope: {
@@ -407,6 +409,11 @@
407409
$q.when($scope.dtColumnDefs)
408410
]).then(function (results) {
409411
var dtOptions = results[0], dtColumns = results[1], dtColumnDefs = results[2];
412+
// Since Angular 1.3, the promise throws a "Maximum call stack size exceeded" when cloning
413+
// See https://github.com/l-lin/angular-datatables/issues/110
414+
DTPropertyUtil.deleteProperty(dtOptions, '$promise');
415+
DTPropertyUtil.deleteProperty(dtColumns, '$promise');
416+
DTPropertyUtil.deleteProperty(dtColumnDefs, '$promise');
410417
var options;
411418
if (angular.isDefined($scope.dtOptions)) {
412419
options = {};
@@ -1008,6 +1015,10 @@
10081015
// Reloading data call the "render()" function again, so it
10091016
// might $watch again. So this flag is here to prevent that!
10101017
_watcherInitialized = false, _render = function (options, $elem, data, $scope) {
1018+
// Since Angular 1.3, the promise renderer is throwing "Maximum call stack size exceeded"
1019+
// By removing the $promise attribute, we avoid an infinite loop when jquery is cloning the data
1020+
// See https://github.com/l-lin/angular-datatables/issues/110
1021+
delete data.$promise;
10111022
options.aaData = data;
10121023
// Add $timeout to be sure that angular has finished rendering before calling datatables
10131024
$timeout(function () {
@@ -1176,6 +1187,11 @@
11761187
result = angular.copy(target);
11771188
}
11781189
return result;
1190+
},
1191+
deleteProperty: function (obj, propertyName) {
1192+
if (angular.isObject(obj)) {
1193+
delete obj[propertyName];
1194+
}
11791195
}
11801196
};
11811197
});

dist/angular-datatables.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ <h1>
5757
</footer>
5858

5959
<script src="vendor/highlightjs/highlight.pack.js"></script>
60-
<script src="vendor/jquery/dist/jquery.min.js"></script>
60+
<script src="vendor/jquery/dist/jquery.js"></script>
6161
<script src="vendor/backtotop/backtotop.min.js"></script>
62-
<script src="vendor/angular/angular.min.js"></script>
62+
<script src="vendor/angular/angular.js"></script>
6363
<script src="vendor/angular-highlightjs/angular-highlightjs.min.js"></script>
6464
<script src="vendor/angular-resource/angular-resource.min.js"></script>
6565
<script src="vendor/angular-ui-router/release/angular-ui-router.min.js"></script>

src/angular-datatables.directive.js

Lines changed: 86 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,93 @@
11
'use strict';
22

3-
angular.module('datatables.directive', ['datatables.renderer', 'datatables.options'])
4-
.directive('datatable', function($q, DT_DEFAULT_OPTIONS, DTBootstrap, DTRendererFactory, DTRendererService) {
5-
return {
6-
restrict: 'A',
7-
scope: {
8-
dtOptions: '=',
9-
dtColumns: '=',
10-
dtColumnDefs: '=',
11-
datatable: '@'
12-
},
13-
compile: function (tElm) {
14-
var _staticHTML = tElm[0].innerHTML;
15-
return function postLink($scope, $elem, iAttrs, ctrl) {
16-
$scope.$watch('[dtOptions, dtColumns, dtColumnDefs]', function(newVal, oldVal) {
17-
if (newVal !== oldVal) {
18-
var newDTOptions = newVal[0],
19-
oldDTOptions = oldVal[0];
20-
// Do not rerender if we want to reload. There are already
21-
// some watchers in the renderers.
22-
if (!newDTOptions.reload || newDTOptions.sAjaxSource !== oldDTOptions.sAjaxSource) {
23-
ctrl.render($elem, ctrl.buildOptionsPromise(), _staticHTML);
24-
} else {
25-
// The reload attribute is set to false here in order
26-
// to recall this watcher again
27-
newDTOptions.reload = false;
28-
}
29-
}
30-
}, true);
31-
ctrl.showLoading($elem);
32-
ctrl.render($elem, ctrl.buildOptionsPromise(), _staticHTML);
33-
};
34-
},
35-
controller: function ($scope) {
36-
var _renderer;
37-
this.showLoading = function ($elem) {
38-
DTRendererService.showLoading($elem);
39-
};
40-
this.buildOptionsPromise = function () {
41-
var defer = $q.defer();
42-
// Build options
43-
$q.all([
44-
$q.when($scope.dtOptions),
45-
$q.when($scope.dtColumns),
46-
$q.when($scope.dtColumnDefs)
47-
]).then(function(results) {
48-
var dtOptions = results[0],
49-
dtColumns = results[1],
50-
dtColumnDefs = results[2];
51-
var options;
52-
if (angular.isDefined($scope.dtOptions)) {
53-
options = {};
54-
angular.extend(options, dtOptions);
55-
// Set the columns
56-
if (angular.isArray(dtColumns)) {
57-
options.aoColumns = dtColumns;
3+
angular.module('datatables.directive', ['datatables.renderer', 'datatables.options', 'datatables.util'])
4+
.directive('datatable', function($q, DT_DEFAULT_OPTIONS, DTBootstrap, DTRendererFactory, DTRendererService, DTPropertyUtil) {
5+
return {
6+
restrict: 'A',
7+
scope: {
8+
dtOptions: '=',
9+
dtColumns: '=',
10+
dtColumnDefs: '=',
11+
datatable: '@'
12+
},
13+
compile: function(tElm) {
14+
var _staticHTML = tElm[0].innerHTML;
15+
return function postLink($scope, $elem, iAttrs, ctrl) {
16+
$scope.$watch('[dtOptions, dtColumns, dtColumnDefs]', function(newVal, oldVal) {
17+
if (newVal !== oldVal) {
18+
var newDTOptions = newVal[0],
19+
oldDTOptions = oldVal[0];
20+
// Do not rerender if we want to reload. There are already
21+
// some watchers in the renderers.
22+
if (!newDTOptions.reload || newDTOptions.sAjaxSource !== oldDTOptions.sAjaxSource) {
23+
ctrl.render($elem, ctrl.buildOptionsPromise(), _staticHTML);
24+
} else {
25+
// The reload attribute is set to false here in order
26+
// to recall this watcher again
27+
newDTOptions.reload = false;
28+
}
5829
}
30+
}, true);
31+
ctrl.showLoading($elem);
32+
ctrl.render($elem, ctrl.buildOptionsPromise(), _staticHTML);
33+
};
34+
},
35+
controller: function($scope) {
36+
var _renderer;
37+
this.showLoading = function($elem) {
38+
DTRendererService.showLoading($elem);
39+
};
40+
this.buildOptionsPromise = function() {
41+
var defer = $q.defer();
42+
// Build options
43+
$q.all([
44+
$q.when($scope.dtOptions),
45+
$q.when($scope.dtColumns),
46+
$q.when($scope.dtColumnDefs)
47+
]).then(function(results) {
48+
var dtOptions = results[0],
49+
dtColumns = results[1],
50+
dtColumnDefs = results[2];
51+
// Since Angular 1.3, the promise throws a "Maximum call stack size exceeded" when cloning
52+
// See https://github.com/l-lin/angular-datatables/issues/110
53+
DTPropertyUtil.deleteProperty(dtOptions, '$promise');
54+
DTPropertyUtil.deleteProperty(dtColumns, '$promise');
55+
DTPropertyUtil.deleteProperty(dtColumnDefs, '$promise');
56+
var options;
57+
if (angular.isDefined($scope.dtOptions)) {
58+
options = {};
59+
angular.extend(options, dtOptions);
60+
// Set the columns
61+
if (angular.isArray(dtColumns)) {
62+
options.aoColumns = dtColumns;
63+
}
5964

60-
// Set the column defs
61-
if (angular.isArray(dtColumnDefs)) {
62-
options.aoColumnDefs = dtColumnDefs;
65+
// Set the column defs
66+
if (angular.isArray(dtColumnDefs)) {
67+
options.aoColumnDefs = dtColumnDefs;
68+
}
69+
// Integrate bootstrap (or not)
70+
if (options.integrateBootstrap) {
71+
DTBootstrap.integrate(options);
72+
} else {
73+
DTBootstrap.deIntegrate();
74+
}
6375
}
64-
// Integrate bootstrap (or not)
65-
if (options.integrateBootstrap) {
66-
DTBootstrap.integrate(options);
76+
defer.resolve(options);
77+
});
78+
return defer.promise;
79+
};
80+
this.render = function($elem, optionsPromise, staticHTML) {
81+
optionsPromise.then(function(options) {
82+
var isNgDisplay = $scope.datatable && $scope.datatable === 'ng';
83+
// Render dataTable
84+
if (_renderer) {
85+
_renderer.withOptions(options).render($scope, $elem, staticHTML);
6786
} else {
68-
DTBootstrap.deIntegrate();
87+
_renderer = DTRendererFactory.fromOptions(options, isNgDisplay).render($scope, $elem, staticHTML);
6988
}
70-
}
71-
defer.resolve(options);
72-
});
73-
return defer.promise;
74-
};
75-
this.render = function ($elem, optionsPromise, staticHTML) {
76-
optionsPromise.then(function(options) {
77-
var isNgDisplay = $scope.datatable && $scope.datatable === 'ng';
78-
// Render dataTable
79-
if (_renderer) {
80-
_renderer.withOptions(options).render($scope, $elem, staticHTML);
81-
} else {
82-
_renderer = DTRendererFactory.fromOptions(options, isNgDisplay).render($scope, $elem, staticHTML);
83-
}
84-
});
85-
};
86-
}
87-
};
88-
});
89+
});
90+
};
91+
}
92+
};
93+
});

src/angular-datatables.renderer.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ angular.module('datatables.renderer', ['datatables.factory', 'datatables.options
121121
// might $watch again. So this flag is here to prevent that!
122122
_watcherInitialized = false,
123123
_render = function (options, $elem, data, $scope) {
124+
// Since Angular 1.3, the promise renderer is throwing "Maximum call stack size exceeded"
125+
// By removing the $promise attribute, we avoid an infinite loop when jquery is cloning the data
126+
// See https://github.com/l-lin/angular-datatables/issues/110
127+
delete data.$promise;
124128
options.aaData = data;
125129
// Add $timeout to be sure that angular has finished rendering before calling datatables
126130
$timeout(function () {

src/angular-datatables.util.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
2-
angular.module('datatables.util', []).factory('DTPropertyUtil', function () {
2+
angular.module('datatables.util', []).factory('DTPropertyUtil', function() {
33
return {
44
/**
55
* Overrides the source property with the given target properties.
@@ -8,7 +8,7 @@ angular.module('datatables.util', []).factory('DTPropertyUtil', function () {
88
* @param target the target properties
99
* @returns {*} the object overrided
1010
*/
11-
overrideProperties: function (source, target) {
11+
overrideProperties: function(source, target) {
1212
var result = angular.copy(source);
1313

1414
if (angular.isUndefined(result) || result === null) {
@@ -27,6 +27,11 @@ angular.module('datatables.util', []).factory('DTPropertyUtil', function () {
2727
result = angular.copy(target);
2828
}
2929
return result;
30+
},
31+
deleteProperty: function(obj, propertyName) {
32+
if (angular.isObject(obj)) {
33+
delete obj[propertyName];
34+
}
3035
}
3136
};
3237
});

test/karma.conf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// http://karma-runner.github.io/0.10/config/configuration-file.html
33

44
module.exports = function(config) {
5+
'use strict';
56
config.set({
67
// base path, that will be used to resolve files and exclude
78
basePath: '../',

test/spec/angular-datatables.util.spec.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
describe('datatables.service', function () {
1+
describe('datatables.service', function() {
22
'use strict';
33
beforeEach(module('datatables.util'));
44

5-
describe('DTPropertyUtil', function () {
5+
describe('DTPropertyUtil', function() {
66
var DTPropertyUtil,
77
source = {
88
a: 'a',
@@ -24,12 +24,12 @@ describe('datatables.service', function () {
2424
}
2525
};
2626

27-
beforeEach(inject(function ($injector) {
27+
beforeEach(inject(function($injector) {
2828
DTPropertyUtil = $injector.get('DTPropertyUtil');
2929
}));
3030

31-
describe(', when overriding the properties,', function () {
32-
it('should overrides the properties', function () {
31+
describe(', when overriding the properties,', function() {
32+
it('should overrides the properties', function() {
3333
var result = DTPropertyUtil.overrideProperties(source, target);
3434
expect(result).not.toBeNull();
3535
expect(result).toEqual({
@@ -47,10 +47,19 @@ describe('datatables.service', function () {
4747
});
4848
});
4949

50-
it('should return the source if the target is null or undefined', function () {
50+
it('should return the source if the target is null or undefined', function() {
5151
expect(DTPropertyUtil.overrideProperties(source)).toEqual(source);
5252
expect(DTPropertyUtil.overrideProperties(source, null)).toEqual(source);
5353
});
5454
});
55+
describe(', when deleting a property from an object,', function() {
56+
var foo = {
57+
foo: 'Foo'
58+
};
59+
it('should remove the property if it exists', function() {
60+
DTPropertyUtil.deleteProperty(foo, 'foo');
61+
expect(foo.foo).toBeUndefined();
62+
});
63+
});
5564
});
5665
});

0 commit comments

Comments
 (0)