tableSpec.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. describe('ng-table', function() {
  2. var data = [
  3. { id: 1, name: "Moroni", age: 50, money: -10 },
  4. { id: 2, name: "Tiancum", age: 43, money: 120 },
  5. { id: 3, name: "Jacob", age: 27, money: 5.5 },
  6. { id: 4, name: "Nephi", age: 29, money: -54 },
  7. { id: 5, name: "Enos", age: 34, money: 110 },
  8. { id: 6, name: "Tiancum", age: 43, money: 1000 },
  9. { id: 7, name: "Jacob", age: 27, money: -201 },
  10. { id: 8, name: "Nephi", age: 29, money: 100 },
  11. { id: 9, name: "Enos", age: 34, money: -52.5 },
  12. { id: 10, name: "Tiancum", age: 43, money: 52.1 },
  13. { id: 11, name: "Jacob", age: 27, money: 110 },
  14. { id: 12, name: "Nephi", age: 29, money: -55 },
  15. { id: 13, name: "Enos", age: 34, money: 551 },
  16. { id: 14, name: "Tiancum", age: 43, money: -1410 },
  17. { id: 15, name: "Jacob", age: 27, money: 410 },
  18. { id: 16, name: "Nephi", age: 29, money: 100 },
  19. { id: 17, name: "Enos", age: 34, money: -100 }
  20. ];
  21. beforeEach(module('ngTable'));
  22. var scope;
  23. beforeEach(inject(function($rootScope) {
  24. scope = $rootScope.$new(true);
  25. }));
  26. describe('basics', function(){
  27. var elm;
  28. beforeEach(inject(function($compile, $q) {
  29. elm = angular.element(
  30. '<div>' +
  31. '<table ng-table="tableParams" show-filter="true">' +
  32. '<tr ng-repeat="user in $data">' +
  33. '<td data-header-title="\'Sort by Name\'" data-title="nameTitle()" filter="{ \'name\': \'text\' }" sortable="\'name\'" data-header-class="getCustomClass($column)">' +
  34. '{{user.name}}' +
  35. '</td>' +
  36. '<td x-data-header-title="\'Sort by Age\'" x-data-title="ageTitle()" sortable="\'age\'" x-data-header-class="getCustomClass($column)">' +
  37. '{{user.age}}' +
  38. '</td>' +
  39. '<td header-title="\'Sort by Money\'" title="moneyTitle()" filter="{ \'action\': \'select\' }" filter-data="money($column)" header-class="getCustomClass($column)">' +
  40. '{{user.money}}' +
  41. '</td>' +
  42. '</tr>' +
  43. '</table>' +
  44. '</div>');
  45. scope.nameTitle = function(){
  46. return 'Name of person';
  47. };
  48. scope.ageTitle = function(){
  49. return 'Age';
  50. };
  51. scope.moneyTitle = function(){
  52. return 'Money';
  53. };
  54. scope.getCustomClass = function($column){
  55. if ($column.title().indexOf('Money') !== -1){
  56. return 'moneyHeaderClass';
  57. } else{
  58. return 'customClass';
  59. }
  60. };
  61. scope.money = function(/*$column*/) {
  62. var def = $q.defer();
  63. def.resolve([{
  64. 'id': 10,
  65. 'title': '10'
  66. }]);
  67. return def;
  68. };
  69. $compile(elm)(scope);
  70. scope.$digest();
  71. }));
  72. it('should create table header', function() {
  73. var thead = elm.find('thead');
  74. expect(thead.length).toBe(1);
  75. var rows = thead.find('tr');
  76. expect(rows.length).toBe(2);
  77. var titles = angular.element(rows[0]).find('th');
  78. expect(titles.length).toBe(3);
  79. expect(angular.element(titles[0]).text().trim()).toBe('Name of person');
  80. expect(angular.element(titles[1]).text().trim()).toBe('Age');
  81. expect(angular.element(titles[2]).text().trim()).toBe('Money');
  82. expect(angular.element(rows[1]).hasClass('ng-table-filters')).toBeTruthy();
  83. var filters = angular.element(rows[1]).find('th');
  84. expect(filters.length).toBe(3);
  85. expect(angular.element(filters[0]).hasClass('filter')).toBeTruthy();
  86. expect(angular.element(filters[1]).hasClass('filter')).toBeTruthy();
  87. expect(angular.element(filters[2]).hasClass('filter')).toBeTruthy();
  88. });
  89. it('should create table header classes', inject(function($compile, $rootScope) {
  90. var thead = elm.find('thead');
  91. var rows = thead.find('tr');
  92. var titles = angular.element(rows[0]).find('th');
  93. expect(angular.element(titles[0]).hasClass('header')).toBeTruthy();
  94. expect(angular.element(titles[1]).hasClass('header')).toBeTruthy();
  95. expect(angular.element(titles[2]).hasClass('header')).toBeTruthy();
  96. expect(angular.element(titles[0]).hasClass('sortable')).toBeTruthy();
  97. expect(angular.element(titles[1]).hasClass('sortable')).toBeTruthy();
  98. expect(angular.element(titles[2]).hasClass('sortable')).toBeFalsy();
  99. expect(angular.element(titles[0]).hasClass('customClass')).toBeTruthy();
  100. expect(angular.element(titles[1]).hasClass('customClass')).toBeTruthy();
  101. expect(angular.element(titles[2]).hasClass('moneyHeaderClass')).toBeTruthy();
  102. }));
  103. it('should create table header titles', function() {
  104. var thead = elm.find('thead');
  105. var rows = thead.find('tr');
  106. var titles = angular.element(rows[0]).find('th');
  107. expect(angular.element(titles[0]).attr('title').trim()).toBe('Sort by Name');
  108. expect(angular.element(titles[1]).attr('title').trim()).toBe('Sort by Age');
  109. expect(angular.element(titles[2]).attr('title').trim()).toBe('Sort by Money');
  110. });
  111. it('should show scope data', inject(function(NgTableParams) {
  112. var tbody = elm.find('tbody');
  113. expect(tbody.length).toBe(1);
  114. var rows = tbody.find('tr');
  115. expect(rows.length).toBe(0);
  116. var params = new NgTableParams({
  117. page: 1, // show first page
  118. count: 10 // count per page
  119. }, {
  120. total: data.length, // length of data
  121. getData: function($defer, params) {
  122. $defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
  123. }
  124. });
  125. scope.tableParams = params;
  126. scope.$digest();
  127. rows = tbody.find('tr');
  128. expect(rows.length).toBe(10);
  129. scope.tableParams.page(2);
  130. scope.$digest();
  131. rows = tbody.find('tr');
  132. expect(rows.length).toBe(7);
  133. params.total(20);
  134. scope.$digest();
  135. rows = tbody.find('tr');
  136. expect(rows.length).toBe(7);
  137. }));
  138. it('should show data-title-text', inject(function(NgTableParams) {
  139. var tbody = elm.find('tbody');
  140. var params = new NgTableParams({
  141. page: 1, // show first page
  142. count: 10 // count per page
  143. }, {
  144. total: data.length, // length of data
  145. getData: function($defer, params) {
  146. $defer.resolve(data);
  147. }
  148. });
  149. scope.tableParams = params;
  150. scope.$digest();
  151. var filterRow = angular.element(elm.find('thead').find('tr')[1]);
  152. var filterCells = filterRow.find('th');
  153. expect(angular.element(filterCells[0]).attr('data-title-text').trim()).toBe('Name of person');
  154. expect(angular.element(filterCells[1]).attr('data-title-text').trim()).toBe('Age');
  155. expect(angular.element(filterCells[2]).attr('data-title-text').trim()).toBe('Money');
  156. var dataRows = elm.find('tbody').find('tr');
  157. var dataCells = angular.element(dataRows[0]).find('td');
  158. expect(angular.element(dataCells[0]).attr('data-title-text').trim()).toBe('Name of person');
  159. expect(angular.element(dataCells[1]).attr('data-title-text').trim()).toBe('Age');
  160. expect(angular.element(dataCells[2]).attr('data-title-text').trim()).toBe('Money');
  161. }));
  162. });
  163. describe('title-alt', function() {
  164. var elm;
  165. beforeEach(inject(function($compile, NgTableParams) {
  166. elm = angular.element(
  167. '<table ng-table="tableParams">' +
  168. '<tr ng-repeat="user in $data">' +
  169. '<td title="\'Name of person\'" title-alt="\'Name\'">{{user.name}}</td>' +
  170. '<td title="\'Age of person\'" data-title-alt="\'Age\'">{{user.age}}</td>' +
  171. '<td title="\'Money earned\'" x-data-title-alt="\'£\'">{{user.money}}</td>' +
  172. '</tr>' +
  173. '</table>');
  174. $compile(elm)(scope);
  175. scope.$digest();
  176. var params = new NgTableParams({
  177. page: 1, // show first page
  178. count: 10 // count per page
  179. }, {
  180. total: data.length, // length of data
  181. getData: function($defer, params) {
  182. $defer.resolve(data);
  183. }
  184. });
  185. scope.tableParams = params;
  186. scope.$digest();
  187. }));
  188. it('should show as data-title-text', inject(function($compile) {
  189. var filterRow = angular.element(elm.find('thead').find('tr')[1]);
  190. var filterCells = filterRow.find('th');
  191. expect(angular.element(filterCells[0]).attr('data-title-text').trim()).toBe('Name');
  192. expect(angular.element(filterCells[1]).attr('data-title-text').trim()).toBe('Age');
  193. expect(angular.element(filterCells[2]).attr('data-title-text').trim()).toBe('£');
  194. var dataRows = elm.find('tbody').find('tr');
  195. var dataCells = angular.element(dataRows[0]).find('td');
  196. expect(angular.element(dataCells[0]).attr('data-title-text').trim()).toBe('Name');
  197. expect(angular.element(dataCells[1]).attr('data-title-text').trim()).toBe('Age');
  198. expect(angular.element(dataCells[2]).attr('data-title-text').trim()).toBe('£');
  199. }));
  200. });
  201. describe('sorting', function() {
  202. it('should provide $column definition', inject(function($compile) {
  203. var columnDef;
  204. var elm = angular.element(
  205. '<table ng-table="tableParams">' +
  206. '<tr ng-repeat="user in $data">' +
  207. '<td title="\'Age\'" sortable="captureColumn($column)">{{user.age}}</td>' +
  208. '</tr>' +
  209. '</table>');
  210. scope.captureColumn = function($column){
  211. columnDef = $column;
  212. return 'age'
  213. };
  214. $compile(elm)(scope);
  215. scope.$digest();
  216. expect(columnDef).toBeDefined();
  217. }));
  218. });
  219. describe('filters', function(){
  220. var $capturedColumn;
  221. beforeEach(inject(function() {
  222. // stash a reference to $column definition so that its available in asserts
  223. scope.captureColumn = function ($column) {
  224. $capturedColumn = $column;
  225. };
  226. }));
  227. describe('filter specified as alias', function(){
  228. var elm;
  229. beforeEach(inject(function($compile, NgTableParams) {
  230. elm = angular.element(
  231. '<div>' +
  232. '<table ng-table="tableParams" show-filter="true">' +
  233. '<tr ng-repeat="user in $data">' +
  234. '<td header-class="captureColumn($column)" title="\'Name\'" ' +
  235. 'filter="usernameFilter">{{user.name}}</td>' +
  236. '</tr>' +
  237. '</table>' +
  238. '</div>');
  239. $compile(elm)(scope);
  240. scope.$digest();
  241. // 'text' is a shortcut alias for the template ng-table/filters/text
  242. scope.usernameFilter = {username: 'text'};
  243. scope.tableParams = new NgTableParams({}, {});
  244. scope.$digest();
  245. }));
  246. it('should render named filter template', function() {
  247. var inputs = elm.find('thead').find('tr').eq(1).find('th').find('input');
  248. expect(inputs.length).toBe(1);
  249. expect(inputs.eq(0).attr('type')).toBe('text');
  250. expect(inputs.eq(0).attr('ng-model')).not.toBeUndefined();
  251. expect(inputs.eq(0).attr('name')).toBe('username');
  252. });
  253. it('should databind ngTableParams.filter to filter input', function () {
  254. scope.tableParams.filter()['username'] = 'my name is...';
  255. scope.$digest();
  256. var input = elm.find('thead').find('tr').eq(1).find('th').find('input');
  257. expect(input.val()).toBe('my name is...');
  258. });
  259. it('should make filter def available on $column', function () {
  260. expect($capturedColumn).toBeDefined();
  261. expect($capturedColumn.filter).toBeDefined();
  262. expect($capturedColumn.filter()['username']).toBe('text');
  263. });
  264. it('when filter changes should reset page number to 1', inject(function ($timeout) {
  265. // trigger initial load of data so that subsequent changes to filter will trigger reset of page #
  266. scope.tableParams.filter()['username'] = 'initial value';
  267. scope.$digest();
  268. $timeout.flush(); // trigger delayed filter
  269. // set page to something other than 1
  270. scope.tableParams.page(5);
  271. expect(scope.tableParams.page()).toBe(5); // checking assumptions
  272. // when
  273. scope.tableParams.filter()['username'] = 'new value';
  274. scope.$digest();
  275. $timeout.flush(); // trigger delayed filter
  276. expect(scope.tableParams.page()).toBe(1);
  277. }));
  278. });
  279. describe('filter specified with url', function(){
  280. var elm;
  281. beforeEach(inject(function($compile, NgTableParams) {
  282. elm = angular.element(
  283. '<div>' +
  284. '<script type="text/ng-template" id="ng-table/filters/customNum.html"><input type="number" id="{{name}}"/></script>' +
  285. '<table ng-table="tableParams" show-filter="true">' +
  286. '<tr ng-repeat="user in $data">' +
  287. '<td header-class="captureColumn($column)" title="\'Age\'" ' +
  288. 'filter="{ \'age\': \'ng-table/filters/customNum.html\' }">{{user.age}}</td>' +
  289. '</tr>' +
  290. '</table>' +
  291. '</div>');
  292. $compile(elm)(scope);
  293. scope.tableParams = new NgTableParams({}, {});
  294. scope.$digest();
  295. }));
  296. it('should render filter template specified by url', function() {
  297. var inputs = elm.find('thead').find('tr').eq(1).find('th').find('input');
  298. expect(inputs.length).toBe(1);
  299. expect(inputs.eq(0).attr('type')).toBe('number');
  300. expect(inputs.eq(0).attr('id')).toBe('age');
  301. });
  302. });
  303. describe('multiple filter inputs', function(){
  304. var elm;
  305. beforeEach(inject(function($compile, NgTableParams) {
  306. elm = angular.element(
  307. '<div>' +
  308. '<table ng-table="tableParams" show-filter="true">' +
  309. '<tr ng-repeat="user in $data">' +
  310. '<td header-class="captureColumn($column)" title="\'Name\'" ' +
  311. 'filter="{ \'name\': \'text\', \'age\': \'text\' }">{{user.name}}</td>' +
  312. '</tr>' +
  313. '</table>' +
  314. '</div>');
  315. $compile(elm)(scope);
  316. scope.$digest();
  317. scope.tableParams = new NgTableParams({}, {});
  318. scope.$digest();
  319. }));
  320. it('should render filter template for each key/value pair ordered by key', function() {
  321. var inputs = elm.find('thead').find('tr').eq(1).find('th').find('input');
  322. expect(inputs.length).toBe(2);
  323. expect(inputs.eq(0).attr('type')).toBe('text');
  324. expect(inputs.eq(0).attr('ng-model')).not.toBeUndefined();
  325. expect(inputs.eq(1).attr('type')).toBe('text');
  326. expect(inputs.eq(1).attr('ng-model')).not.toBeUndefined();
  327. });
  328. it('should databind ngTableParams.filter to filter inputs', function () {
  329. scope.tableParams.filter()['name'] = 'my name is...';
  330. scope.tableParams.filter()['age'] = '10';
  331. scope.$digest();
  332. var inputs = elm.find('thead').find('tr').eq(1).find('th').find('input');
  333. expect(inputs.eq(1).val()).toBe('my name is...');
  334. expect(inputs.eq(0).val()).toBe('10');
  335. });
  336. it('should make filter def available on $column', function () {
  337. expect($capturedColumn).toBeDefined();
  338. expect($capturedColumn.filter).toBeDefined();
  339. expect($capturedColumn.filter()['name']).toBe('text');
  340. expect($capturedColumn.filter()['age']).toBe('text');
  341. });
  342. });
  343. describe('dynamic filter', function(){
  344. var elm, ageFilter;
  345. beforeEach(inject(function($compile, NgTableParams) {
  346. ageFilter = {age: 'text'};
  347. elm = angular.element(
  348. '<div>' +
  349. '<script type="text/ng-template" id="ng-table/filters/number.html"><input type="number" name="{{name}}"/></script>' +
  350. '<table ng-table="tableParams" show-filter="true">' +
  351. '<tr ng-repeat="user in $data">' +
  352. '<td title="\'Name\'" filter="getFilter($column)">{{user.name}}</td>' +
  353. '<td title="\'Age\'" filter="getFilter($column)">{{user.age}}</td>' +
  354. '</tr>' +
  355. '</table>' +
  356. '</div>');
  357. $compile(elm)(scope);
  358. scope.$digest();
  359. scope.getFilter = function(colDef){
  360. if (colDef.id === 0) {
  361. return {username: 'text'};
  362. } else if (colDef.id === 1) {
  363. return ageFilter;
  364. }
  365. };
  366. scope.tableParams = new NgTableParams({}, {});
  367. scope.$digest();
  368. }));
  369. it('should render named filter template', function() {
  370. var usernameInput = elm.find('thead').find('tr').eq(1).find('th').eq(0).find('input');
  371. expect(usernameInput.attr('type')).toBe('text');
  372. expect(usernameInput.attr('name')).toBe('username');
  373. var ageInput = elm.find('thead').find('tr').eq(1).find('th').eq(1).find('input');
  374. expect(ageInput.attr('type')).toBe('text');
  375. expect(ageInput.attr('name')).toBe('age');
  376. });
  377. it('should databind ngTableParams.filter to filter input', function () {
  378. scope.tableParams.filter()['username'] = 'my name is...';
  379. scope.tableParams.filter()['age'] = '10';
  380. scope.$digest();
  381. var usernameInput = elm.find('thead').find('tr').eq(1).find('th').eq(0).find('input');
  382. expect(usernameInput.val()).toBe('my name is...');
  383. var ageInput = elm.find('thead').find('tr').eq(1).find('th').eq(1).find('input');
  384. expect(ageInput.val()).toBe('10');
  385. });
  386. it('should render new template as filter changes', function() {
  387. ageFilter.age = 'number';
  388. scope.$digest();
  389. var ageInput = elm.find('thead').find('tr').eq(1).find('th').eq(1).find('input');
  390. expect(ageInput.attr('type')).toBe('number');
  391. expect(ageInput.attr('name')).toBe('age');
  392. });
  393. });
  394. });
  395. });