({}, {
12 | dataset: demoData
13 | });
14 | }
15 |
16 | interface Person {
17 | name: string;
18 | age: number;
19 | }
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/demo-data.ts:
--------------------------------------------------------------------------------
1 | export const demoData = [{"name":"Karen","age":45,"money":798,"country":"Czech Republic"},{"name":"Cat","age":49,"money":749,"country":"Czech Republic"},{"name":"Bismark","age":48,"money":672,"country":"Denmark"},{"name":"Markus","age":41,"money":695,"country":"Costa Rica"},{"name":"Anthony","age":45,"money":559,"country":"Japan"},{"name":"Alex","age":55,"money":645,"country":"Czech Republic"},{"name":"Stephane","age":57,"money":662,"country":"Japan"},{"name":"Alex","age":59,"money":523,"country":"American Samoa"},{"name":"Tony","age":56,"money":540,"country":"Canada"},{"name":"Cat","age":57,"money":746,"country":"China"},{"name":"Christian","age":59,"money":572,"country":"Canada"},{"name":"Tony","age":60,"money":649,"country":"Japan"},{"name":"Cat","age":47,"money":675,"country":"Denmark"},{"name":"Stephane","age":50,"money":674,"country":"China"},{"name":"Markus","age":40,"money":549,"country":"Portugal"},{"name":"Anthony","age":53,"money":660,"country":"Bahamas"},{"name":"Stephane","age":54,"money":549,"country":"China"},{"name":"Karen","age":50,"money":611,"country":"American Samoa"},{"name":"Therese","age":53,"money":754,"country":"China"},{"name":"Bismark","age":49,"money":791,"country":"Canada"},{"name":"Daraek","age":56,"money":640,"country":"Costa Rica"},{"name":"Tony","age":43,"money":674,"country":"Canada"},{"name":"Karen","age":47,"money":700,"country":"Portugal"},{"name":"Therese","age":47,"money":718,"country":"Czech Republic"},{"name":"Karen","age":50,"money":655,"country":"Japan"},{"name":"Daraek","age":59,"money":581,"country":"American Samoa"},{"name":"Daraek","age":60,"money":595,"country":"Portugal"},{"name":"Markus","age":44,"money":607,"country":"China"},{"name":"Simon","age":58,"money":728,"country":"Japan"},{"name":"Simon","age":49,"money":655,"country":"Bahamas"}];
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/images/webpack-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/demo-apps/ts-webpack/src/shared/images/webpack-logo.png
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/index.ts:
--------------------------------------------------------------------------------
1 | export { demoData } from './demo-data';
2 | export { Person } from './person';
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/person.ts:
--------------------------------------------------------------------------------
1 | export interface Person {
2 | name: string;
3 | age: number;
4 | }
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/site.scss:
--------------------------------------------------------------------------------
1 | body {
2 | background: url("images/webpack-logo.png") no-repeat bottom right;
3 | }
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/shared/vendor-styles.scss:
--------------------------------------------------------------------------------
1 | @import '~bootstrap-css-only/css/bootstrap.css';
2 | @import '~ng-table/src/styles/ng-table.scss'
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/type-declarations/angular-route.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@types/angular-route' {
2 | import mod = angular.route;
3 | export = mod;
4 | }
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/src/type-declarations/global.d.ts:
--------------------------------------------------------------------------------
1 | // fake the nodejs require function so that we can add 'require' calls for html files;
2 | // these calls to 'require' will then be converted by webpack ngtemplate-loader
3 | // note that I would have prefered to use standard es2015 import for these
4 | // html files but that would have meant using typescript 2 feature of implicit
5 | // ambient modules which in turn would have meant turning off noImplicitAny checks
6 | // which is a VERY bad idea
7 | declare function require(path: string): any;
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "removeComments": false,
11 | "noEmitOnError": true, // WARNING: NOT WORKING in webpack ie a compiler error still results in bundled JS
12 | "noImplicitAny": true,
13 | "noImplicitReturns": true,
14 | "suppressImplicitAnyIndexErrors": true
15 | },
16 | "exclude": ["node_modules"],
17 | "awesomeTypescriptLoaderOptions": {
18 | "forkChecker": true,
19 | "useWebpackText": true //Allows loaders to be chained to awesome-typescript-loader.
20 | }
21 | }
--------------------------------------------------------------------------------
/demo-apps/ts-webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const merge = require('webpack-merge');
3 |
4 | module.exports = (env = { prod: false, debug: false, port: 8080, host: 'localhost' }) => {
5 |
6 | const parts = require('../../scripts/webpack/appParts')(__dirname, env);
7 |
8 | const extactedStyles = {
9 | entry: {
10 | 'vendor-styles': path.join(__dirname, 'src', 'shared', 'vendor-styles.scss'),
11 | 'site-styles': path.join(__dirname, 'src', 'shared', 'site.scss')
12 | }
13 | };
14 |
15 | return merge(
16 | {
17 | entry: {
18 | main: path.join(__dirname, 'src', 'main.ts')
19 | }
20 | },
21 | parts.asAppBundle(),
22 | parts.extractBundle({
23 | vendorSelector: parts.isNotAppModuleSelector
24 | }),
25 | parts.asAppBundle(),
26 | extactedStyles,
27 | parts.isDevServer ? parts.sass() : parts.extractSassChunks(extactedStyles.entry),
28 | parts.typescript(),
29 | parts.inlineImages(),
30 | parts.inlineHtmlTemplates(),
31 | parts.inlineNgTableHtmlTemplates(),
32 | parts.useHtmlPlugin(),
33 | parts.forEnvironment()
34 | );
35 | }
--------------------------------------------------------------------------------
/demo-site/CNAME:
--------------------------------------------------------------------------------
1 | ng-table.com
2 |
--------------------------------------------------------------------------------
/demo-site/css/docs.css:
--------------------------------------------------------------------------------
1 | body > .row {
2 | width: 100%;
3 | }
4 |
5 | [ng-view] {
6 | padding: 20px 0;
7 | }
8 |
9 | .row .page-header {
10 | margin-top: 0;
11 | padding: 0;
12 | }
13 | .page-header h1 {
14 | margin: 0;
15 | padding: 5px 0px;
16 | }
17 |
18 | .bs-docs-sidebar.affix {
19 | position: static;
20 | }
21 | @media (min-width: 768px) {
22 | .bs-docs-sidebar {
23 | padding-left: 20px;
24 | }
25 | }
26 | /* First level of nav */
27 | .bs-docs-sidenav {
28 | margin-top: 20px;
29 | margin-bottom: 20px;
30 | border-left: 2px solid #b94a48;
31 | }
32 |
33 | .bs-docs-sidenav h1 {
34 | margin: 0;
35 | padding: 10px 18px;
36 | font-size: 24px;
37 | }
38 | .bs-docs-sidenav h1 a {
39 | color: #b94a48;
40 | text-decoration: none;
41 | }
42 |
43 | /* All levels of nav */
44 | .bs-docs-sidebar .nav > li > a {
45 | display: block;
46 | font-size: 13px;
47 | font-weight: 500;
48 | color: #999;
49 | padding: 4px 20px;
50 | }
51 | .bs-docs-sidebar .nav > li > a:hover,
52 | .bs-docs-sidebar .nav > li > a:focus {
53 | padding-left: 19px;
54 | color: #b94a48;
55 | text-decoration: none;
56 | background-color: transparent;
57 | }
58 | .bs-docs-sidebar .nav > .active > a,
59 | .bs-docs-sidebar .nav > .active:hover > a,
60 | .bs-docs-sidebar .nav > .active:focus > a {
61 | padding-left: 18px;
62 | font-weight: bold;
63 | color: #b94a48;
64 | background-color: transparent;
65 | }
66 |
67 | /* Nav: second level (shown on .active) */
68 | .bs-docs-sidebar .nav .nav {
69 | display: none; /* Hide by default, but at >768px, show it */
70 | padding-bottom: 10px;
71 | }
72 | .bs-docs-sidebar .nav .nav > li > a {
73 | padding-top: 1px;
74 | padding-bottom: 1px;
75 | padding-left: 30px;
76 | font-size: 12px;
77 | font-weight: normal;
78 | }
79 | .bs-docs-sidebar .nav .nav > li > a:hover,
80 | .bs-docs-sidebar .nav .nav > li > a:focus {
81 | padding-left: 29px;
82 | }
83 | .bs-docs-sidebar .nav .nav > .active > a,
84 | .bs-docs-sidebar .nav .nav > .active:hover > a,
85 | .bs-docs-sidebar .nav .nav > .active:focus > a {
86 | font-weight: 500;
87 | padding-left: 28px;
88 | }
89 |
90 | /* Back to top (hidden on mobile) */
91 | .back-to-top {
92 | display: none;
93 | margin-top: 10px;
94 | margin-left: 10px;
95 | padding: 4px 10px;
96 | font-size: 12px;
97 | font-weight: 500;
98 | color: #999;
99 | }
100 | .back-to-top:hover {
101 | text-decoration: none;
102 | color: #b94a48;
103 | }
104 |
105 | @media (min-width: 768px) {
106 | .back-to-top {
107 | display: block;
108 | }
109 | }
110 |
111 | /* Show and affix the side nav when space allows it */
112 | @media (min-width: 992px) {
113 | .bs-docs-sidebar .nav > .active > ul {
114 | display: block;
115 | }
116 | /* Widen the fixed sidebar */
117 | .bs-docs-sidebar.affix,
118 | .bs-docs-sidebar.affix-bottom {
119 | width: 213px;
120 | }
121 | .bs-docs-sidebar.affix {
122 | position: fixed; /* Undo the static from mobile first approach */
123 | top: 20px;
124 | }
125 | .bs-docs-sidebar.affix-bottom {
126 | position: absolute; /* Undo the static from mobile first approach */
127 | }
128 | .bs-docs-sidebar.affix-bottom .bs-docs-sidenav,
129 | .bs-docs-sidebar.affix .bs-docs-sidenav {
130 | margin-top: 0;
131 | margin-bottom: 0;
132 | }
133 | }
134 | @media (min-width: 1200px) {
135 | /* Widen the fixed sidebar again */
136 | .bs-docs-sidebar.affix-bottom,
137 | .bs-docs-sidebar.affix {
138 | width: 263px;
139 | }
140 | }
141 |
142 |
143 | /* Footer
144 | -------------------------------------------------- */
145 |
146 | .bs-footer {
147 | padding: 20px 0;
148 | margin-top: 10px;
149 | text-align: center;
150 | border-top: 1px solid #e5e5e5;
151 | }
152 | .bs-footer p {
153 | margin-bottom: 0;
154 | color: #777;
155 | }
156 | .footer-links {
157 | margin: 10px 0;
158 | }
159 | .footer-links li {
160 | display: inline;
161 | padding: 0 2px;
162 | }
163 | .footer-links li:first-child {
164 | padding-left: 0;
165 | }
166 |
167 |
168 | /* Table */
169 | .variables-matrix {
170 | border:1px solid #ddd;
171 | width:100%;
172 | margin:10px 0;
173 | }
174 |
175 | .variables-matrix td,
176 | .variables-matrix th {
177 | padding:10px;
178 | }
179 |
180 | .variables-matrix td {
181 | border-top:1px solid #eee;
182 | }
183 |
184 | .variables-matrix td + td,
185 | .variables-matrix th + th {
186 | border-left:1px solid #eee;
187 | }
188 |
189 | .variables-matrix tr:nth-child(even) td {
190 | background:#f5f5f5;
191 | }
192 |
193 | .variables-matrix th {
194 | background:#f1f1f1;
195 | }
196 |
197 | /* bootstrap callouts
198 | -------------------------------------------------- */
199 | .bs-callout {
200 | padding: 20px;
201 | margin: 20px 0;
202 | border: 1px solid #eee;
203 | border-left-width: 5px;
204 | border-radius: 3px;
205 | }
206 | .bs-callout h4 {
207 | margin-top: 0;
208 | margin-bottom: 5px;
209 | }
210 | .bs-callout p:last-child {
211 | margin-bottom: 0;
212 | }
213 | .bs-callout code {
214 | border-radius: 3px;
215 | }
216 | .bs-callout+.bs-callout {
217 | margin-top: -5px;
218 | }
219 | .bs-callout-default {
220 | border-left-color: #777;
221 | }
222 | .bs-callout-default h4 {
223 | color: #777;
224 | }
225 | .bs-callout-success {
226 | border-left-color: #5cb85c;
227 | }
228 | .bs-callout-success h4 {
229 | color: #5cb85c;
230 | }
231 | .bs-callout-danger {
232 | border-left-color: #d9534f;
233 | }
234 | .bs-callout-danger h4 {
235 | color: #d9534f;
236 | }
237 | .bs-callout-warning {
238 | border-left-color: #f0ad4e;
239 | }
240 | .bs-callout-warning h4 {
241 | color: #f0ad4e;
242 | }
243 | .bs-callout-info {
244 | border-left-color: #1b809e;
245 | }
246 | .bs-callout-info h4 {
247 | color: #1b809e;
248 | }
249 |
250 | /* extra callout styles */
251 | .bs-callout dl {
252 | margin-top: 10px
253 | }
254 |
--------------------------------------------------------------------------------
/demo-site/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/demo-site/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/demo-site/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/demo-site/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/demo-site/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/demo-site/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/demo-site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ngTable Examples
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
35 |
36 |
37 |
71 |
72 |
73 |
74 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/demo-site/js/embed-codepen.min.js:
--------------------------------------------------------------------------------
1 | angular.module("embedCodepen.config",[]).value("embedCodepen.config",{debug:!0}),angular.module("embedCodepen.directives",[]),angular.module("embedCodepen",["embedCodepen.config","embedCodepen.directives"]),function(){function e(){return{restrict:"A",scope:{themeId:"@",slugHash:"@",user:"@",defaultTab:"@",height:"@",showTabBar:"@",animations:"@",border:"@",borderColor:"@",tabBarColor:"@",tabLinkColor:"@",activeTabColor:"@",activeLinkColor:"@",linkLogoColor:"@","class":"@",customCssUrl:"@"},template:[""].join(""),link:function(e,o){if(e.slugHash&&e.user){var r=document.location.protocol+"//codepen.io/"+e.user+"/embed/"+e.slugHash+"?user="+e.user,a=["themeId","defaultTab","height","showTabBar","animations","border","borderColor","tabBarColor","tabLinkColor","activeTabColor","activeLinkColor","linkLogoColor","class","customCssUrl"];angular.forEach(a,function(o){e[o]&&(r+="&"+o+"="+e[o])}),o.find("iframe").attr("src",r).attr("height",e.height).attr("id","cp_embed_"+e.slugHash)}}}}e.$inject=[],angular.module("embedCodepen.directives").directive("slugHash",e)}();
--------------------------------------------------------------------------------
/demo-site/js/embed-codepen.version.txt:
--------------------------------------------------------------------------------
1 | 1.1.1
2 |
--------------------------------------------------------------------------------
/demo-site/views/columns/demo-reordering.html:
--------------------------------------------------------------------------------
1 | See the Pen Reordering columns by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/columns/demo-visibility.html:
--------------------------------------------------------------------------------
1 | See the Pen Showing and hiding columns by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/editing/demo-batch.html:
--------------------------------------------------------------------------------
1 | See the Pen Batch editable table by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/editing/demo-inline.html:
--------------------------------------------------------------------------------
1 | See the Pen Inline row editing by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/events/demo-subscribe.html:
--------------------------------------------------------------------------------
1 | See the Pen Subscribing to NgTableParams events by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/events/demo-unsubscribe.html:
--------------------------------------------------------------------------------
1 | See the Pen Unsubscribing to NgTableParams events by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-api.html:
--------------------------------------------------------------------------------
1 | See the Pen Change filter values programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-custom-template.html:
--------------------------------------------------------------------------------
1 | See the Pen Custom filter template by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-customize-algorithm.html:
--------------------------------------------------------------------------------
1 | See the Pen Customize filter algorithm by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-enabling.html:
--------------------------------------------------------------------------------
1 | See the Pen Enable filters programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-filtering-basic.html:
--------------------------------------------------------------------------------
1 | See the Pen Filtering - basic example by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-multi-template.html:
--------------------------------------------------------------------------------
1 | See the Pen Multi-template filter by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-nested-property.html:
--------------------------------------------------------------------------------
1 | See the Pen Nested properties filters by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/filtering/demo-select.html:
--------------------------------------------------------------------------------
1 | See the Pen Select Filter by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-cell-values.html:
--------------------------------------------------------------------------------
1 | See the Pen Data cell template by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-custom-header.html:
--------------------------------------------------------------------------------
1 | See the Pen Custom header by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-dynamic-html-values.html:
--------------------------------------------------------------------------------
1 | See the Pen Advanced cell value display in ngTableDynamic (via HTML) by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-dynamic-js-values.html:
--------------------------------------------------------------------------------
1 | See the Pen Display cell values within ngTableDynamic by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-header-cell-basic.html:
--------------------------------------------------------------------------------
1 | See the Pen Header cell template - simple by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-header-cell-full.html:
--------------------------------------------------------------------------------
1 | See the Pen Header cell template - full by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/formatting/demo-row.html:
--------------------------------------------------------------------------------
1 | See the Pen Row template by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/global-customization/demo-defaults.html:
--------------------------------------------------------------------------------
1 | See the Pen Change default settings and paramater values by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/global-customization/demo-response-interceptors.html:
--------------------------------------------------------------------------------
1 | See the Pen getData response interceptors by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/grouping/demo-api.html:
--------------------------------------------------------------------------------
1 | See the Pen Change grouping column programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/grouping/demo-enabling.html:
--------------------------------------------------------------------------------
1 | See the Pen Enable grouping programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/grouping/demo-grouping-basic.html:
--------------------------------------------------------------------------------
1 | See the Pen Grouping - basic example by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/grouping/demo-grouping-fn.html:
--------------------------------------------------------------------------------
1 | See the Pen Custom grouping function by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/grouping/demo-summary.html:
--------------------------------------------------------------------------------
1 | See the Pen Groups with summary row by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/intro/demo-real-world.html:
--------------------------------------------------------------------------------
1 | See the Pen ngTable - Real world example by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/intro/overview.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
Steps for getting started (example on right)
13 |
14 | - Add references to AngularJS. EG:
15 |
16 | <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.js"></script>
17 |
18 |
19 | - Add references to ngTable's javascript and css files. EG:
20 |
21 | <link rel="stylesheet"; href="https://unpkg.com/ng-table@2.0.2/bundles/ng-table.min.css">
22 | <script src="https://unpkg.com/ng-table@2.0.2/bundles/ng-table.min.js"></script>
23 |
24 |
25 | Note: ng-table npm package distributes individual ES2015 modules. Use these instead, if your app uses webpack to bundle vendor dependencies
26 |
27 |
28 | - Where you declare your app module, add
ngTable
:
29 |
30 | angular.module("myApp", ["ngTable"]);
31 |
32 |
33 | - In your html file within the controller where you plan to use
ng-table
, add:
34 |
35 | <table ng-table="vm.tableParams" class="table" show-filter="true">
36 | <tr ng-repeat="user in $data">
37 | <td title="'Name'" filter="{ name: 'text'}" sortable="'name'">
38 | {{user.name}}</td>
39 | <td title="'Age'" filter="{ age: 'number'}" sortable="'age'">
40 | {{user.age}}</td>
41 | </tr>
42 | </table>
43 |
44 |
45 | - In your javascript file within the controller where you plan to use
ng-table
, declare:
46 |
47 | var self = this;
48 | var data = [{name: "Moroni", age: 50} /*,*/];
49 | self.tableParams = new NgTableParams({}, { dataset: data});
50 |
51 |
52 |
53 |
54 |
55 |
56 |
Example
57 |
58 |
59 |
60 |
61 |
62 | {{user.name}}
63 | |
64 |
65 | {{user.age}}
66 | |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/demo-site/views/loading/demo-external-array.html:
--------------------------------------------------------------------------------
1 | See the Pen Loading data - External array by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/loading/demo-lazy-loaded.html:
--------------------------------------------------------------------------------
1 | See the Pen Loading data - lazy loading managed array by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/loading/demo-managed-array.html:
--------------------------------------------------------------------------------
1 | See the Pen Loading data - managed array by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/loading/overview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
There are broadly two options for getting data loaded into a table. These are discussed below
9 |
10 |
11 | - 1. Managed array
12 | -
13 | Hand
NgTableParams
an in-memory array and let it do the filtering, sorting and paging
14 | on that array. Eg:
15 |
16 | var dataset = [{ name: 'christian', age: 21 }, { name: 'anthony', age: 88 }];
17 | var tp = new NgTableParams({}, { dataset: dataset });
18 |
19 |
20 | - 2. External array
21 | -
22 | Hand
NgTableParams
a custom getData
function that it will call to load
23 | data. Eg:
24 |
25 | var tp = new NgTableParams({}, { getData: function(params){
26 | /* code to fetch data that matches the params values EG: */
27 | return executeQuery(params).then(function(data){
28 | params.total(data.inlineCount);
29 | return data.results;
30 | });
31 | }});
32 |
33 |
34 | - Typically you will use this option to load server-side data
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo-site/views/pagination/demo-api.html:
--------------------------------------------------------------------------------
1 | See the Pen Change page / page controls programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/pagination/demo-pager-basic.html:
--------------------------------------------------------------------------------
1 | See the Pen Pagination - basic example by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/sorting/demo-api.html:
--------------------------------------------------------------------------------
1 | See the Pen Change sorting programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/sorting/demo-enabling.html:
--------------------------------------------------------------------------------
1 | See the Pen Enable sorting programmatically by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/sorting/demo-sorting-basic.html:
--------------------------------------------------------------------------------
1 | See the Pen Sorting - basic example by christianacca (@christianacca) on CodePen.
2 |
--------------------------------------------------------------------------------
/demo-site/views/todo.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
Feel free to contribute a codepen for this missing demo
7 |
Fork this codepen as the base template
8 |
To contribute: create an github issue with a link to your codepen
9 |
10 |
--------------------------------------------------------------------------------
/e2e/async-await-example.spec.ts:
--------------------------------------------------------------------------------
1 | import { DemoNgTablePage } from './demo-ng-table.po';
2 |
3 | describe('async/await', () => {
4 |
5 | it('should be supported in tests', async () => {
6 | const demoPage = new DemoNgTablePage('es5/index.html');
7 | demoPage.open();
8 |
9 | if (await demoPage.dataRows.count() === 0){
10 | expect(true).toBe(false);
11 | }
12 | });
13 | });
--------------------------------------------------------------------------------
/e2e/builds.spec.ts:
--------------------------------------------------------------------------------
1 | import { DemoNgTablePage } from './demo-ng-table.po';
2 |
3 | describe('ng-table builds', () => {
4 |
5 | describe('es5', () => {
6 | const demoPageUrl = 'es5/index.html';
7 | it('should render ng-table', () => {
8 | renderTableSpec(demoPageUrl);
9 | });
10 | });
11 |
12 | describe('es6-systemjs', () => {
13 | // demo-app/es6-systemjs is failing in IE less than vs 11
14 | // this seems to be something to do with SystemJS rather than ng-table per sa;
15 | // I given up trying to investigate for lack of time. Degugging the error
16 | // on SauceLabs shows the following error logged to the browser console:
17 | // "Unable to get property 'pos' of undefined or null reference"
18 | if (capabilities.browserName === "internet explorer" && capabilities.version < 11) {
19 | return
20 | }
21 |
22 | const demoPageUrl = 'es6-systemjs/index.html';
23 | it('should render ng-table', () => {
24 | renderTableSpec(demoPageUrl);
25 | });
26 | });
27 |
28 | describe('es6-webpack', () => {
29 | const demoPageUrl = 'es6-webpack/build/index.html';
30 | it('should render ng-table', () => {
31 | renderTableSpec(demoPageUrl);
32 | });
33 | });
34 |
35 | describe('ts-webpack', () => {
36 | const demoPageUrl = 'ts-webpack/build/index.html';
37 | it('should render ng-table', () => {
38 | renderTableSpec(demoPageUrl);
39 | });
40 | });
41 |
42 |
43 | function renderTableSpec(url: string) {
44 | const demoPage = new DemoNgTablePage(url);
45 | demoPage.open();
46 | expect(demoPage.table.isPresent()).toBe(true);
47 | expect(demoPage.dataRows.count()).toBeGreaterThan(0);
48 | }
49 | });
--------------------------------------------------------------------------------
/e2e/demo-ng-table.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element, ElementArrayFinder, ElementFinder } from 'protractor';
2 |
3 | export class DemoNgTablePage {
4 | dataRows: ElementArrayFinder;
5 | table: ElementFinder;
6 | constructor(private url: string) {
7 | this.table = element(by.css('table[ng-table]'));
8 | this.dataRows = element.all(by.repeater('user in $data'));
9 | }
10 | open() {
11 | browser.get(this.url);
12 | }
13 | }
--------------------------------------------------------------------------------
/e2e/global.d.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | declare var capabilities: {
4 | browserName?: "chrome" | "firefox" | "internet explorer" | "safari";
5 | /**
6 | * Name of the capability
7 | */
8 | name?: string;
9 | /**
10 | * Name of the operating system running the process
11 | */
12 | platform?: string;
13 | /**
14 | * Browser version
15 | */
16 | version?: number;
17 | };
--------------------------------------------------------------------------------
/e2e/protractor-travis.config.js:
--------------------------------------------------------------------------------
1 | var SpecReporter = require('jasmine-spec-reporter');
2 |
3 | exports.config = {
4 |
5 | allScriptsTimeout: 30000,
6 | getPageTimeout: 30000,
7 |
8 | specs: [
9 | '*.spec.ts'
10 | ],
11 |
12 | multiCapabilities: [
13 | capabilitiesForSauceLabs({
14 | 'name': 'Linux/Chrome',
15 | 'browserName': 'chrome'
16 | }),
17 | capabilitiesForSauceLabs({
18 | 'name': 'Linux/Firefox',
19 | 'browserName': 'firefox'
20 | }),
21 | capabilitiesForSauceLabs({
22 | 'name': 'Win7/Firefox',
23 | 'browserName': 'firefox',
24 | 'platform': 'Windows 7'
25 | }),
26 | capabilitiesForSauceLabs({
27 | 'name': 'Win7/Chrome',
28 | 'browserName': 'chrome',
29 | 'platform': 'Windows 7'
30 | })
31 | ,
32 | capabilitiesForSauceLabs({
33 | 'name': 'Win7/IE9',
34 | 'browserName': 'internet explorer',
35 | 'platform': 'Windows 7',
36 | 'version': 9
37 | }),
38 | capabilitiesForSauceLabs({
39 | 'name': 'Win8/IE10',
40 | 'browserName': 'internet explorer',
41 | 'platform': 'Windows 8',
42 | 'version': 10
43 | }),
44 | capabilitiesForSauceLabs({
45 | 'name': 'Win8.1/IE11',
46 | 'browserName': 'internet explorer',
47 | 'platform': 'Windows 8.1',
48 | 'version': 11
49 | }),
50 | // capabilitiesForSauceLabs({
51 | // 'name': 'Win10/Edge',
52 | // 'browserName': 'edge',
53 | // 'platform': 'Windows 10',
54 | // 'version': '13.10586'
55 | // }),
56 | capabilitiesForSauceLabs({
57 | 'name': 'Mac/Safari 8',
58 | 'browserName': 'safari',
59 | 'platform': 'OS X 10.10',
60 | 'version': 8
61 | }),
62 | capabilitiesForSauceLabs({
63 | 'name': 'Mac/Safari 9',
64 | 'browserName': 'safari',
65 | 'platform': 'OS X 10.11',
66 | 'version': 9
67 | })
68 | ],
69 |
70 | baseUrl: 'http://localhost:8080/',
71 |
72 | framework: 'jasmine',
73 |
74 | jasmineNodeOpts: {
75 | defaultTimeoutInterval: 30000,
76 | showColors: true,
77 | includeStackTrace: true
78 | },
79 |
80 | onPrepare: function () {
81 | jasmine.getEnv().addReporter(new SpecReporter());
82 | require('ts-node').register({
83 | project: 'e2e'
84 | });
85 | return browser.getProcessedConfig().then(function (config) {
86 | global.capabilities = config.capabilities;
87 | });
88 | },
89 |
90 | sauceUser: process.env.SAUCE_USERNAME,
91 | sauceKey: process.env.SAUCE_ACCESS_KEY
92 | };
93 |
94 | function capabilitiesForSauceLabs(capabilities) {
95 | return {
96 | 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
97 |
98 | 'name': capabilities.name,
99 | 'build': process.env.TRAVIS_BUILD_NUMBER,
100 |
101 | 'browserName': capabilities.browserName,
102 | 'platform': capabilities.platform,
103 | 'version': capabilities.version
104 | };
105 | }
--------------------------------------------------------------------------------
/e2e/protractor.config.js:
--------------------------------------------------------------------------------
1 | var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
2 |
3 | var reporter = new HtmlScreenshotReporter({
4 | cleanDestination: true,
5 | dest: './out/test/end2end/reports',
6 | filename: 'e2e.html',
7 | ignoreSkippedSpecs: true,
8 | showSummary: true,
9 |
10 | // reportOnlyFailedSpecs: true,
11 | // captureOnlyFailedSpecs: true
12 | });
13 |
14 | exports.config = {
15 |
16 | allScriptsTimeout: 11000,
17 |
18 | specs: [
19 | '*.spec.ts'
20 | ],
21 |
22 | capabilities: {
23 | 'browserName': 'chrome'
24 | },
25 |
26 | baseUrl: 'http://localhost:8080/',
27 |
28 | framework: 'jasmine',
29 |
30 | jasmineNodeOpts: {
31 | defaultTimeoutInterval: 30000,
32 | showColors: true,
33 | includeStackTrace: true
34 | },
35 |
36 | beforeLaunch: function () {
37 | require('ts-node').register({
38 | project: 'e2e'
39 | });
40 | // Setup the report before any tests start
41 | return new Promise(function (resolve) {
42 | reporter.beforeLaunch(resolve);
43 | });
44 | },
45 |
46 | onPrepare: function () {
47 | jasmine.getEnv().addReporter(reporter);
48 |
49 | return browser.getProcessedConfig().then(function (config) {
50 | global.capabilities = config.capabilities;
51 | });
52 | },
53 |
54 | afterLaunch: function (exitCode) {
55 | // Close the report after all tests finish
56 | return new Promise(function (resolve) {
57 | reporter.afterLaunch(resolve.bind(this, exitCode));
58 | });
59 | }
60 | };
--------------------------------------------------------------------------------
/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2015",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": false,
7 | "declaration": false,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "noImplicitAny": true,
11 | "noImplicitReturns": true,
12 | "suppressImplicitAnyIndexErrors": true,
13 | "typeRoots": [
14 | "../node_modules/@types"
15 | ]
16 | },
17 | "include": [
18 | "./**/*"
19 | ],
20 | "exclude": [
21 | "node_modules"
22 | ]
23 | }
--------------------------------------------------------------------------------
/examples-old/app/app.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'angular',
3 | 'ngTable'
4 | ], function (angular) {
5 | 'use strict';
6 |
7 | var app = angular.module('main', ['ngTable']).
8 | controller('DemoCtrl', function($scope, $filter, $q, NgTableParams) {
9 | var data = [{name: "Moroni", age: 50, money: -10},
10 | {name: "Tiancum", age: 43,money: 120},
11 | {name: "Jacob", age: 27, money: 5.5},
12 | {name: "Nephi", age: 29,money: -54},
13 | {name: "Enos", age: 34,money: 110},
14 | {name: "Tiancum", age: 43, money: 1000},
15 | {name: "Jacob", age: 27,money: -201},
16 | {name: "Nephi", age: 29, money: 100},
17 | {name: "Enos", age: 34, money: -52.5},
18 | {name: "Tiancum", age: 43, money: 52.1},
19 | {name: "Jacob", age: 27, money: 110},
20 | {name: "Nephi", age: 29, money: -55},
21 | {name: "Enos", age: 34, money: 551},
22 | {name: "Tiancum", age: 43, money: -1410},
23 | {name: "Jacob", age: 27, money: 410},
24 | {name: "Nephi", age: 29, money: 100},
25 | {name: "Enos", age: 34, money: -100}];
26 |
27 | $scope.tableParams = new NgTableParams({
28 | $liveFiltering: true,
29 | page: 1, // show first page
30 | total: data.length, // length of data
31 | count: 10 // count per page
32 | });
33 |
34 | $scope.names = function(column) {
35 | var def = $q.defer(),
36 | arr = [],
37 | names = [];
38 | angular.forEach(data, function(item){
39 | if ($.inArray(item.name, arr) === -1) {
40 | arr.push(item.name);
41 | names.push({
42 | 'id': item.name,
43 | 'title': item.name
44 | });
45 | }
46 | });
47 | def.resolve(names);
48 | return def.promise;
49 | };
50 |
51 | $scope.$watch('tableParams', function(params) {
52 | // use built-in angular filter
53 | var orderedData = params.sorting ?
54 | $filter('orderBy')(data, params.orderBy()) :
55 | data;
56 | orderedData = params.filter ?
57 | $filter('filter')(orderedData, params.filter) :
58 | orderedData;
59 |
60 | params.total = orderedData.length; // set total for recalc pagination
61 | $scope.users = orderedData.slice((params.page - 1) * params.count, params.page * params.count);
62 | }, true);
63 | });
64 | return app;
65 | });
66 |
--------------------------------------------------------------------------------
/examples-old/app/main.js:
--------------------------------------------------------------------------------
1 | require.config({
2 | paths: {
3 | jquery: '../js/jquery-1.9.1.min',
4 | angular: '../js/angular.min',
5 | ngTable: '../../dist'
6 | },
7 | shim: {
8 | 'angular': {'exports': 'angular'}
9 | }
10 | });
11 |
12 | require([
13 | 'jquery',
14 | 'angular',
15 | 'app'
16 | ], function ($, angular, app) {
17 | 'use strict';
18 |
19 | angular.bootstrap(document, ['main']);
20 | });
21 |
--------------------------------------------------------------------------------
/examples-old/demo15.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Export to CSV
23 |
24 |
25 |
26 |
Export to CSV
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 | {{user.name}}
38 | |
39 |
40 | {{user.age}}
41 | |
42 |
43 |
44 |
45 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/examples-old/demo26.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Table with Resizable Columns
26 |
27 |
28 |
29 |
30 |
31 |
32 | {{user.name}}
33 | |
34 |
35 | {{user.age}}
36 | |
37 |
38 |
39 |
40 |
84 |
85 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/examples-old/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/examples-old/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/examples-old/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/examples-old/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/examples-old/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esvit/ng-table/b6d5d0bfeef923c617081ffe80a0266d7fb4aa33/examples-old/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/examples-old/js/angular-resource.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | AngularJS v1.2.0-rc.2
3 | (c) 2010-2012 Google, Inc. http://angularjs.org
4 | License: MIT
5 | */
6 | (function(H,g,C){'use strict';var A=g.$$minErr("$resource");g.module("ngResource",["ng"]).factory("$resource",["$http","$parse","$q",function(D,y,E){function n(g,h){this.template=g;this.defaults=h||{};this.urlParams={}}function u(l,h,d){function p(c,b){var e={};b=v({},h,b);q(b,function(a,b){t(a)&&(a=a());var m;a&&a.charAt&&"@"==a.charAt(0)?(m=a.substr(1),m=y(m)(c)):m=a;e[b]=m});return e}function b(c){return c.resource}function e(c){z(c||{},this)}var F=new n(l);d=v({},G,d);q(d,function(c,f){var h=
7 | /^(POST|PUT|PATCH)$/i.test(c.method);e[f]=function(a,f,m,l){var d={},r,s,w;switch(arguments.length){case 4:w=l,s=m;case 3:case 2:if(t(f)){if(t(a)){s=a;w=f;break}s=f;w=m}else{d=a;r=f;s=m;break}case 1:t(a)?s=a:h?r=a:d=a;break;case 0:break;default:throw A("badargs",arguments.length);}var n=r instanceof e,k=n?r:c.isArray?[]:new e(r),x={},u=c.interceptor&&c.interceptor.response||b,y=c.interceptor&&c.interceptor.responseError||C;q(c,function(a,c){"params"!=c&&("isArray"!=c&&"interceptor"!=c)&&(x[c]=z(a))});
8 | x.data=r;F.setUrlParams(x,v({},p(r,c.params||{}),d),c.url);d=D(x).then(function(a){var b=a.data,f=k.$promise;if(b){if(g.isArray(b)!=!!c.isArray)throw A("badcfg",c.isArray?"array":"object",g.isArray(b)?"array":"object");c.isArray?(k.length=0,q(b,function(a){k.push(new e(a))})):(z(b,k),k.$promise=f)}k.$resolved=!0;(s||B)(k,a.headers);a.resource=k;return a},function(a){k.$resolved=!0;(w||B)(a);return E.reject(a)}).then(u,y);return n?d:(k.$promise=d,k.$resolved=!1,k)};e.prototype["$"+f]=function(a,c,
9 | b){t(a)&&(b=c,c=a,a={});a=e[f](a,this,c,b);return a.$promise||a}});e.bind=function(c){return u(l,v({},h,c),d)};return e}var G={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},B=g.noop,q=g.forEach,v=g.extend,z=g.copy,t=g.isFunction;n.prototype={setUrlParams:function(l,h,d){var p=this,b=d||p.template,e,n,c=p.urlParams={};q(b.split(/\W/),function(f){!/^\d+$/.test(f)&&(f&&RegExp("(^|[^\\\\]):"+f+"(\\W|$)").test(b))&&(c[f]=!0)});
10 | b=b.replace(/\\:/g,":");h=h||{};q(p.urlParams,function(c,d){e=h.hasOwnProperty(d)?h[d]:p.defaults[d];g.isDefined(e)&&null!==e?(n=encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),b=b.replace(RegExp(":"+d+"(\\W|$)","g"),n+"$1")):b=b.replace(RegExp("(/?):"+d+"(\\W|$)","g"),function(a,c,b){return"/"==b.charAt(0)?b:c+b})});b=b.replace(/\/+$/,"");b=b.replace(/\/\.(?=\w+($|\?))/,
11 | ".");l.url=b.replace(/\/\\\./,"/.");q(h,function(c,b){p.urlParams[b]||(l.params=l.params||{},l.params[b]=c)})}};return u}])})(window,window.angular);
12 | /*
13 | //@ sourceMappingURL=angular-resource.min.js.map
14 | */
--------------------------------------------------------------------------------
/examples-old/js/ng-table-export.src.js:
--------------------------------------------------------------------------------
1 | angular.module('ngTableExport', [])
2 | .config(['$compileProvider', function($compileProvider) {
3 | // allow data links
4 | $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|data):/);
5 | }])
6 | .directive('exportCsv', ['$parse', function ($parse) {
7 | return {
8 | restrict: 'A',
9 | scope: false,
10 | link: function(scope, element, attrs) {
11 | var data = '';
12 | var csv = {
13 | stringify: function(str) {
14 | return '"' +
15 | str.replace(/^\s\s*/, '').replace(/\s*\s$/, '') // trim spaces
16 | .replace(/"/g,'""') + // replace quotes with double quotes
17 | '"';
18 | },
19 | generate: function() {
20 | data = '';
21 | var rows = element.find('tr');
22 | angular.forEach(rows, function(row, i) {
23 | var tr = angular.element(row),
24 | tds = tr.find('th'),
25 | rowData = '';
26 | if (tr.hasClass('ng-table-filters')) {
27 | return;
28 | }
29 | if (tds.length == 0) {
30 | tds = tr.find('td');
31 | }
32 | if (i != 1) {
33 | angular.forEach(tds, function(td, i) {
34 | rowData += csv.stringify(angular.element(td).text()) + ';';
35 | });
36 | rowData = rowData.slice(0, rowData.length - 1); //remove last semicolon
37 | }
38 | data += rowData + "\n";
39 | });
40 | },
41 | link: function() {
42 | return 'data:text/csv;charset=UTF-8,' + encodeURIComponent(data);
43 | }
44 | };
45 | $parse(attrs.exportCsv).assign(scope.$parent, csv);
46 | }
47 | };
48 | }]);
--------------------------------------------------------------------------------
/examples-old/js/ng-table-resizable-columns.js:
--------------------------------------------------------------------------------
1 | /*! ngTableColumnResizable v0.1.0 by Vitalii Savchuk(esvit666@gmail.com) - https://github.com/esvit/ng-table-resizable-columns - New BSD License */
2 |
3 | angular.module("ngTableResizableColumns",[]).directive("ngTableResizableColumns",function(){function a(a){var b=function(a,b){return function(){return a.apply(b,arguments)}};this.pointerdown=b(this.pointerdown,this);var c=this;this.options={store:window.store,rigidSizing:!1,resizeFromBody:!0},this.$table=a,this.setHeaders(),this.restoreColumnWidths(),this.syncHandleWidths(),$(window).on("resize.rc",function(){return c.syncHandleWidths()})}var b=function(a){return parseFloat(a.style.width.replace("%",""))},c=function(a,b){return a.style.width=""+b.toFixed(2)+"%"},d=function(a){return 0===a.type.indexOf("touch")?(a.originalEvent.touches[0]||a.originalEvent.changedTouches[0]).pageX:a.pageX};return a.prototype.getColumnId=function(a){return this.$table.data("resizable-columns-id")+"-"+a.data("resizable-column-id")},a.prototype.setHeaders=function(){return this.$tableHeaders=this.$table.find("thead tr:first th:visible"),this.assignPercentageWidths(),this.createHandles()},a.prototype.destroy=function(){return this.$handleContainer.remove(),this.$table.removeData("resizableColumns"),$(window).off(".rc")},a.prototype.assignPercentageWidths=function(){var a=this;return this.$tableHeaders.each(function(b,d){var e;return e=$(d),c(e[0],e.outerWidth()/a.$table.width()*100)})},a.prototype.createHandles=function(){var a,b=this;return null!=(a=this.$handleContainer)&&a.remove(),this.$table.before(this.$handleContainer=$("")),this.$tableHeaders.each(function(a,c){var d;if(0!==b.$tableHeaders.eq(a+1).length&&null==b.$tableHeaders.eq(a).attr("data-noresize")&&null==b.$tableHeaders.eq(a+1).attr("data-noresize"))return d=$(""),d.data("th",$(c)),d.appendTo(b.$handleContainer)}),this.$handleContainer.on("mousedown touchstart",".rc-handle",this.pointerdown)},a.prototype.syncHandleWidths=function(){var a=this;return this.setHeaders(),this.$handleContainer.width(this.$table.width()).find(".rc-handle").each(function(b,c){var d;return d=$(c),d.css({left:d.data("th").outerWidth()+(d.data("th").offset().left-a.$handleContainer.offset().left),height:a.options.resizeFromBody?a.$table.height():a.$table.find("thead").height()})})},a.prototype.saveColumnWidths=function(){var a=this;return this.$tableHeaders.each(function(c,d){var e;return e=$(d),null==e.attr("data-noresize")&&null!=a.options.store?a.options.store.set(a.getColumnId(e),b(e[0])):void 0})},a.prototype.restoreColumnWidths=function(){var a=this;return this.$tableHeaders.each(function(b,d){var e,f;return e=$(d),null!=a.options.store&&(f=a.options.store.get(a.getColumnId(e)))?c(e[0],f):void 0})},a.prototype.totalColumnWidths=function(){var a;return a=0,this.$tableHeaders.each(function(b,c){return a+=parseFloat($(c)[0].style.width.replace("%",""))}),a},a.prototype.pointerdown=function(a){var e,f,g,h,i,j=this;return a.preventDefault(),h=d(a),e=$(a.currentTarget),f=e.data("th"),g=this.$tableHeaders.eq(this.$tableHeaders.index(f)+1),i={left:b(f[0]),right:b(g[0])},this.$table.addClass("rc-table-resizing"),$(document).on("mousemove.rc touchmove.rc",function(a){var b;return b=(d(a)-h)/j.$table.width()*100,c(g[0],i.right-b),c(f[0],i.left+b)}),$(document).one("mouseup touchend",function(){return $(document).off("mousemove.rc touchmove.rc"),j.$table.removeClass("rc-table-resizing"),j.syncHandleWidths(),j.saveColumnWidths()})},{restrict:"C",priority:999,require:"ngTable",link:function(b,c){var d;b.$watch("$data",function(){d.destroy(),d=new a(c)}),d=new a(c)}}});
4 | //# sourceMappingURL=ng-table-resizable-columns.map
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import * as ng1 from 'angular';
2 | import { ngTableCoreModule } from './src/core';
3 | import { ngTableBrowserModule } from './src/browser';
4 |
5 | const ngTableModule = ng1.module('ngTable', [ngTableCoreModule.name, ngTableBrowserModule.name]);
6 |
7 | export { ngTableModule };
8 | export * from './src/core';
9 | export * from './src/browser';
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=759670
3 | // for the documentation about the jsconfig.json format
4 | "compilerOptions": {
5 | "target": "es5",
6 | "module": "commonjs",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "exclude": [
10 | "node_modules",
11 | "tmp",
12 | "temp"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file
2 | // See http://karma-runner.github.io/0.10/config/configuration-file.html
3 | const testGlob = 'test/index.js';
4 | var debug = process.env.npm_lifecycle_event === 'test:debug'
5 | const webpackConfig = require('./webpack.config')({ test: true, noCoverage: debug });
6 |
7 | module.exports = function (config) {
8 | let reporters = ['jasmine-diff', 'dots', 'spec'];
9 | if (!debug) {
10 | reporters.push('coverage');
11 | }
12 | config.set({
13 | basePath: '',
14 |
15 | frameworks: ['jasmine'],
16 |
17 | // list of files / patterns to load in the browser
18 | files: [
19 | // libraries
20 | 'node_modules/lodash/lodash.js',
21 | 'node_modules/angular/angular.js',
22 | 'node_modules/angular-mocks/angular-mocks.js',
23 | testGlob
24 | ],
25 |
26 | // generate js files from html templates
27 | preprocessors: {
28 | [testGlob]: ['webpack']
29 | },
30 | webpack: webpackConfig,
31 | webpackMiddleware: {
32 | stats: {
33 | chunks: false,
34 | chunkModules: false,
35 | colors: true,
36 | hash: false
37 | }
38 | },
39 | reporters: reporters,
40 | colors: true,
41 | logLevel: config.LOG_INFO,
42 | autoWatch: false,
43 | singleRun: true,
44 | browsers: [debug ? 'Chrome' : 'PhantomJS'],
45 | coverageReporter: {
46 | reporters: [
47 | { type: 'lcov', dir: 'out/coverage' },
48 | { type: 'cobertura', dir: 'out/coverage' },
49 | { type: 'json', dir: 'out/coverage' },
50 | { type: 'text-summary' }
51 | ]
52 | }
53 | });
54 | };
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-table",
3 | "version": "0.0.0-semantic-release",
4 | "author": "Vitalii Savchuk ",
5 | "license": "BSD",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/esvit/ng-table.git"
9 | },
10 | "main": "bundles/ng-table.js",
11 | "module": "index.js",
12 | "typings": "index.d.ts",
13 | "release": {
14 | "branch": "master",
15 | "fallbackTags": {
16 | "next": "latest"
17 | }
18 | },
19 | "publishConfig": {
20 | "tag": "next"
21 | },
22 | "devDependencies": {
23 | "@types/angular-mocks": "^1.5.4",
24 | "@types/angular-route": "^1.3.2",
25 | "@types/jasmine": "^2.2.33",
26 | "@types/karma-jasmine": "0.0.28",
27 | "@types/lodash": "^4.14.43",
28 | "angular": "^1.5.8",
29 | "angular-mocks": "^1.5.8",
30 | "angular-route": "^1.5.8",
31 | "angular1-template-loader": "^0.1.0",
32 | "awesome-typescript-loader": "^3.0.0-beta.9",
33 | "babel-core": "^6.14.0",
34 | "babel-loader": "^6.2.10",
35 | "babel-preset-es2015": "^6.13.2",
36 | "babel-preset-es2016": "^6.11.3",
37 | "babel-preset-stage-2": "^6.13.0",
38 | "bootstrap-css-only": "^3.3.6",
39 | "bulk": "git+https://github.com/kumarharsh/bulk.git#68ac8daa57191f7ea79279b22b0876cf4ab19575",
40 | "commitizen": "^2.8.6",
41 | "core-js": "^2.4.1",
42 | "coveralls": "~2.11.0",
43 | "css-loader": "^0.23.1",
44 | "cz-conventional-changelog": "^1.2.0",
45 | "extract-text-webpack-plugin": "^2.0.0-beta.3",
46 | "file-loader": "^0.9.0",
47 | "gh-pages": "^0.11.0",
48 | "html-loader": "^0.4.3",
49 | "html-webpack-plugin": "^2.22.0",
50 | "http-server": "^0.9.0",
51 | "husky": "^0.11.9",
52 | "istanbul": "^0.4.4",
53 | "istanbul-instrumenter-loader": "^1.1.0",
54 | "jasmine-core": "git+https://github.com/jasmine/jasmine.git#be6ff8b24cba355246df93d00d74a64de9e580ad",
55 | "jasmine-spec-reporter": "^2.7.0",
56 | "karma": "1.1.2",
57 | "karma-chrome-launcher": "1.0.1",
58 | "karma-coverage": "1.1.1",
59 | "karma-firefox-launcher": "1.0.0",
60 | "karma-jasmine": "^1.1.0",
61 | "karma-jasmine-diff-reporter": "^0.6.3",
62 | "karma-phantomjs-launcher": "1.0.1",
63 | "karma-spec-reporter": "0.0.26",
64 | "karma-webpack": "^1.8.0",
65 | "linklocal": "git+https://github.com/theoy/linklocal.git#3f939171c3c925f2af831d78a3f2fbf9caa3002e",
66 | "lodash": "^4.17.2",
67 | "ngtemplate-loader": "git+https://github.com/wearymonkey/ngtemplate-loader.git#63e3461d8b1298de913e3528766068260915ae1f",
68 | "node-sass": "^3.8.0",
69 | "npm-run-all": "^2.3.0",
70 | "open": "0.0.5",
71 | "phantomjs-prebuilt": "2.1.10",
72 | "protractor": "^4.0.9",
73 | "protractor-jasmine2-screenshot-reporter": "^0.3.2",
74 | "resolve-url-loader": "^1.6.0",
75 | "sass-loader": "^4.1.0",
76 | "semantic-release": "^4.3.5",
77 | "shx": "^0.1.4",
78 | "style-loader": "^0.13.1",
79 | "systemjs": "^0.19.36",
80 | "systemjs-plugin-babel": "0.0.15",
81 | "ts-node": "^1.3.0",
82 | "typedoc": "^0.5.0",
83 | "typescript": "^2.1.4",
84 | "url-loader": "^0.5.7",
85 | "validate-commit-msg": "^2.8.2",
86 | "webpack": "^2.1.0-beta.28",
87 | "webpack-dev-server": "^2.2.0-rc.0",
88 | "webpack-merge": "^1.1.1",
89 | "webpack-validator": "^2.3.0"
90 | },
91 | "scripts": {
92 | "build:all": "run-s build:full build:demo-apps",
93 | "build:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm run build\"",
94 | "prebuild": "npm run clean",
95 | "build": "run-p tsc \"webpack -- --progress --profile --env.debug\"",
96 | "prebuild:prod": "npm run clean",
97 | "build:prod": "run-p tsc \"webpack -- --progress --profile --env.prod\"",
98 | "prebuild:full": "npm run clean",
99 | "build:full": "run-p tsc \"webpack -- --progress --profile --env.prod --env.debug\"",
100 | "clean:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm run clean\"",
101 | "clean:all": "run-p clean clean:demo-apps",
102 | "clean": "shx rm -rf bundles out demo-site/api-docs index.{js,js.map,d.ts} src/**/*.{js,js.map,d.ts} test/specs/**/*.{js,js.map,d.ts} test/util/**/*.{js,js.map,d.ts}",
103 | "cm": "git add -A && git-cz",
104 | "commitmsg": "validate-commit-msg",
105 | "doc-deploy": "gh-pages -d demo-site",
106 | "predoc": "shx rm -rf demo-site/api-docs",
107 | "doc": "typedoc --options typedoc.json index.ts",
108 | "e2e-server": "http-server demo-apps -c-1",
109 | "e2e-server:ci": "http-server demo-apps -s -c-1 &",
110 | "e2e": "npm run build:all && npm run e2e-only",
111 | "e2e:ci": "protractor e2e/protractor-travis.config",
112 | "e2e-only": "protractor e2e/protractor.config.js",
113 | "poste2e-only": "node ./scripts/open-e2e-report",
114 | "install:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm install\"",
115 | "link:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm run linklocal\"",
116 | "precommit": "npm run tsc",
117 | "semantic-release": "semantic-release pre && npm publish && semantic-release post",
118 | "serve:demo": "cd demo-apps/es5 && npm start",
119 | "serve:docs-site": "http-server demo-site -o -c-1",
120 | "_setup:common": "run-s build:full install:demo-apps link:demo-apps",
121 | "setup:ci": "npm run _setup:common",
122 | "setup": "run-p _setup:common update-webdriver",
123 | "test": "karma start",
124 | "test:w": "karma start --no-single-run --auto-watch",
125 | "test:debug": "karma start --no-single-run",
126 | "tsc": "tsc",
127 | "unlink:demo-apps": "shx ls -d demo-apps/*/ | bulk -c \"npm run unlinklocal\"",
128 | "update-webdriver": "webdriver-manager update",
129 | "validate-webpack": "webpack-validator webpack.config.js --env.dev --env.test --env.prod",
130 | "webpack": "webpack"
131 | },
132 | "dependencies": {
133 | "@types/angular": "^1.5.13"
134 | },
135 | "peerDependencies": {
136 | "angular": "^1.2"
137 | },
138 | "config": {
139 | "commitizen": {
140 | "path": "./node_modules/cz-conventional-changelog"
141 | },
142 | "validate-commit-msg": {
143 | "types": "conventional-commit-types",
144 | "helpMessage": "To help create valid commit messages consider using `npm run cm` instead of `git commit`"
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/scripts/open-e2e-report.js:
--------------------------------------------------------------------------------
1 | var open = require("open");
2 | open("./out/test/end2end/reports/e2e.html");
--------------------------------------------------------------------------------
/scripts/webpack/libParts.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const ExtractTextPlugin = require("extract-text-webpack-plugin");
4 | const merge = require('webpack-merge');
5 | const webpack = require('webpack');
6 |
7 | module.exports = createLibraryParts;
8 |
9 | function createLibraryParts(rootDir, env = {}) {
10 | const commonParts = require('./parts')(rootDir, env);
11 | const pkg = require(path.join(rootDir, 'package'));
12 | const libraryName = pkg.name;
13 |
14 | return Object.assign({}, commonParts, {
15 | asUmdLibrary,
16 | banner,
17 | extractSass,
18 | excludeAngular,
19 | inlineHtmlTemplates
20 | });
21 |
22 | /////
23 |
24 |
25 | function asUmdLibrary() {
26 | const filename = env.prod ? `[name].min.js` : `[name].js`;
27 | return {
28 | entry: {
29 | [libraryName]: path.join(rootDir, 'index.ts')
30 | },
31 | // tells webpack not to include in bundle require'd node specific objects (eg path)
32 | target: 'node',
33 | output: {
34 | path: path.join(rootDir, 'bundles'),
35 | filename: filename,
36 | library: libraryName,
37 | libraryTarget: 'umd',
38 | umdNamedDefine: false
39 | }
40 | };
41 | }
42 |
43 | function banner() {
44 | // warning: this conflicts with ExtractTextPlugin used to extract styles into seperate bundle
45 | const text = `/*! ngTable v${pkg.version} by Vitalii Savchuk(esvit666@gmail.com) - ` +
46 | 'https://github.com/esvit/ng-table - New BSD License */\n';
47 | return {
48 | plugins: [
49 | new webpack.BannerPlugin({ banner: text, entryOnly: true })
50 | ]
51 | };
52 | }
53 |
54 | function excludeAngular() {
55 | return {
56 | externals: {
57 | angular: 'angular'
58 | }
59 | }
60 | }
61 |
62 | /**
63 | * Extracts styles into a seperate bundle
64 | */
65 | function extractSass(files) {
66 |
67 | // note: The way we're setting up webpack here seems a bit of a hack:
68 | //
69 | // Although the setup creates two bundles seperating the js and css as desired,
70 | // it's also producing an extra styles.js file which we're throwing away/ignoring.
71 | // The alternative, more supported way of things, is to leave the css inline
72 | // within js and let the styles plugin add the css at runtime to the html page.
73 | // At the moment keeping with the extracted css as:
74 | // 1. more familar to angular 1 developers (?)
75 | // 2. maintains backwards compatibility with the existing apps that expects
76 | // the css to be delivered to the browser as a seperate file
77 |
78 | const filename = env.prod ? `${libraryName}.min.css` : `${libraryName}.css`;
79 | const extractor = new ExtractTextPlugin(filename);
80 | let loader;
81 | if (env.debug || env.prod) {
82 | loader = 'css-loader?sourceMap!sass-loader?sourceMap';
83 | } else {
84 | loader = 'css-loader!sass-loader';
85 | }
86 | return {
87 | entry: {
88 | styles: files
89 | },
90 | module: {
91 | rules: [
92 | {
93 | test: /\.scss$/,
94 | loader: extractor.extract(loader),
95 | include: files
96 | }
97 | ]
98 | },
99 | plugins: [
100 | extractor
101 | ]
102 | };
103 | }
104 |
105 | function inlineHtmlTemplates() {
106 | return {
107 | module: {
108 | rules: [
109 | {
110 | test: /\.html$/,
111 | loaders: ['ngtemplate-loader?requireAngular&relativeTo=/src/browser/&prefix=ng-table/', 'html-loader']
112 | }
113 | ]
114 | }
115 | };
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/scripts/webpack/multiConfig.js:
--------------------------------------------------------------------------------
1 | module.exports = function (partsFactory) {
2 | return function multiconfig(sourceDir, env, configFactory) {
3 | let configs = [];
4 | if (env.prod) {
5 | let prodEnv = Object.assign({}, env, { debug: false });
6 | configs.push(configFactory(prodEnv, partsFactory(sourceDir, prodEnv)));
7 | }
8 | if (env.debug) {
9 | let debugEnv = Object.assign({}, env, { prod: false });
10 | configs.push(configFactory(debugEnv, partsFactory(sourceDir, debugEnv)));
11 | }
12 | if (!env.debug && !env.prod) {
13 | configs.push(configFactory(env, partsFactory(sourceDir, env)));
14 | }
15 | return configs;
16 | }
17 | };
18 |
19 |
--------------------------------------------------------------------------------
/scripts/webpack/parts.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge');
2 | const webpack = require('webpack');
3 | const path = require('path');
4 |
5 | module.exports = createParts;
6 |
7 | function createParts(rootDir, env) {
8 |
9 | return {
10 | es6,
11 | forEnvironment,
12 | prodOptimize,
13 | testCoverage,
14 | typescript
15 | };
16 |
17 | ////////
18 |
19 | function es6() {
20 | return {
21 | module: {
22 | rules: [
23 | { test: /\.js$/, loaders: ['babel-loader?cacheDirectory'], exclude: /node_modules/ }
24 | ]
25 | }
26 | }
27 | }
28 |
29 | function prodOptimize() {
30 | return {
31 | plugins: [
32 | new webpack.LoaderOptionsPlugin({
33 | minimize: true,
34 | debug: false,
35 | quiet: true,
36 | }),
37 | new webpack.DefinePlugin({
38 | 'process.env': {
39 | NODE_ENV: '"production"',
40 | },
41 | }),
42 | new webpack.optimize.UglifyJsPlugin({
43 | compress: {
44 | screw_ie8: true, // eslint-disable-line
45 | warnings: false,
46 | },
47 | comments: false,
48 | sourceMap: true
49 | })
50 | ]
51 | };
52 | }
53 |
54 | function forEnvironment() {
55 | if (env.prod) {
56 | return merge(
57 | {
58 | devtool: 'source-map',
59 | bail: true
60 | },
61 | prodOptimize()
62 | );
63 | } else if (env.debug) {
64 | return {
65 | output: {
66 | pathinfo: true
67 | },
68 | // note: wanted to use eval-source-map to increase build times, but chrome would not stop on breakpoint
69 | // therefore instead using source-map
70 | devtool: 'source-map',
71 | performance: {
72 | hints: false
73 | }
74 | };
75 | } else if (env.test) {
76 | return {
77 | devtool: 'inline-source-map'
78 | };
79 | } else {
80 | return {
81 | devtool: 'eval'
82 | };
83 | }
84 | }
85 |
86 | function testCoverage() {
87 | return {
88 | module: {
89 | rules: [
90 | {
91 | enforce: 'post',
92 | test: /\.ts$/,
93 | exclude: [
94 | /\.spec\.ts$/,
95 | /node_modules/
96 | ],
97 | loader: 'istanbul-instrumenter-loader',
98 | query: {
99 | esModules: true
100 | }
101 | }
102 | ]
103 | }
104 | };
105 | }
106 |
107 | function typescript(tsconfig = 'tsconfig.json') {
108 | const tsconfigPath = path.resolve(rootDir, tsconfig)
109 | return {
110 | // Currently we need to add '.ts' to the resolve.extensions array.
111 | resolve: {
112 | extensions: ['.ts', '.tsx', '.js', '.jsx']
113 | },
114 | module: {
115 | rules: [
116 | {
117 | test: /\.ts$/,
118 | exclude: /node_modules/,
119 | loaders: [`awesome-typescript-loader?tsconfig=${tsconfigPath}`, 'angular1-template-loader']
120 | }
121 | ]
122 | }
123 | };
124 | }
125 | }
--------------------------------------------------------------------------------
/src/browser/filterRow.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 | |
8 |
9 |
--------------------------------------------------------------------------------
/src/browser/filters/number.html:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/browser/filters/select-multiple.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/browser/filters/select.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/browser/filters/text.html:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/browser/groupRow.html:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/src/browser/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/browser/index.ts:
--------------------------------------------------------------------------------
1 | import * as angular from 'angular';
2 | import { ngTable } from './ngTable.directive';
3 | import { NgTableColumn } from './ngTableColumn';
4 | import { ngTableColumnsBinding } from './ngTableColumnsBinding.directive';
5 | import { NgTableController } from './ngTableController';
6 | import { ngTableDynamic } from './ngTableDynamic.directive';
7 | import { NgTableFilterConfigProvider, NgTableFilterConfig } from './ngTableFilterConfig';
8 | import { ngTableFilterRow } from './ngTableFilterRow.directive';
9 | import { NgTableFilterRowController } from './ngTableFilterRowController';
10 | import { ngTableGroupRow } from './ngTableGroupRow.directive';
11 | import { NgTableGroupRowController } from './ngTableGroupRowController';
12 | import { ngTablePagination } from './ngTablePagination.directive';
13 | import { ngTableSelectFilterDs } from './ngTableSelectFilterDs.directive';
14 | import { ngTableSorterRow } from './ngTableSorterRow.directive';
15 | import { NgTableSorterRowController } from './ngTableSorterRowController';
16 | import './filters/number.html';
17 | import './filters/select.html';
18 | import './filters/select-multiple.html';
19 | import './filters/text.html';
20 | import './pager.html';
21 | import './header.html';
22 |
23 | const ngTableBrowserModule = angular.module('ngTable-browser', [])
24 | .directive('ngTable', ngTable)
25 | .service('ngTableColumn', NgTableColumn)
26 | .directive('ngTableColumnsBinding', ngTableColumnsBinding)
27 | .controller('ngTableController', NgTableController)
28 | .directive('ngTableDynamic', ngTableDynamic)
29 | .provider('ngTableFilterConfig', NgTableFilterConfigProvider)
30 | .directive('ngTableFilterRow', ngTableFilterRow)
31 | .controller('ngTableFilterRowController', NgTableFilterRowController)
32 | .directive('ngTableGroupRow', ngTableGroupRow)
33 | .controller('ngTableGroupRowController', NgTableGroupRowController)
34 | .directive('ngTablePagination', ngTablePagination)
35 | .directive('ngTableSelectFilterDs', ngTableSelectFilterDs)
36 | .directive('ngTableSorterRow', ngTableSorterRow)
37 | .controller('ngTableSorterRowController', NgTableSorterRowController);
38 |
39 | export * from './public-interfaces';
40 | export { NgTableController, ngTableBrowserModule };
41 | export * from './ngTableFilterConfig';
--------------------------------------------------------------------------------
/src/browser/ngTableColumn.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IScope } from 'angular';
10 | import * as ng1 from 'angular';
11 | import { ColumnDef, ColumnDefPartial, DynamicTableColDef } from './public-interfaces';
12 |
13 | /**
14 | * @private
15 | */
16 | function isScopeLike(object: any) {
17 | return object != null && ng1.isFunction(object.$new);
18 | }
19 |
20 | /**
21 | * @private
22 | * Service to construct a $column definition used by {@link ngTable ngTable} directive
23 | */
24 | export class NgTableColumn {
25 | static $inject: string[] = [];
26 |
27 | /**
28 | * Creates a $column for use within a header template
29 | *
30 | * @param column the initial definition for $column to build
31 | * @param defaultScope the $scope to supply to the $column getter methods when not supplied by caller
32 | * @param columns a reference to the $columns array to make available on the context supplied to the
33 | * $column getter methods
34 | */
35 | buildColumn(column: TCol, defaultScope: IScope, columns: ColumnDef[]): ColumnDef {
36 | // note: we're not modifying the original column object. This helps to avoid unintended side affects
37 | const extendedCol = Object.create(column);
38 | const defaults = this.createDefaults();
39 | for (const prop in defaults) {
40 | if (extendedCol[prop] === undefined) {
41 | extendedCol[prop] = defaults[prop];
42 | }
43 | if (!ng1.isFunction(extendedCol[prop])) {
44 | // wrap raw field values with "getter" functions
45 | // - this is to ensure consistency with how ngTable.compile builds columns
46 | // - note that the original column object is being "proxied"; this is important
47 | // as it ensure that any changes to the original object will be returned by the "getter"
48 | const getterSetter = function getterSetter(/*[value] || [$scope, locals]*/) {
49 | if (arguments.length === 1 && !isScopeLike(arguments[0])) {
50 | (getterSetter as any).assign(null, arguments[0]);
51 | } else {
52 | return column[prop];
53 | }
54 | };
55 | (getterSetter as any).assign = function ($scope: IScope, value: any) {
56 | column[prop] = value;
57 | };
58 | extendedCol[prop] = getterSetter;
59 | }
60 | // satisfy the arguments expected by the function returned by parsedAttribute in the ngTable directive
61 | const getterFn = extendedCol[prop];
62 | extendedCol[prop] = function () {
63 | if (arguments.length === 1 && !isScopeLike(arguments[0])) {
64 | getterFn.assign(defaultScope, arguments[0]);
65 | } else {
66 | const scope = arguments[0] || defaultScope;
67 | const context = Object.create(scope);
68 | ng1.extend(context, {
69 | $column: extendedCol,
70 | $columns: columns
71 | });
72 | return getterFn.call(column, context);
73 | }
74 | };
75 | if (getterFn.assign) {
76 | extendedCol[prop].assign = getterFn.assign;
77 | } else {
78 | const wrappedGetterFn = extendedCol[prop];
79 | let localValue: any;
80 | const getterSetter = function getterSetter(/*[value] || [$scope, locals]*/) {
81 | if (arguments.length === 1 && !isScopeLike(arguments[0])) {
82 | (getterSetter as any).assign(null, arguments[0]);
83 | } else {
84 | return localValue != undefined ? localValue : wrappedGetterFn.apply(extendedCol, arguments);
85 | }
86 | };
87 | (getterSetter as any).assign = function ($scope: IScope, value: any) {
88 | localValue = value;
89 | };
90 | extendedCol[prop] = getterSetter;
91 | }
92 | }
93 | return extendedCol as ColumnDef;
94 | }
95 |
96 | private createDefaults() {
97 | return {
98 | 'class': this.createGetterSetter(''),
99 | filter: this.createGetterSetter(false),
100 | groupable: this.createGetterSetter(false),
101 | filterData: ng1.noop,
102 | headerTemplateURL: this.createGetterSetter(false),
103 | headerTitle: this.createGetterSetter(''),
104 | sortable: this.createGetterSetter(false),
105 | show: this.createGetterSetter(true),
106 | title: this.createGetterSetter(''),
107 | titleAlt: this.createGetterSetter('')
108 | };
109 | }
110 |
111 | private createGetterSetter(initialValue: any) {
112 | let value = initialValue;
113 | const getterSetter = function getterSetter(/*[value] || [$scope, locals]*/) {
114 | if (arguments.length === 1 && !isScopeLike(arguments[0])) {
115 | (getterSetter as any).assign(null, arguments[0]);
116 | } else {
117 | return value;
118 | }
119 | };
120 | (getterSetter as any).assign = function ($scope: IScope, newValue: any) {
121 | value = newValue;
122 | };
123 | return getterSetter;
124 | }
125 | }
--------------------------------------------------------------------------------
/src/browser/ngTableColumnsBinding.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IAugmentedJQuery, IAttributes, IDirective, IParseService } from 'angular';
10 | import { TableScope } from './ngTableController';
11 | import { ColumnDef } from './public-interfaces';
12 |
13 | /**
14 | * @private
15 | */
16 | interface InputAttributes extends IAttributes {
17 | ngTableColumnsBinding: string;
18 | }
19 |
20 | ngTableColumnsBinding.$inject = ["$parse"];
21 |
22 | /**
23 | * One-way data binds the $columns array generated by ngTable/ngTableDynamic to the specified
24 | * expression.
25 | * This allows the $columns array created for the table to be accessed outside of the html table
26 | * markup.
27 | *
28 | * @ngdoc directive
29 | *
30 | * @example
31 | * ```html
32 | *
33 | * ```
34 | */
35 | export function ngTableColumnsBinding($parse: IParseService) : IDirective {
36 | const directive = {
37 | restrict: 'A',
38 | link: linkFn
39 | };
40 | return directive;
41 |
42 | function linkFn($scope: TableScope, $element: IAugmentedJQuery, $attrs: InputAttributes){
43 | const setter = $parse($attrs.ngTableColumnsBinding).assign;
44 | if (setter){
45 | $scope.$watch('$columns', newColumns => {
46 | const shallowClone = (newColumns || []).slice(0);
47 | setter($scope, shallowClone);
48 | });
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/browser/ngTableDynamic.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IAugmentedJQuery, IDirective, IScope } from 'angular';
10 | import * as ng1 from 'angular';
11 | import { ColumnDef, DynamicTableColDef, DynamicTableHtmlAttributes } from './public-interfaces';
12 | import { NgTableController } from './ngTableController';
13 |
14 | interface ScopeExtensions {
15 | $columns: ColumnDef[]
16 | }
17 |
18 | function toArray(arr: ArrayLike) {
19 | return Array.prototype.slice.call(arr) as T[];
20 | }
21 |
22 | ngTableDynamic.$inject = [];
23 |
24 | /**
25 | * A dynamic version of the {@link ngTable ngTable} directive that accepts a dynamic list of columns
26 | * definitions to render
27 | * @ngdoc directive
28 | *
29 | * @example
30 | * ```html
31 | *
32 | *
33 | * {{row[col.field]}} |
34 | *
35 | *
36 | * ```
37 | */
38 | export function ngTableDynamic(): IDirective {
39 |
40 | return {
41 | restrict: 'A',
42 | priority: 1001,
43 | scope: true,
44 | controller: 'ngTableController',
45 | compile: function (tElement: IAugmentedJQuery) {
46 |
47 | const tRows = toArray(tElement[0].getElementsByTagName('tr'));
48 | const tRow = tRows.filter(tr => !ng1.element(tr).hasClass('ng-table-group'))[0];
49 |
50 | if (!tRow) {
51 | return undefined;
52 | }
53 |
54 | toArray(tRow.getElementsByTagName('td')).forEach(tCell => {
55 | const el = ng1.element(tCell);
56 | const getAttrValue = (attr: string) => {
57 | return el.attr('x-data-' + attr) || el.attr('data-' + attr) || el.attr(attr);
58 | };
59 |
60 | // this used in responsive table
61 | const titleExpr = getAttrValue('title');
62 | if (!titleExpr) {
63 | el.attr('data-title-text', '{{$columns[$index].titleAlt(this) || $columns[$index].title(this)}}');
64 | }
65 | const showExpr = el.attr('ng-if');
66 | if (!showExpr) {
67 | el.attr('ng-if', '$columns[$index].show(this)');
68 | }
69 | });
70 | return function (scope: IScope & ScopeExtensions, element: IAugmentedJQuery, attrs: DynamicTableHtmlAttributes, controller: NgTableController) {
71 | const expr = controller.parseNgTableDynamicExpr(attrs.ngTableDynamic);
72 |
73 | controller.setupBindingsToInternalScope(expr.tableParams);
74 | controller.compileDirectiveTemplates();
75 |
76 | scope.$watchCollection(expr.columns, (newCols/*, oldCols*/) => {
77 | scope.$columns = controller.buildColumns(newCols);
78 | controller.loadFilterData(scope.$columns);
79 | });
80 | };
81 | }
82 | };
83 | }
--------------------------------------------------------------------------------
/src/browser/ngTableFilterConfig.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import * as ng1 from 'angular';
10 | import { IServiceProvider, auto } from 'angular';
11 | import { assignPartialDeep } from '../shared';
12 | import { FilterTemplateDef } from './public-interfaces';
13 |
14 | /**
15 | * Configuration values that determine the behaviour of the `ngTableFilterConfig` service
16 | */
17 | export class FilterConfigValues {
18 | /**
19 | * The default base url to use when deriving the url for a filter template given just an alias name
20 | */
21 | defaultBaseUrl = 'ng-table/filters/';
22 | /**
23 | * The extension to use when deriving the url of a filter template when given just an alias name
24 | */
25 | defaultExt = '.html';
26 | /**
27 | * A map of alias names and their corrosponding urls. A lookup against this map will be used
28 | * to find the url matching an alias name.
29 | * If no match is found then a url will be derived using the following pattern `${defaultBaseUrl}${aliasName}.${defaultExt}`
30 | */
31 | aliasUrls: { [name: string]: string } = {};
32 | }
33 |
34 | export type FilterConfigValuesPartial = Partial
35 |
36 | /**
37 | * The angular provider used to configure the behaviour of the `NgTableFilterConfig` service.
38 | */
39 | export class NgTableFilterConfigProvider implements IServiceProvider {
40 | static $inject = ['$injector'];
41 | $get: () => NgTableFilterConfig;
42 | private config: FilterConfigValues;
43 | constructor($injector: auto.IInjectorService) {
44 | this.$get = () => {
45 | return $injector.instantiate(NgTableFilterConfig, { config: ng1.copy(this.config) });
46 | }
47 | this.$get.$inject = [];
48 | this.resetConfigs();
49 | }
50 |
51 | /**
52 | * Reset back to factory defaults the config values that `NgTableFilterConfig` service will use
53 | */
54 | resetConfigs() {
55 | this.config = new FilterConfigValues();
56 | }
57 |
58 | /**
59 | * Set the config values used by `NgTableFilterConfig` service
60 | */
61 | setConfig(customConfig: FilterConfigValuesPartial) {
62 | this.config = assignPartialDeep(ng1.copy(this.config), customConfig);
63 | }
64 | }
65 |
66 | /**
67 | * Exposes configuration values and methods used to return the location of the html
68 | * templates used to render the filter row of an ng-table directive
69 | */
70 | export class NgTableFilterConfig {
71 | static $inject = ['config'];
72 | constructor(
73 | /**
74 | * Readonly copy of the final values used to configure the service.
75 | */
76 | public readonly config: FilterConfigValues
77 | ) { }
78 |
79 | /**
80 | * Return the url of the html filter template registered with the alias supplied
81 | */
82 | getUrlForAlias(aliasName: string, filterKey?: string) {
83 | return this.config.aliasUrls[aliasName] || this.config.defaultBaseUrl + aliasName + this.config.defaultExt;
84 | }
85 |
86 | /**
87 | * Return the url of the html filter template for the supplied definition and key.
88 | * For more information see the documentation for {@link FilterTemplateMap}
89 | */
90 | getTemplateUrl(filterDef: string | FilterTemplateDef, filterKey?: string) {
91 | let filterName: string;
92 | if (typeof filterDef !== 'string') {
93 | filterName = filterDef.id;
94 | } else {
95 | filterName = filterDef;
96 | }
97 | if (filterName.indexOf('/') !== -1) {
98 | return filterName;
99 | }
100 |
101 | return this.getUrlForAlias(filterName, filterKey);
102 | }
103 | }
--------------------------------------------------------------------------------
/src/browser/ngTableFilterRow.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | const templateUrl = require('./filterRow.html');
10 |
11 | ngTableFilterRow.$inject = [];
12 |
13 | /**
14 | * directive that renders the filter header row for a table
15 | * @ngdoc directive
16 | * @example
17 | * ```html
18 | *
19 | * ```
20 | */
21 | export function ngTableFilterRow(){
22 | const directive = {
23 | restrict: 'E',
24 | replace: true,
25 | templateUrl: templateUrl,
26 | scope: true,
27 | controller: 'ngTableFilterRowController',
28 | controllerAs: '$ctrl'
29 | };
30 | return directive;
31 | }
--------------------------------------------------------------------------------
/src/browser/ngTableFilterRowController.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IScope } from 'angular';
10 | import { FilterTemplateDef, FilterTemplateDefMap } from './public-interfaces';
11 | import { NgTableFilterConfig } from './ngTableFilterConfig';
12 |
13 | /**
14 | * @private
15 | */
16 | export interface ScopeExtensions {
17 | getFilterPlaceholderValue(filterDef: string | FilterTemplateDef, filterKey?: string): string;
18 | }
19 |
20 | /**
21 | * Controller for the {@link ngTableFilterRow ngTableFilterRow} directive
22 | */
23 | export class NgTableFilterRowController {
24 | static $inject = ['$scope', 'ngTableFilterConfig'];
25 | config: NgTableFilterConfig;
26 | constructor($scope: IScope & ScopeExtensions, ngTableFilterConfig: NgTableFilterConfig) {
27 | this.config = ngTableFilterConfig;
28 |
29 | // todo: stop doing this. Why?
30 | // * scope inheritance makes it hard to know how supplies functions
31 | // * scope is not a concept in angular 2
32 | // make function available to filter templates
33 | $scope.getFilterPlaceholderValue = this.getFilterPlaceholderValue.bind(this);
34 | }
35 |
36 | getFilterCellCss(filter: FilterTemplateDefMap, layout: string) {
37 | if (layout !== 'horizontal') {
38 | return 's12';
39 | }
40 |
41 | const size = Object.keys(filter).length;
42 | const width = parseInt((12 / size).toString(), 10);
43 | return 's' + width;
44 | }
45 |
46 | getFilterPlaceholderValue(filterDef: string | FilterTemplateDef, filterKey?: string) {
47 | if (typeof filterDef === 'string') {
48 | return '';
49 | } else {
50 | return filterDef.placeholder;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/browser/ngTableGroupRow.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | const templateUrl = require('./groupRow.html');
10 |
11 | ngTableGroupRow.$inject = [];
12 |
13 | /**
14 | * directive that renders the group header row for a table
15 | * @ngdoc directive
16 | * @example
17 | * ```html
18 | *
19 | * ```
20 | */
21 | export function ngTableGroupRow(){
22 | const directive = {
23 | restrict: 'E',
24 | replace: true,
25 | templateUrl: templateUrl,
26 | scope: true,
27 | controller: 'ngTableGroupRowController',
28 | controllerAs: '$ctrl'
29 | };
30 | return directive;
31 | }
--------------------------------------------------------------------------------
/src/browser/ngTableGroupRowController.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IPromise } from 'angular';
10 | import { DataResult, GroupingFunc, Grouping, GroupSort } from '../core';
11 | import { ColumnDef } from './public-interfaces';
12 | import { TableScope } from './ngTableController';
13 |
14 | /**
15 | * @private
16 | */
17 | export interface ScopeExtensions {
18 | $selGroup: GroupingFunc | string;
19 | $selGroupTitle: string;
20 | }
21 |
22 |
23 | /**
24 | * Controller for the {@link ngTableGroupRow ngTableGroupRow} directive
25 | */
26 | export class NgTableGroupRowController {
27 | static $inject = ['$scope'];
28 | private groupFns: Array | ColumnDef> = [];
29 | constructor(private $scope: TableScope & ScopeExtensions) {
30 | $scope.$watch>('params.group()', (newGrouping) => {
31 | this.setGroup(newGrouping);
32 | }, true);
33 | }
34 |
35 | getGroupables() {
36 | const groupableCols = this.$scope.$columns.filter($column => !!$column.groupable(this.$scope));
37 | return this.groupFns.concat(groupableCols);
38 | }
39 |
40 | getGroupTitle(group: GroupingFunc | ColumnDef) {
41 | return this.isGroupingFunc(group) ? group.title : group.title(this.$scope);
42 | }
43 |
44 |
45 | getVisibleColumns() {
46 | return this.$scope.$columns.filter($column => $column.show(this.$scope))
47 | }
48 |
49 | groupBy(group: GroupingFunc | ColumnDef) {
50 | if (this.isSelectedGroup(group)) {
51 | this.changeSortDirection();
52 | } else {
53 | if (this.isGroupingFunc(group)) {
54 | this.$scope.params.group(group);
55 | } else {
56 | // it's OK, we know that groupable will return a string
57 | // this is guaranteed by getGroupables returning only
58 | // columns that return (truthy) strings
59 | this.$scope.params.group(group.groupable(this.$scope) as string);
60 | }
61 | }
62 | }
63 |
64 | isSelectedGroup(group: GroupingFunc | ColumnDef) {
65 | if (this.isGroupingFunc(group)) {
66 | return group === this.$scope.$selGroup;
67 | } else {
68 | return group.groupable(this.$scope) === this.$scope.$selGroup;
69 | }
70 | }
71 |
72 | toggleDetail() {
73 | this.$scope.params.settings().groupOptions.isExpanded = !this.$scope.params.settings().groupOptions.isExpanded;
74 | return this.$scope.params.reload();
75 | }
76 |
77 | private changeSortDirection() {
78 | let newDirection: GroupSort;
79 | if (this.$scope.params.hasGroup(this.$scope.$selGroup, 'asc')) {
80 | newDirection = 'desc';
81 | } else if (this.$scope.params.hasGroup(this.$scope.$selGroup, 'desc')) {
82 | newDirection = '';
83 | } else {
84 | newDirection = 'asc';
85 | }
86 | this.$scope.params.group(this.$scope.$selGroup, newDirection);
87 | }
88 |
89 | private findGroupColumn(groupKey: GroupingFunc | string) {
90 | return this.$scope.$columns.filter($column => $column.groupable(this.$scope) === groupKey)[0];
91 | }
92 |
93 | private isGroupingFunc(val: ColumnDef | Grouping): val is GroupingFunc {
94 | return typeof val === 'function';
95 | }
96 |
97 | private setGroup(grouping: Grouping) {
98 | const existingGroupCol = this.findGroupColumn(this.$scope.$selGroup);
99 | if (existingGroupCol && existingGroupCol.show.assign) {
100 | existingGroupCol.show.assign(this.$scope, true);
101 | }
102 | if (this.isGroupingFunc(grouping)) {
103 | this.groupFns = [grouping];
104 | this.$scope.$selGroup = grouping;
105 | this.$scope.$selGroupTitle = grouping.title || '';
106 | } else {
107 | // note: currently only one group is implemented
108 | const groupKey = Object.keys(grouping || {})[0];
109 | const groupedColumn = this.findGroupColumn(groupKey);
110 | if (groupedColumn) {
111 | this.$scope.$selGroupTitle = groupedColumn.title(this.$scope);
112 | this.$scope.$selGroup = groupKey;
113 | if (groupedColumn.show.assign) {
114 | groupedColumn.show.assign(this.$scope, false);
115 | }
116 | }
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/src/browser/ngTablePagination.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import * as ng1 from 'angular';
10 | import { NgTableEventsChannel, PageButton } from '../core'
11 | import { TableScope } from './ngTableController';
12 |
13 | interface ScopeExtensions {
14 | pages: PageButton[]
15 | }
16 |
17 | ngTablePagination.$inject = ['$compile', '$document', 'ngTableEventsChannel'];
18 |
19 | /**
20 | * Directive that renders the table pagination controls
21 | * @ngdoc directive
22 | */
23 | export function ngTablePagination($compile: ng1.ICompileService, $document: ng1.IDocumentService, ngTableEventsChannel: NgTableEventsChannel): ng1.IDirective {
24 |
25 | return {
26 | restrict: 'A',
27 | scope: {
28 | 'params': '=ngTablePagination',
29 | 'templateUrl': '='
30 | },
31 | replace: false,
32 | link: function(scope: TableScope & ScopeExtensions, element: ng1.IAugmentedJQuery/*, attrs*/) {
33 |
34 | ngTableEventsChannel.onAfterReloadData(function(pubParams) {
35 | scope.pages = pubParams.generatePagesArray();
36 | }, scope, function(pubParams){
37 | return pubParams === scope.params;
38 | });
39 |
40 | scope.$watch('templateUrl', function(templateUrl) {
41 | if (templateUrl === undefined) {
42 | return;
43 | }
44 | const template = ng1.element('', $document);
45 | element.append(template);
46 | $compile(template)(scope);
47 | });
48 | }
49 | };
50 | }
--------------------------------------------------------------------------------
/src/browser/ngTableSelectFilterDs.directive.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ngTable: Table + Angular JS
3 | *
4 | * @author Vitalii Savchuk
5 | * @url https://github.com/esvit/ng-table/
6 | * @license New BSD License
7 | */
8 |
9 | import { IAttributes, IDirective, IParseService, IQService, IPromise, IScope } from 'angular';
10 | import { ColumnDef, SelectData, SelectDataFunc, SelectOption } from './public-interfaces';
11 |
12 | /**
13 | * @private
14 | */
15 | export interface InputAttributes extends IAttributes {
16 | ngTableSelectFilterDs: string;
17 | }
18 |
19 | /**
20 | * @private
21 | */
22 | export interface ScopeExtensions {
23 | $selectData: SelectOption[]
24 | }
25 |
26 | ngTableSelectFilterDs.$inject = [];
27 |
28 | /**
29 | * Takes the array returned by $column.filterData and makes it available as `$selectData` on the `$scope`.
30 | *
31 | * The resulting `$selectData` array will contain an extra item that is suitable to represent the user
32 | * "deselecting" an item from a `