├── .editorconfig ├── .gitattributes ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── gulp └── settings.js ├── gulpfile.coffee ├── package-lock.json ├── package.json └── src ├── index.coffee ├── ng_table_async.coffee ├── ng_table_async_defaults.coffee ├── nta_action.coffee ├── nta_loading.coffee ├── nta_no_data.coffee ├── nta_pager.coffee ├── styles.css └── templates ├── _ng_table_async_action.pug ├── _ng_table_async_loading.pug ├── _ng_table_async_no_data.pug └── _ng_table_async_pager.pug /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Managing line ending conversions 2 | # See http://git-scm.com/docs/gitattributes#_end-of-line_conversion 3 | * text=auto 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.16.3 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Andrés Mata Suárez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ngTableAsync 2 | ============================= 3 | **[ngTable](http://ng-table.com/)** wrapper that offers some base functionality and abstractions for working with asynchronous tables. It serves as a way to avoid table boilerplate code, by declaring only those things relevant in our context. 4 | 5 | It's specially useful for backoffice/dashboard developers, so they can come out with a fully functional asynchronous table with a default Bootstrap style in very few quick steps, where **behaviour has more priority than markup**. 6 | 7 | This module **in no way** intends to be a replacement for **ngTable**, but an enhancement. If it doesn't satisfy your needs, submit a feature PR or go back to **ngTable** :). 8 | 9 | [Homepage](https://andresmatasuarez.github.io/ng-table-async/) 10 | 11 | ## Index 12 | 1. [Requirements](#requirements) 13 | 2. [Installation](#installation) 14 | 3. [Usage](#usage) 15 | 4. [Configuration object](#configuration-object) 16 | 5. [Examples](#examples) 17 | 6. [Development](#development) 18 | 7. [TODO](#todo) 19 | 8. [License](#license) 20 | 21 | ## Requirements 22 | * [AngularJS](https://angularjs.org/) 23 | * [Bootstrap](http://getbootstrap.com/) - styles only 24 | * [Lodash](https://lodash.com/) 25 | * [ngTable](http://ng-table.com/) 26 | 27 | ### Optional requirements 28 | * [UI.Bootstrap](https://angular-ui.github.io/bootstrap) 29 | 30 | ## Installation 31 | 1. Include dependency files in your markup: 32 | * `` 33 | * `` 34 | * `` 35 | * `` 36 | * `` 37 | 2. Include **ngTableAsync** files in your markup: 38 | * `` 39 | * `` 40 | 3. Include **ngTableAsync** as a module dependency in your **AngularJS** app:
41 | `angular.module('myApp', [ ... 'ngTableAsync' ... ])` 42 | 43 | > NOTE: `ng-table-async.js` contains the raw **ngTableAsync** module, whereas `ng-table-async-tpls.js` also includes default directives' templates. 44 | > If you choose the first, you must supply all templates yourself, just the same as if you choose `ui-bootstrap.js` over `ui-boostrap-tpls.js`. 45 | 46 | ## Usage 47 | ngTableAsync offers a way to write HTML tables in a column-oriented declarative way: 48 | ```html 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Actions 58 | 59 | 60 | 61 | 62 | 63 | 64 | ``` 65 | * **`nta-column`**: defines a column. 66 | * Children 67 | * **`nta-header`**: defines HTML markup for column header 68 | * **`nta-content`**: defines HTML markup for column content. 69 | 70 | By looking at the above example, we can infer that: 71 | * Both children of `nta-column` can also be defined as `header` and `content` attributes of the `nta-column` element, respectively. 72 | * Child-wise definition takes more precedence than attribute-wise definition. 73 | * If the only child of `nta-column` is `nta-content`, then we can skip the `nta-content` tag. 74 | * There is a `nta-action` element that seems to define an action. 75 | 76 | ### Directives 77 | **ngTableAsync** also defines the following directives for further customization: 78 | 79 | #### Directive: `ntaAction` 80 | To declare action buttons for each row element in the table. It is only allowed as child of `nta-header` or `nta-content` elements. Supports the following attributes configuration: 81 | * **`label`**: Action button label 82 | * **`action`**: Key referencing an action in the actions array of **ngTableAsync**. See [Configuration object](#configuration-object) section for more information. 83 | * **`size`**: Action button size, using Bootstrap size suffixes. Suppported values: `xs`, `sm`, `lg`. *Defaults to default button size*. 84 | * **`icon`**: Action Button icon class. *Defaults to no icon*. 85 | * **`style`**: Action button style, using Bootstrap style suffixes. Supported values: `default`, `primary`, `success`, `info`, `warning`, `danger`, `link`. *Defaults to `default`*. 86 | * **`template-url`**: Markup template url. Defaults to `'_ng_table_async_action.html'` 87 | > When overriding this template, **ngTableAsync** exposes all this attributes in the scope, plus a function `do`. You may or may not make use of them but you should ***not*** forget to call the `do` function to trigger the action in the template. For example: include `ng-click="do()"` in some button in your custom template. 88 | 89 | ```html 90 | 91 | ... 92 | 99 | ... 100 | 101 | ``` 102 | 103 | #### Directive: `ntaLoading` 104 | To render the 'Loading table' markup. Supports the following attributes configuration: 105 | * **`template-url`**: Markup template url. Defaults to `'_ng_table_async_loading.html'` 106 | 107 | ```html 108 | 109 | ... 110 | 111 | ... 112 | 113 | ``` 114 | > NOTE: `ntaLoading` directive is **only** used to override 'Loading table' page template. **Neither its location nor the times it is included in the markup** have any kind of influence in the resulting table. 115 | 116 | #### Directive: `ntaNoData` 117 | To render the markup to show when table is empty. Supports the following attribute configuration: 118 | * **`text`**: Text to show when table is empty. 119 | * **`template-url`**: Markup template url. Defaults to `'_ng_table_async_no_data.html'` 120 | > When overriding this template, **ngTableAsync** exposes the `text` attribute in the scope of the template. You may or may not make use of it. 121 | 122 | ```html 123 | 124 | ... 125 | 126 | ... 127 | 128 | ``` 129 | > NOTE: `ntaNoData` directive is **only** used to override 'No results available' page template. **Neither its location nor the times it is included in the markup** have any kind of influence in the resulting table. 130 | 131 | #### Directive: `ntaPager` 132 | To render the pagination markup template. Supports the following attribute configuration: 133 | * **`template-url`**: Markup template url. Defaults to `'_ng_table_async_pager.html'` 134 | > When overriding this template, please refer to **ngTable**'s documentation on how to override its pager. 135 | 136 | ```html 137 | 138 | ... 139 | 140 | ... 141 | 142 | ``` 143 | > NOTE: `ntaPager` directive is **only** used to override pager's template. **Neither its location nor the times it is included in the markup** have any kind of influence in the resulting table. 144 | 145 | ## Configuration object 146 | **ngTableAsync** accepts an `options` attribute for initialization of table-level settings: 147 | ```html 148 | 149 | ... 150 | 151 | ``` 152 | Of course, `tableOptions` should be exposed in the scope where **ngTableAsync** is being created, and it can contain any of the following properties: 153 | ```javascript 154 | $scope.tableOptions = { 155 | defaultPage : 3, // Default selected page. Defaults to 1. 156 | pageSize : 5, // Table page size. Defaults to 10. 157 | pagerOnTop : true, // Enable pager above table. Defaults to false. 158 | pagerOnBottom : false, // Enable pager below table. Defaults to true. 159 | headerIfEmpty : false, // Do not hide table header when table is empty. Defaults to true. 160 | 161 | // REQUIRED 162 | // Function to retrieve current page's data, in terms of 'skip' and 'limit' params 163 | // skip: rows to skip from the beggining of the data. 164 | // limit: quantity of rows to return. 165 | // Returns a promise of an array of data. 166 | getPage: function(skip, limit){ 167 | returns API.items.getPage(skip, limit); 168 | }, 169 | 170 | // Actions 171 | // Each action can be a Function or an Object. 172 | actions: { 173 | 174 | // Action definition using Object form 175 | actionName: { 176 | reload: false, // Reload table on this action's completion. Defaults to true. 177 | method: function(item){ 178 | // Action to perform on row item. 179 | // If a promise is not returned, it will be promisified internally. 180 | // ngTableAsync will render the 'Loading table' markup until action completion. 181 | }, 182 | 183 | // If action requires confirmation dialog. 184 | // Action method will only be triggered on dialog acceptance. 185 | // IMPORTANT: UI.Bootstrap should be included for dialog to work. 186 | dialog: { 187 | templateUrl : '_my_action_dialog.html', 188 | params : {} // Params to be passed to dialog template scope. 189 | onCancel : function(item, params){} // To be called on dialog cancel 190 | } 191 | }, 192 | 193 | // Action definition using Function form. 194 | // Simplest form to define an action. 195 | // Table will be reload on completion, and no dialog confirmation is required. 196 | // Same as: anotherActionName: { method: function(item){} } 197 | anotherActionName: function(item){}, 198 | } 199 | }; 200 | ``` 201 | 202 | ## Examples 203 | You can view a variety of usage examples in [ngTableAsync homepage](https://andresmatasuarez.github.io/ng-table-async/). 204 | 205 | ## Development 206 | 1. Fork repo 207 | 2. `npm install` 208 | 3. `npm install gulp -g` 209 | 4. `gulp` - Watches for changes in `src` directory and reruns tasks on each modified file. Outputs are in `dist` directory. 210 | 4. Write contribution 211 | 5. Write tests 212 | 6. Submit Pull Request 213 | 7. Build and release: 214 | ``` 215 | npm run build 216 | git add . 217 | git commit "New release files" 218 | npm run release 219 | ``` 220 | 221 | ## TODO 222 | * Tests 223 | * Global override of templates. 224 | * Receive custom ngTable configuration object and use it on ngTableParams instantiation. 225 | * Basic sorting and filtering out of the box. 226 | 227 | ## License 228 | The MIT License (MIT) 229 | 230 | Copyright (c) 231 | 232 | Permission is hereby granted, free of charge, to any person obtaining a copy 233 | of this software and associated documentation files (the "Software"), to deal 234 | in the Software without restriction, including without limitation the rights 235 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 236 | copies of the Software, and to permit persons to whom the Software is 237 | furnished to do so, subject to the following conditions: 238 | 239 | The above copyright notice and this permission notice shall be included in 240 | all copies or substantial portions of the Software. 241 | 242 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 243 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 244 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 245 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 246 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 247 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 248 | THE SOFTWARE. 249 | -------------------------------------------------------------------------------- /gulp/settings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | paths: { 5 | pkg: './package.json', 6 | all: './*', 7 | src: { 8 | root : './src', 9 | css : './src/**/*.css', 10 | templates : './src/templates/**/*.pug', 11 | index : './src/index.coffee', 12 | coffee : [ './src/index.coffee', './src/**/*.coffee' ] 13 | }, 14 | dest: { 15 | root : './dist', 16 | coffee : './dist', 17 | css : './dist', 18 | templates : './dist', 19 | sourcemaps : './dist' 20 | } 21 | }, 22 | 23 | coffee: { 24 | filename: 'ng-table-async.js' 25 | }, 26 | 27 | css: { 28 | filename: 'ng-table-async.css' 29 | }, 30 | 31 | templates: { 32 | filename : 'ng-table-async-tpls.js', 33 | module : 'ngTableAsync' 34 | }, 35 | 36 | minExtensions: { 37 | js : '.min.js', 38 | html : '.min.html', 39 | css : '.min.css' 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /gulpfile.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | _ = require 'lodash' 4 | path = require 'path' 5 | del = require 'del' 6 | runSequence = require 'run-sequence' 7 | eventStream = require 'event-stream' 8 | minimist = require 'minimist' 9 | gulp = require 'gulp' 10 | gulpLoadPlugins = require 'gulp-load-plugins' 11 | pkg = require './package.json' 12 | settings = require './gulp/settings' 13 | 14 | options = minimist process.argv.slice(2), string: 'type' 15 | plugins = gulpLoadPlugins() 16 | 17 | BANNER = """ 18 | /* 19 | * #{ pkg.name } 20 | * #{ pkg.description } 21 | * @author #{ pkg.author } 22 | * @version #{ pkg.version } 23 | * @link #{ pkg.homepage } 24 | * @license #{ pkg.license } 25 | */ 26 | 27 | """ 28 | 29 | appendTap = (content, atStart) -> 30 | atStart = if _.isUndefined(atStart) then false else atStart 31 | plugins.tap (file, t) -> 32 | str = if _.isFunction(content) then content(file) else content 33 | contents = [ file.contents ] 34 | 35 | if atStart 36 | contents.unshift(new Buffer str) 37 | else 38 | contents.push(new Buffer str) 39 | 40 | file.contents = Buffer.concat contents 41 | t 42 | 43 | headerTap = (header) -> appendTap header, true 44 | footerTap = (header) -> appendTap header 45 | 46 | # Couldn't make this after updating dependencies 47 | # uglifyProcess = (dest, sourcemapDest) -> 48 | # lazypipe() 49 | # .pipe plugins.ngAnnotate 50 | # .pipe plugins.sourcemaps.init 51 | # .pipe plugins.uglify 52 | # .pipe headerTap, BANNER 53 | # .pipe plugins.extReplace, settings.minExtensions.js 54 | # .pipe plugins.sourcemaps.write, path.join('./', path.relative(dest, sourcemapDest)) 55 | # .pipe gulp.dest, dest 56 | 57 | # Internal tasks 58 | gulp.task 'css', -> 59 | gulp.src settings.paths.src.css 60 | .pipe plugins.sourcemaps.init() 61 | .pipe plugins.concat settings.css.filename 62 | .pipe headerTap BANNER 63 | .pipe gulp.dest settings.paths.dest.css 64 | .pipe plugins.cleanCss() 65 | .pipe headerTap BANNER 66 | .pipe plugins.extReplace settings.minExtensions.css 67 | .pipe plugins.sourcemaps.write path.join('./', path.relative(settings.paths.dest.css, settings.paths.dest.sourcemaps)) 68 | .pipe gulp.dest settings.paths.dest.css 69 | 70 | gulp.task 'coffee', -> 71 | gulp.src settings.paths.src.coffee 72 | .pipe plugins.coffee() 73 | .pipe plugins.concat settings.coffee.filename 74 | .pipe headerTap BANNER 75 | .pipe gulp.dest settings.paths.dest.coffee 76 | 77 | # See uglifyProcess above 78 | #.pipe uglifyProcess(settings.paths.dest.coffee, settings.paths.dest.sourcemaps)() 79 | .pipe plugins.ngAnnotate() 80 | .pipe plugins.sourcemaps.init() 81 | .pipe plugins.uglify() 82 | .pipe headerTap(BANNER) 83 | .pipe plugins.extReplace(settings.minExtensions.js) 84 | .pipe plugins.sourcemaps.write(path.join('./', path.relative(settings.paths.dest.coffee, settings.paths.dest.sourcemaps))) 85 | .pipe gulp.dest(settings.paths.dest.coffee) 86 | 87 | gulp.task 'templates', (cb) -> 88 | coffeeStream = gulp.src settings.paths.src.coffee 89 | .pipe plugins.coffee() 90 | 91 | templatesStream = gulp.src settings.paths.src.templates 92 | .pipe plugins.pug pretty: true 93 | .pipe plugins.htmlmin collapseWhitespace: true 94 | .pipe plugins.ngTemplates 95 | standalone : false, 96 | filename : settings.templates.filename 97 | module : settings.templates.module 98 | path : (path, base) -> 99 | path.replace(base, '').replace('/templates', '') 100 | .pipe headerTap '(function() {\n' 101 | .pipe footerTap '\n}).call(this);\n' 102 | 103 | eventStream.merge coffeeStream, templatesStream 104 | .pipe plugins.concat settings.templates.filename 105 | .pipe headerTap BANNER 106 | .pipe gulp.dest settings.paths.dest.templates 107 | 108 | # See uglifyProcess above 109 | #.pipe uglifyProcess(settings.paths.dest.templates, settings.paths.dest.sourcemaps)() 110 | .pipe plugins.ngAnnotate() 111 | .pipe plugins.sourcemaps.init() 112 | .pipe plugins.uglify() 113 | .pipe headerTap(BANNER) 114 | .pipe plugins.extReplace(settings.minExtensions.js) 115 | .pipe plugins.sourcemaps.write(path.join('./', path.relative(settings.paths.dest.templates, settings.paths.dest.sourcemaps))) 116 | .pipe gulp.dest(settings.paths.dest.templates) 117 | 118 | # Rerun the task when a file changes 119 | gulp.task 'watch', -> 120 | gulp.watch settings.paths.src.coffee, [ 'coffee' ] 121 | gulp.watch settings.paths.src.css, [ 'css' ] 122 | gulp.watch [ 123 | settings.paths.src.coffee, 124 | settings.paths.src.templates 125 | ], [ 'templates' ] 126 | 127 | # Public tasks 128 | gulp.task 'clean', -> 129 | del [ settings.paths.dest.root ] 130 | 131 | gulp.task 'build', gulp.parallel('coffee', 'css', 'templates') 132 | 133 | gulp.task 'default', gulp.series('clean', 'build', 'watch') 134 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-table-async", 3 | "version": "0.0.21", 4 | "description": "ngTable wrapper that offers some basic functionality and abstractions for working with asynchronous tables.", 5 | "main": "dist/ng-table-async-tpls.js", 6 | "files": [ 7 | "/dist/*" 8 | ], 9 | "peerDependencies": { 10 | "angular": "^1.4.3", 11 | "ng-table": "^1.0.0" 12 | }, 13 | "devDependencies": { 14 | "angular-ui-publisher": "^1.2.8", 15 | "coffeescript": "^2.5.1", 16 | "del": "^5.1.0", 17 | "event-stream": "^3.3.1", 18 | "gulp": "^4.0.2", 19 | "gulp-bump": "^0.3.1", 20 | "gulp-clean-css": "^4.3.0", 21 | "gulp-coffee": "^2.3.1", 22 | "gulp-concat": "^2.5.2", 23 | "gulp-ext-replace": "^0.2.0", 24 | "gulp-git": "^2.10.0", 25 | "gulp-htmlmin": "^1.1.2", 26 | "gulp-load-plugins": "^2.0.3", 27 | "gulp-ng-annotate": "^2.1.0", 28 | "gulp-ng-templates": "0.0.6", 29 | "gulp-pug": "^4.0.1", 30 | "gulp-sourcemaps": "^1.5.2", 31 | "gulp-tap": "^0.1.3", 32 | "gulp-uglify": "^1.2.0", 33 | "lodash": "^3.9.3", 34 | "minimist": "^1.1.1", 35 | "np": "^6.4.0", 36 | "pug": "^3.0.0", 37 | "run-sequence": "^1.1.0" 38 | }, 39 | "scripts": { 40 | "build": "gulp build", 41 | "release": "npm run build && np", 42 | "test": "echo \"Error: no test specified\"" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "https://github.com/andresmatasuarez/ng-table-async.git" 47 | }, 48 | "keywords": [ 49 | "ngTable", 50 | "angular", 51 | "async", 52 | "table", 53 | "ng-table", 54 | "module" 55 | ], 56 | "author": "Andrés Mata Suárez ", 57 | "license": "MIT", 58 | "bugs": { 59 | "url": "https://github.com/andresmatasuarez/ng-table-async/issues" 60 | }, 61 | "homepage": "https://andresmatasuarez.github.io/ng-table-async" 62 | } 63 | -------------------------------------------------------------------------------- /src/index.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module 'ngTableAsync', [ 4 | 'ngTable' 5 | ] 6 | -------------------------------------------------------------------------------- /src/ng_table_async.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | parseColumnContent = (column) -> 6 | column = angular.element column 7 | content = column.html() 8 | 9 | if content 10 | contentElement = if _.isEmpty(column.find('nta-content')) then column else column.find 'nta-content' 11 | content = "#{ contentElement[0].outerHTML }" 12 | else 13 | contentAttr = column.attr 'content' 14 | content = if contentAttr then "" else "" 15 | 16 | content 17 | 18 | parseColumnHeader = (column) -> 19 | column = angular.element column 20 | header = if _.isEmpty(column.attr 'header') then '' else column.attr('header') 21 | 22 | if header 23 | header = "" 24 | else 25 | if !_.isEmpty column.find('nta-content') 26 | header = column.find('nta-header').html() 27 | header = "#{ header }" 28 | 29 | header 30 | 31 | parseColumn = (column) -> 32 | header : parseColumnHeader column 33 | content : parseColumnContent column 34 | 35 | ###* 36 | @ngdoc directive 37 | @name ngTableAsync 38 | @module ngTableAsync 39 | @restrict E 40 | @description 41 | ngTable wrapper directive that offers some basic functionality for working with asynchronous tables. 42 | ### 43 | module.directive 'ngTableAsync', () -> 44 | restrict: 'E' 45 | scope: 46 | options: '=' 47 | 48 | template: (element, attrs) -> 49 | columns = element.find 'nta-column' 50 | parsedColumns = _.map columns, parseColumn 51 | compiledHeaders = _.map parsedColumns, 'header' 52 | compiledContents = _.map parsedColumns, 'content' 53 | 54 | # Determine 'No Data Available' template 55 | ndaElement = _.last element.find 'nta-no-data' 56 | if ndaElement 57 | ndaTemplate = ndaElement.outerHTML 58 | else 59 | ndaTemplate = "" 60 | 61 | # Determine pager template 62 | pagerElement = _.last element.find 'nta-pager' 63 | if pagerElement 64 | pagerTemplate = pagerElement.outerHTML 65 | else 66 | pagerTemplate = "" 67 | 68 | # Determine loading template 69 | loadingElement = _.last element.find 'nta-loading' 70 | if loadingElement 71 | loadingTemplate = loadingElement.outerHTML 72 | else 73 | loadingTemplate = "" 74 | 75 | # Tried to extract this template to a separate file 76 | # but there is no blocking way to load it. 77 | # Sadly, this function cannot return a promise, so 78 | # the $templateRequest alternative becomes useless. 79 | """ 80 |
81 |
82 |
83 | 84 |
85 | #{ pagerTemplate } 86 |
87 | 88 |
89 |
90 | 91 | 92 | 93 | #{ compiledHeaders.join(' ') } 94 | 95 | 96 | 97 | 98 | 99 | #{ compiledContents.join(' ') } 100 | 101 | 102 | 103 | 104 | 105 | 106 |
#{ ndaTemplate }
107 |
108 | 109 |
110 | #{ loadingTemplate } 111 |
112 | 113 |
114 | 115 |
116 | #{ pagerTemplate } 117 |
118 | 119 |
120 |
121 | 122 |
123 | 124 |
125 | #{ ndaTemplate } 126 |
127 | 128 | """ 129 | 130 | controller: ($scope, $element, $q, ngTableAsyncDefaults, NgTableParams) -> 131 | 132 | $scope.options = _.merge 133 | pagerOnTop : ngTableAsyncDefaults.PAGER_ON_TOP 134 | pagerOnBottom : ngTableAsyncDefaults.PAGER_ON_BOTTOM 135 | defaultPage : ngTableAsyncDefaults.DEFAULT_PAGE 136 | pageSize : ngTableAsyncDefaults.PAGE_SIZE 137 | headerIfEmpty : ngTableAsyncDefaults.HEADER_IF_EMPTY 138 | , $scope.options 139 | 140 | $scope.mainScope = $scope 141 | 142 | $scope.tableParams = new NgTableParams 143 | page : $scope.options.defaultPage 144 | count : $scope.options.pageSize 145 | , 146 | getData: (params) -> 147 | $scope.loading = true 148 | 149 | skip = (params.page() - 1) * params.count() 150 | limit = params.count() 151 | 152 | pagePromise = $scope.options.getPage skip, limit 153 | pagePromise = $q.all(pagePromise) if not pagePromise.then 154 | 155 | pagePromise 156 | .then (results) -> 157 | $scope.tableParams.total results[0] 158 | delete $scope.loading 159 | results[1] 160 | 161 | $scope.$on 'ng-table-async:reload', -> 162 | $scope.loading = true 163 | $scope.tableParams.reload() 164 | .then -> 165 | delete $scope.loading 166 | -------------------------------------------------------------------------------- /src/ng_table_async_defaults.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | ###* 6 | @ngdoc object 7 | @name ngTableAsyncDefaults 8 | @module ngTableAsync 9 | @description Default settings for ngTableAsync 10 | ### 11 | module.value 'ngTableAsyncDefaults', 12 | DEFAULT_PAGE : 1 13 | PAGE_SIZE : 10 14 | NO_DATA_TEXT : 'No available results to show' 15 | PAGER_ON_TOP : false 16 | PAGER_ON_BOTTOM : true 17 | HEADER_IF_EMPTY : true 18 | 19 | SUPPORTED_VALUES : 20 | NTA_ACTION_SIZE : [ 'xs', 'sm', 'lg' ] 21 | NTA_ACTION_STYLE : [ 'default', 'primary', 'success', 'info', 'warning', 'danger', 'link' ] 22 | 23 | DEFAULT_VALUES : 24 | NTA_ACTION_SIZE : '' 25 | NTA_ACTION_STYLE : 'default' 26 | 27 | DEFAULT_TEMPLATES : 28 | NTA_ACTION : '/_ng_table_async_action.html' 29 | NTA_LOADING : '/_ng_table_async_loading.html' 30 | NTA_NO_DATA : '/_ng_table_async_no_data.html' 31 | NTA_PAGER : '/_ng_table_async_pager.html' 32 | -------------------------------------------------------------------------------- /src/nta_action.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | parseDialogAttribute = (d) -> 6 | dialog = if d and d.templateUrl then d else undefined 7 | 8 | if _.isUndefined(dialog) or _.isEmpty(dialog.params) or _.isFunction(dialog.params) 9 | return dialog 10 | 11 | dialog.params = -> undefined if _.isEmpty dialog.params 12 | dialog.params = (item) -> dialog.params if _.isObject dialog.params 13 | 14 | if _.isString dialog.params 15 | dialog.params = (item) -> 16 | params = {} 17 | params[dialog.params] = item 18 | params 19 | 20 | dialog.params = (item, index) -> item: item, index: index 21 | 22 | dialog 23 | 24 | ###* 25 | @ngdoc directive 26 | @name ntaAction 27 | @module ngTableAsync 28 | @restrict E 29 | @description 30 | Renders an action button for ngTableAsync directive 31 | ### 32 | module.directive 'ntaAction', (ngTableAsyncDefaults) -> 33 | restrict : 'E' 34 | scope : true 35 | templateUrl: (element, attrs) -> 36 | if attrs.templateUrl and attrs.templateUrl != 'undefined' 37 | attrs.templateUrl 38 | else 39 | ngTableAsyncDefaults.DEFAULT_TEMPLATES.NTA_ACTION 40 | 41 | controller: ($scope, $attrs, $q, $injector) -> 42 | defaults = ngTableAsyncDefaults 43 | action = $scope.options.actions[$attrs.action] 44 | method = if _.isFunction action then action else action.method 45 | reload = if _.isUndefined action.reload then true else action.reload 46 | dialog = parseDialogAttribute action.dialog 47 | 48 | $scope.label = $attrs.label 49 | $scope.icon = if $attrs.icon and $attrs.icon != 'undefined' then $attrs.icon else undefined 50 | 51 | if $attrs.size in defaults.SUPPORTED_VALUES.NTA_ACTION_SIZE 52 | $scope.size = "btn-#{$attrs.size}" 53 | else 54 | $scope.size = defaults.DEFAULT_VALUES.NTA_ACTION_SIZE 55 | 56 | if $attrs.style in defaults.SUPPORTED_VALUES.NTA_ACTION_STYLE 57 | $scope.style = "btn-#{$attrs.style}" 58 | else 59 | $scope.style = "btn-#{defaults.DEFAULT_VALUES.NTA_ACTION_STYLE}" 60 | 61 | performAction = (item, index) -> 62 | $scope.mainScope.loading = true 63 | $q.when() 64 | .then -> method(item, index) 65 | .then -> $scope.tableParams.reload() if reload 66 | .finally -> delete $scope.mainScope.loading 67 | 68 | if !_.isEmpty action.dialog 69 | # Checks if ui.bootstrap.modal is available 70 | try 71 | $modal = $injector.get '$modal' 72 | 73 | # AngularUI Bootstrap Modal module is available 74 | performActionWithDialog = (item, index) -> 75 | params = dialog.params item, index 76 | 77 | # Launch modal 78 | modalScope = _.merge $scope.$new(true), params 79 | modalInstance = $modal.open 80 | templateUrl : dialog.templateUrl 81 | scope : modalScope 82 | 83 | # Handle result 84 | modalInstance.result 85 | .then -> 86 | performAction item, index 87 | .catch -> 88 | if dialog and dialog.onCancel 89 | dialog.onCancel item, params 90 | 91 | triggerAction = performActionWithDialog 92 | 93 | catch error 94 | # AngularUI Bootstrap Modal module is not available 95 | triggerAction = performAction 96 | else 97 | triggerAction = performAction 98 | 99 | $scope.do = -> triggerAction $scope.item, $scope.$index 100 | -------------------------------------------------------------------------------- /src/nta_loading.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | ###* 6 | @ngdoc directive 7 | @name ntaLoading 8 | @module ngTableAsync 9 | @restrict E 10 | @description 11 | Renders the 'loading table' markup for ngTableAsync directive 12 | ### 13 | module.directive 'ntaLoading', (ngTableAsyncDefaults) -> 14 | restrict: 'E' 15 | templateUrl: (element, attrs) -> 16 | if attrs.templateUrl and attrs.templateUrl != 'undefined' 17 | attrs.templateUrl 18 | else 19 | ngTableAsyncDefaults.DEFAULT_TEMPLATES.NTA_LOADING 20 | -------------------------------------------------------------------------------- /src/nta_no_data.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | ###* 6 | @ngdoc directive 7 | @name ntaNoData 8 | @module ngTableAsync 9 | @restrict E 10 | @description 11 | Renders a 'No available data' for ngTableAsync directive 12 | ### 13 | module.directive 'ntaNoData', (ngTableAsyncDefaults) -> 14 | restrict : 'E' 15 | scope : true 16 | templateUrl: (element, attrs) -> 17 | if attrs.templateUrl and attrs.templateUrl != 'undefined' 18 | attrs.templateUrl 19 | else 20 | ngTableAsyncDefaults.DEFAULT_TEMPLATES.NTA_NO_DATA 21 | 22 | controller: ($scope, $element, $attrs) -> 23 | if !$attrs.text or $attrs.text == 'undefined' 24 | $attrs.text = ngTableAsyncDefaults.NO_DATA_TEXT 25 | 26 | $scope.text = $attrs.text 27 | -------------------------------------------------------------------------------- /src/nta_pager.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module = angular.module 'ngTableAsync' 4 | 5 | ###* 6 | @ngdoc directive 7 | @name ntaPager 8 | @module ngTableAsync 9 | @restrict E 10 | @description 11 | Renders a pager for ngTableAsync directive 12 | ### 13 | module.directive 'ntaPager', (ngTableAsyncDefaults) -> 14 | restrict: 'E' 15 | template: (element, attrs) -> 16 | if !attrs.templateUrl or attrs.templateUrl == 'undefined' 17 | attrs.templateUrl = ngTableAsyncDefaults.DEFAULT_TEMPLATES.NTA_PAGER 18 | "
" 19 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | ng-table-async .nta-content .panel { 2 | margin-bottom: 0; 3 | } 4 | 5 | /* _ng_table_async_loading template */ 6 | ng-table-async .nta-content { 7 | position: relative; 8 | } 9 | 10 | ng-table-async .nta-loading-container { 11 | position : absolute; 12 | top : 0; 13 | left : 0; 14 | right : 0; 15 | bottom : 0; 16 | background : rgba(255,255,255,0.5); 17 | color : #888; 18 | } 19 | 20 | ng-table-async .nta-loading { 21 | height: 100%; 22 | } 23 | 24 | ng-table-async .nta-loading-loader { 25 | position : relative; 26 | top : 50%; 27 | transform : translate(0, -50%); 28 | text-align : center; 29 | font-size : 3em; 30 | } 31 | 32 | ng-table-async .nta-loading-spinner { 33 | -webkit-animation: spin 1s infinite linear; 34 | animation: spin 1s infinite linear; 35 | } 36 | 37 | ng-table-async @-webkit-keyframes spin { 38 | 0% { 39 | -webkit-transform: rotate(0deg); 40 | transform: rotate(0deg); 41 | } 42 | 100% { 43 | -webkit-transform: rotate(359deg); 44 | transform: rotate(359deg); 45 | } 46 | } 47 | @keyframes spin { 48 | 0% { 49 | -webkit-transform: rotate(0deg); 50 | transform: rotate(0deg); 51 | } 52 | 100% { 53 | -webkit-transform: rotate(359deg); 54 | transform: rotate(359deg); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/templates/_ng_table_async_action.pug: -------------------------------------------------------------------------------- 1 | button.btn(class="{{size}} {{style}}" type="button" ng-click="do()") 2 | span(ng-if="icon") 3 | span(class="{{icon}}") 4 | span(ng-if="label") 5 | |   6 | span(ng-bind="label") 7 | -------------------------------------------------------------------------------- /src/templates/_ng_table_async_loading.pug: -------------------------------------------------------------------------------- 1 | .nta-loading 2 | .nta-loading-loader 3 | i.glyphicon.glyphicon-refresh.nta-loading-spinner 4 | -------------------------------------------------------------------------------- /src/templates/_ng_table_async_no_data.pug: -------------------------------------------------------------------------------- 1 | h2.text-muted.text-center(ng-bind="text") 2 | -------------------------------------------------------------------------------- /src/templates/_ng_table_async_pager.pug: -------------------------------------------------------------------------------- 1 | .text-center 2 | ul.pagination.ng-table-pagination 3 | li(ng-repeat="page in pages" ng-class="{'disabled active': !page.active, 'previous': page.type == 'prev', 'next': page.type == 'next'}" ng-switch="page.type") 4 | 5 | a(ng-switch-when="prev" ng-click="params.page(page.number)" href="") 6 | span.glyphicon.glyphicon-chevron-left 7 | 8 | a(ng-switch-when="next" ng-click="params.page(page.number)" href="") 9 | span.glyphicon.glyphicon-chevron-right 10 | 11 | a(ng-switch-when="more" ng-click="params.page(page.number)" href="") 12 | | ... 13 | 14 | a(ng-switch-default="" ng-click="params.page(page.number)" href="") 15 | | {{ page.number }} 16 | --------------------------------------------------------------------------------