2
schangxiang@126.com
2024-08-16 b47c50a2a514def7374b32d7194b2c599cba5625
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/**
 * ngTable: Table + Angular JS
 *
 * @author Vitalii Savchuk <esvit666@gmail.com>
 * @url https://github.com/esvit/ng-table/
 * @license New BSD License <http://creativecommons.org/licenses/BSD/>
 */
 
(function(){
    /**
     * @ngdoc object
     * @name ngTableController
     *
     * @description
     * Each {@link ngTable ngTable} directive creates an instance of `ngTableController`
     */
    angular.module('ngTable').controller('ngTableController', ['$scope', 'NgTableParams', '$timeout', '$parse', '$compile', '$attrs', '$element',
        'ngTableColumn', 'ngTableEventsChannel',
        function($scope, NgTableParams, $timeout, $parse, $compile, $attrs, $element, ngTableColumn, ngTableEventsChannel) {
            var isFirstTimeLoad = true;
            $scope.$filterRow = {};
            $scope.$loading = false;
 
            // until such times as the directive uses an isolated scope, we need to ensure that the check for
            // the params field only consults the "own properties" of the $scope. This is to avoid seeing the params
            // field on a $scope higher up in the prototype chain
            if (!$scope.hasOwnProperty("params")) {
                $scope.params = new NgTableParams(true);
            }
            $scope.params.settings().$scope = $scope;
 
            var delayFilter = (function() {
                var timer = 0;
                return function(callback, ms) {
                    $timeout.cancel(timer);
                    timer = $timeout(callback, ms);
                };
            })();
 
            function onDataReloadStatusChange (newStatus/*, oldStatus*/) {
                if (!newStatus || $scope.params.hasErrorState()) {
                    return;
                }
 
                $scope.params.settings().$scope = $scope;
 
                var currentParams = $scope.params;
                var filterOptions = currentParams.settings().filterOptions;
 
                if (currentParams.hasFilterChanges()) {
                    var applyFilter = function () {
                        currentParams.page(1);
                        currentParams.reload();
                    };
                    if (filterOptions.filterDelay) {
                        delayFilter(applyFilter, filterOptions.filterDelay);
                    } else {
                        applyFilter();
                    }
                } else {
                    currentParams.reload();
                }
            }
 
            // watch for when a new NgTableParams is bound to the scope
            // CRITICAL: the watch must be for reference and NOT value equality; this is because NgTableParams maintains
            // the current data page as a field. Checking this for value equality would be terrible for performance
            // and potentially cause an error if the items in that array has circular references
            $scope.$watch('params', function(newParams, oldParams){
                if (newParams === oldParams || !newParams) {
                    return;
                }
 
                newParams.reload();
            }, false);
 
            $scope.$watch('params.isDataReloadRequired()', onDataReloadStatusChange);
 
            this.compileDirectiveTemplates = function () {
                if (!$element.hasClass('ng-table')) {
                    $scope.templates = {
                        header: ($attrs.templateHeader ? $attrs.templateHeader : 'ng-table/header.html'),
                        pagination: ($attrs.templatePagination ? $attrs.templatePagination : 'ng-table/pager.html')
                    };
                    $element.addClass('ng-table');
                    var headerTemplate = null;
 
                    // $element.find('> thead').length === 0 doesn't work on jqlite
                    var theadFound = false;
                    angular.forEach($element.children(), function(e) {
                        if (e.tagName === 'THEAD') {
                            theadFound = true;
                        }
                    });
                    if (!theadFound) {
                        headerTemplate = angular.element(document.createElement('thead')).attr('ng-include', 'templates.header');
                        $element.prepend(headerTemplate);
                    }
                    var paginationTemplate = angular.element(document.createElement('div')).attr({
                        'ng-table-pagination': 'params',
                        'template-url': 'templates.pagination'
                    });
                    $element.after(paginationTemplate);
                    if (headerTemplate) {
                        $compile(headerTemplate)($scope);
                    }
                    $compile(paginationTemplate)($scope);
                }
            };
 
            this.loadFilterData = function ($columns) {
                angular.forEach($columns, function ($column) {
                    var result;
                    result = $column.filterData($scope);
                    if (!result) {
                        delete $column.filterData;
                        return;
                    }
 
                    // if we're working with a deferred object or a promise, let's wait for the promise
                    /* WARNING: support for returning a $defer is depreciated */
                    if ((angular.isObject(result) && (angular.isObject(result.promise) || angular.isFunction(result.then)))) {
                        var pData = angular.isFunction(result.then) ? result : result.promise;
                        delete $column.filterData;
                        return pData.then(function(data) {
                            // our deferred can eventually return arrays, functions and objects
                            if (!angular.isArray(data) && !angular.isFunction(data) && !angular.isObject(data)) {
                                // if none of the above was found - we just want an empty array
                                data = [];
                            }
                            $column.data = data;
                        });
                    }
                    // otherwise, we just return what the user gave us. It could be a function, array, object, whatever
                    else {
                        return $column.data = result;
                    }
                });
            };
 
            this.buildColumns = function (columns) {
                var result = [];
                columns.forEach(function(col){
                    result.push(ngTableColumn.buildColumn(col, $scope, result));
                });
                return result
            };
 
            this.parseNgTableDynamicExpr = function (attr) {
                if (!attr || attr.indexOf(" with ") > -1) {
                    var parts = attr.split(/\s+with\s+/);
                    return {
                        tableParams: parts[0],
                        columns: parts[1]
                    };
                } else {
                    throw new Error('Parse error (expected example: ng-table-dynamic=\'tableParams with cols\')');
                }
            };
 
            this.setupBindingsToInternalScope = function(tableParamsExpr){
 
                // note: this we're setting up watches to simulate angular's isolated scope bindings
 
                // note: is REALLY important to watch for a change to the ngTableParams *reference* rather than
                // $watch for value equivalence. This is because ngTableParams references the current page of data as
                // a field and it's important not to watch this
                var tableParamsGetter = $parse(tableParamsExpr);
                $scope.$watch(tableParamsGetter, (function (params) {
                    if (angular.isUndefined(params)) {
                        return;
                    }
                    $scope.paramsModel = tableParamsGetter;
                    $scope.params = params;
                }), false);
 
                setupFilterRowBindingsToInternalScope();
                setupGroupRowBindingsToInternalScope();
            };
 
            function setupFilterRowBindingsToInternalScope(){
                if ($attrs.showFilter) {
                    $scope.$parent.$watch($attrs.showFilter, function(value) {
                        $scope.show_filter = value;
                    });
                } else {
                    $scope.$watch(hasVisibleFilterColumn, function(value){
                        $scope.show_filter = value;
                    })
                }
 
                if ($attrs.disableFilter) {
                    $scope.$parent.$watch($attrs.disableFilter, function(value) {
                        $scope.$filterRow.disabled = value;
                    });
                }
            }
 
            function setupGroupRowBindingsToInternalScope(){
                $scope.$groupRow = {};
                if ($attrs.showGroup) {
                    var showGroupGetter = $parse($attrs.showGroup);
                    $scope.$parent.$watch(showGroupGetter, function(value) {
                        $scope.$groupRow.show = value;
                    });
                    if (showGroupGetter.assign){
                        // setup two-way databinding thus allowing ngTableGrowRow to assign to the showGroup expression
                        $scope.$watch('$groupRow.show', function(value) {
                            showGroupGetter.assign($scope.$parent, value);
                        });
                    }
                } else{
                    $scope.$watch('params.hasGroup()', function(newValue) {
                        $scope.$groupRow.show = newValue;
                    });
                }
            }
 
            function getVisibleColumns(){
                return ($scope.$columns || []).filter(function(c){
                    return c.show($scope);
                });
            }
 
            function hasVisibleFilterColumn(){
                if (!$scope.$columns) return false;
 
                return some($scope.$columns, function($column){
                    return $column.show($scope) && $column.filter($scope);
                });
            }
 
            function some(array, predicate){
                var found = false;
                for (var i = 0; i < array.length; i++) {
                    var obj = array[i];
                    if (predicate(obj)){
                        found = true;
                        break;
                    }
                }
                return found;
            }
 
            function commonInit(){
                ngTableEventsChannel.onAfterReloadData(bindDataToScope, $scope, isMyPublisher);
                ngTableEventsChannel.onPagesChanged(bindPagesToScope, $scope, isMyPublisher);
 
                function bindDataToScope(params, newDatapage){
                    if (params.hasGroup()) {
                        $scope.$groups = newDatapage || [];
                        $scope.$groups.visibleColumnCount = getVisibleColumns().length;
                    } else {
                        $scope.$data = newDatapage;
                    }
                }
 
                function bindPagesToScope(params, newPages){
                    $scope.pages = newPages
                }
 
                function isMyPublisher(publisher){
                    return $scope.params === publisher;
                }
            }
 
            commonInit();
        }]);
})();