From e15978531382d755ec60956bfaa7d11b266e4842 Mon Sep 17 00:00:00 2001 From: Yauheni Kokatau Date: Fri, 22 Jan 2016 05:56:56 -0800 Subject: [PATCH] add onEdit event with lastValue and newValue params --- dev/example.js | 150 ++++++------- dev/index.html | 199 +++++++--------- src/js/contenteditableDirective.js | 43 ++-- src/js/directive.js | 157 +++++++------ src/js/objectTableCtrl.js | 350 +++++++++++++++-------------- 5 files changed, 439 insertions(+), 460 deletions(-) diff --git a/dev/example.js b/dev/example.js index 178914b..037553d 100644 --- a/dev/example.js +++ b/dev/example.js @@ -4,103 +4,103 @@ * gTableTest Description */ angular.module('test', ['objectTable']) -.controller('mainController', function ($scope,$http,$timeout,$q) { - - - $scope.data = [{name: "Moroni", age: 50, money: -10}, - {name: "Tiancum", age: 43,money: 120}, - {name: "Jacob", age: 27, money: 5.5}, - {name: "Nephi", age: 29,money: -54}, - {name: "Enos", age: 34,money: 110}, - {name: "Tiancum", age: 43, money: 1000}, - {name: "Jacob", age: 27,money: -201}, - {name: "Nephi", age: 29, money: 100}, - {name: "Enos", age: 34, money: -52.5}, - {name: "Tiancum", age: 43, money: 52.1}, - {name: "Jacob", age: 27, money: 110}, - {name: "Nephi", age: 29, money: -55}, - {name: "Enos", age: 34, money: 551}, - {name: "Tiancum", age: 43, money: -1410}, - {name: "Jacob", age: 27, money: 410}, - {name: "Nephi", age: 29, money: 100}, - {name: "Enos", age: 34, money: -100}]; - - $scope.test = function(e) { - alert('Alert from controller method!'); +.controller('mainController', function($scope, $http, $timeout, $q) { + + $scope.data = [{name: 'Moroni', age: 50, money: -10}, + {name: 'Tiancum', age: 43,money: 120}, + {name: 'Jacob', age: 27, money: 5.5}, + {name: 'Nephi', age: 29,money: -54}, + {name: 'Enos', age: 34,money: 110}, + {name: 'Tiancum', age: 43, money: 1000}, + {name: 'Jacob', age: 27,money: -201}, + {name: 'Nephi', age: 29, money: 100}, + {name: 'Enos', age: 34, money: -52.5}, + {name: 'Tiancum', age: 43, money: 52.1}, + {name: 'Jacob', age: 27, money: 110}, + {name: 'Nephi', age: 29, money: -55}, + {name: 'Enos', age: 34, money: 551}, + {name: 'Tiancum', age: 43, money: -1410}, + {name: 'Jacob', age: 27, money: 410}, + {name: 'Nephi', age: 29, money: 100}, + {name: 'Enos', age: 34, money: -100}]; + + $scope.test = function(e) { + alert('Alert from controller method!'); }; + $scope.logChange = function(oldValue, newValue) { + console.log(oldValue); + console.log(newValue); + }; - $scope.dataTeacherSearch = [{"employeeNo":"4433", - "name":{"firstName":"kuldeep","middleName":"dsf","lastName":"gfdkjh"}, - "department":[{"dept":"Computer Science","status":true}, - {"dept":"science","status":false}, - {"dept":"sports","status":false}, - {"dept":"sdlkf","status":false}], - "designation":[{"post":"director","status":false}, - {"post":"principal","status":false}, - {"post":"teaching","status":true}, - {"post":"nonteaching","status":false}]}]; + $scope.dataTeacherSearch = [{'employeeNo': '4433', + 'name': {'firstName': 'kuldeep','middleName': 'dsf','lastName': 'gfdkjh'}, + 'department': [{'dept': 'Computer Science','status': true}, + {'dept': 'science','status': false}, + {'dept': 'sports','status': false}, + {'dept': 'sdlkf','status': false}], + 'designation': [{'post': 'director','status': false}, + {'post': 'principal','status': false}, + {'post': 'teaching','status': true}, + {'post': 'nonteaching','status': false}]}]; $scope.report = { - selectedUser:null -} - - -$scope.pagingExample = { - exData:null, - limit:0, - currentPage:0, - total:0, - pages:[] -}; + selectedUser: null + } + + $scope.pagingExample = { + exData: null, + limit: 0, + currentPage: 0, + total: 0, + pages: [] + }; -var ctrl = this, -initialLoaded=false; + var ctrl = this, + initialLoaded = false; -$scope.loadData = function(n){ + $scope.loadData = function(n) { //don't load if n==0 or n>pages - if($scope.pagingExample.pages.length){ - if(n==0 || n > $scope.pagingExample.pages.length) return; + if ($scope.pagingExample.pages.length) { + if (n == 0 || n > $scope.pagingExample.pages.length) return; }; - + //load data - $http.get('data/data-page'+ n +'.json').then(function(response){ - $scope.pagingExample.exData = response.data.data; - $scope.pagingExample.limit = response.data.limit; - $scope.pagingExample.currentPage = response.data.page; - $scope.pagingExample.total = response.data.total; - - //calculate pages just once - after first loading - if(!initialLoaded){ - ctrl.getTotalPages(); - initialLoaded = true; - }; + $http.get('data/data-page' + n + '.json').then(function(response) { + $scope.pagingExample.exData = response.data.data; + $scope.pagingExample.limit = response.data.limit; + $scope.pagingExample.currentPage = response.data.page; + $scope.pagingExample.total = response.data.total; + + //calculate pages just once - after first loading + if (!initialLoaded) { + ctrl.getTotalPages(); + initialLoaded = true; + }; }); -}; + }; -// load first page -$scope.loadData($scope.pagingExample.currentPage+1); + // load first page + $scope.loadData($scope.pagingExample.currentPage + 1); -// calculate totals and return page range ([1,2,3]) -this.getTotalPages = function(){ + // calculate totals and return page range ([1,2,3]) + this.getTotalPages = function() { var count = Math.round($scope.pagingExample.total / $scope.pagingExample.limit); for (var i = 0; i < count; i++) { - $scope.pagingExample.pages.push(i); + $scope.pagingExample.pages.push(i); }; -}; + }; - $scope.getTotalBalance = function(data){ - if(!data || !data.length) return; + $scope.getTotalBalance = function(data) { + if (!data || !data.length) return; var totalNumber = 0; - for(var i=0; i - + - - jTable Example - - - - - - + + jTable Example + + + + + + - - @@ -42,96 +41,67 @@ -
-

Row custom

- - - - - - - - - - - - -
{{::item.name}}
- {{::item.eyeColor}} -
{{::item.age}}{{::item.balance}}{{::item.company}}{{::item.address}}{{::item.favoriteFruit}}
-

Patel

--- - - - - - - - - - -
{{item.name.firstName}} {{item.name.middleName}} {{item.name.lastName}} - {{items.dept}} - - {{designation.status}} -
-
- - - - - - - - - - - - - - - - - - - - - - -
NameEye colorAgeBalanceCompanyFavorite Fruit
{{::item.name}}
- {{::item.eyeColor}} -
{{::item.age}}{{::item.balance}}{{::item.balance}}{{::item.favoriteFruit}}
- -

Excell selection

- -
- -
+ + diff --git a/src/js/contenteditableDirective.js b/src/js/contenteditableDirective.js index 8d43c26..8178b87 100644 --- a/src/js/contenteditableDirective.js +++ b/src/js/contenteditableDirective.js @@ -1,21 +1,24 @@ -"use strict" -angular.module('objectTable',[]).directive("contenteditable", function() { - return { - restrict: "A", - require: "ngModel", - link: function(scope, element, attrs, ngModel) { +'use strict' +angular.module('objectTable',[]).directive('contenteditable', function() { + return { + restrict: 'A', + require: ['ngModel', '^objectTable'], + link: function(scope, element, attrs, ctrls) { + var ngModel = ctrls[0], objectTableCtrl = ctrls[1]; + ngModel.$render = function() { + element.html(ngModel.$viewValue || ''); + }; - function read() { - ngModel.$setViewValue(element.html()); - }; - - ngModel.$render = function() { - element.html(ngModel.$viewValue || ""); - }; - - element.bind("change blur", function() { - scope.$apply(read); - }); - } - }; - }) \ No newline at end of file + element.bind('change blur', function() { + var oldValue = ngModel.$viewValue.toString(); + var newValue = element.text(); + if (oldValue !== newValue) { + scope.$apply(function() { + ngModel.$setViewValue(newValue); + }); + if (!!objectTableCtrl.onEdit && typeof objectTableCtrl.onEdit === 'function') objectTableCtrl.onEdit({$oldValue: oldValue, $newValue: newValue}); + } + }) + } + } +}); diff --git a/src/js/directive.js b/src/js/directive.js index b227b61..4b79b27 100644 --- a/src/js/directive.js +++ b/src/js/directive.js @@ -1,94 +1,93 @@ -"use strict" -angular.module('objectTable').directive('objectTable', ['$compile','$interpolate',function ($compile,$interpolate) { - return { - restrict: 'A', - replace:true, - templateUrl: '/src/templates/common.html', - controller:'objectTableCtrl', - controllerAs:"ctrl", - transclude: true, - scope:{ - data:"=", - display:"=?", - resize:"=?", - paging:"=?", - fromUrl:"@", - //search:"@?", - //headers:"@", - //fields:"@", - sortingType: "@?sorting", - editable:"=?", - select:"@?", - selectedModel:"=?", - dragColumns:"=?" +'use strict' +angular.module('objectTable').directive('objectTable', ['$compile','$interpolate',function($compile, $interpolate) { + return { + restrict: 'A', + replace: true, + templateUrl: '/src/templates/common.html', + controller: 'objectTableCtrl', + controllerAs: 'ctrl', + transclude: true, + scope: { + data: '=', + display: '=?', + resize: '=?', + paging: '=?', + fromUrl: '@', + //search:"@?", + //headers:"@", + //fields:"@", + sortingType: '@?sorting', + editable: '&?', + onEdit: '&?', + select: '@?', + selectedModel: '=?', + dragColumns: '=?' - }, - compile:function( tElement, tAttributes) { + }, + compile: function(tElement, tAttributes) { - //collect filters - var rowFilter = "", - pagingFilter = ""; + //collect filters + var rowFilter = '', + pagingFilter = ''; - // additional user filters - if(!!tAttributes.addFilter){ - rowFilter += tAttributes.addFilter; - } + // additional user filters + if (!!tAttributes.addFilter) { + rowFilter += tAttributes.addFilter; + } - //If SORTING allowed - if(tAttributes.sorting!=="false"){ - rowFilter += "| orderBy:sortingArray"; - } + //If SORTING allowed + if (tAttributes.sorting !== 'false') { + rowFilter += '| orderBy:sortingArray'; + } - // add 'allow-drag' attribute to header is just cistom tbody present - if(tAttributes.dragColumns){ - tElement.find('th').attr('allow-drag',''); - } + // add 'allow-drag' attribute to header is just cistom tbody present + if (tAttributes.dragColumns) { + tElement.find('th').attr('allow-drag',''); + } - //If SEARCH allowed - if(tAttributes.search =="separate"){ - tAttributes.fields.split(',').forEach(function(item,index){ - rowFilter += "| filter:{'" + item.trim() + "':columnSearch['" + item + "']}"; - }); + //If SEARCH allowed + if (tAttributes.search === 'separate') { + tAttributes.fields.split(',').forEach(function(item, index) { + rowFilter += '| filter:{\'' + item.trim() + '\':columnSearch[\'' + item + '\']}'; + }); + } else if (typeof(tAttributes.search) === 'undefined' || tAttributes.search === 'true') { + rowFilter += '| filter:globalSearch'; + } - }else if(typeof(tAttributes.search)=='undefined' || tAttributes.search=="true"){ - rowFilter += "| filter:globalSearch"; - } + //pagingFilter = rowFilter; + pagingFilter += ' | offset: currentPage:display |limitTo: display'; - //pagingFilter = rowFilter; - pagingFilter += " | offset: currentPage:display |limitTo: display"; + tElement[0].querySelector('#rowTr').setAttribute('ng-repeat','item in $parent.$filtered = (data' + rowFilter + ')' + pagingFilter); + //add paging + tElement.find('paging').attr('count','$filtered.length'); - tElement[0].querySelector("#rowTr").setAttribute("ng-repeat","item in $parent.$filtered = (data" + rowFilter +")"+ pagingFilter); - //add paging - tElement.find("paging").attr("count","$filtered.length"); + return function preLink(scope, element, attrs, ctrl, transclude) { + ctrl._init(); + transclude(scope, function(clone, innerScope) { + scope.$owner = innerScope.$parent; + for (var key in clone) { + if (clone.hasOwnProperty(key)) { + switch (clone[key].tagName) { + case 'THEAD': + ctrl._addHeaderPattern(clone[key]); + break; + case 'TBODY': + scope.findBody = true; + ctrl._addRowPattern(clone[key],rowFilter,pagingFilter); + break; + case 'TFOOT': + ctrl._addFooterPattern(clone[key]); + break; + } + } + } + }); - return function preLink(scope, element, attrs, ctrl, transclude) { - ctrl._init(); - var ii=0; - transclude(scope, function(clone, innerScope) { - scope.$owner = innerScope.$parent; - for(var key in clone){ - if(clone.hasOwnProperty(key)){ - switch (clone[key].tagName) { - case 'THEAD': - ctrl._addHeaderPattern(clone[key]); - break; - case 'TBODY': - scope.findBody = true; - ctrl._addRowPattern(clone[key],rowFilter,pagingFilter); - break; - case 'TFOOT': - ctrl._addFooterPattern(clone[key]); - break; - } - } - } - }); + }; //[END transclude] - }; //[END transclude] + }, - }, - - }; + }; }]); diff --git a/src/js/objectTableCtrl.js b/src/js/objectTableCtrl.js index 629890d..52b6ddf 100644 --- a/src/js/objectTableCtrl.js +++ b/src/js/objectTableCtrl.js @@ -1,179 +1,185 @@ angular.module('objectTable').controller('objectTableCtrl', ['$scope', '$timeout','$element', '$attrs','$http', '$compile', '$controller', 'objectTableUtilService', function angTableCtrl($scope, $timeout, $element, $attrs, $http, $compile, $controller, Util) { - $controller('objectTableSortingCtrl', {$scope: $scope}); - var ctrl = this; - - this._init = function(){ - $scope.headers = []; - $scope.fields = []; - $scope.display = $scope.display || 5; - $scope.paging = angular.isDefined($scope.paging) ? $scope.paging : true; - $scope.sortingType = $scope.sortingType || "simple"; - $scope.currentPage = 0; - $scope.customHeader = false; - - if($attrs.search =="separate"){ - $scope.search = "separate"; - $scope.columnSearch = []; - - /* ## after changing search model - clear currentPage ##*/ - }else{ - /* 'separate' or 'true' or 'false '*/ - $scope.search = typeof($attrs.search)==='undefined' || $attrs.search==="true"; - } - - /* GET HEADERS */ - $scope.headers = Util.getArrayFromParams($attrs.headers,'headers'); - - /* GET FIELDS */ - $scope.fields = Util.getArrayFromParams($attrs.fields,'fields'); - - //LOAD FROM EXTERNAL URL - if(!!$attrs.fromUrl){ - this._loadExternalData($attrs.fromUrl); - } - - //reinitialize selected model - $scope.selectedModel = $scope.select==="multiply"? []:{}; - - }; - - this._loadExternalData = function(url){ - $scope.dataIsLoading= true; - $http.get(url).then(function(response){ - $scope.data = response.data; - $scope.dataIsLoading = false; - }); - - }; - - this._addHeaderPattern = function(node){ - $scope.customHeader = true; - //add Index to drag - Array.prototype.forEach.call(node.querySelectorAll("[allow-drag]"), function(th,index){ - th.setAttribute('index',index); - }); - node.removeAttribute('ng-non-bindable'); - $element.find("table").prepend(node); - }; - - this._addFooterPattern = function(node){ - $element.find("table").prepend(node); - }; - - this._addRowPattern = function(node, rowFilter, paggingFilter){ - this._checkEditableContent(node); - this._addRepeatToRow(node, rowFilter, paggingFilter); - node.removeAttribute('ng-non-bindable'); - //compile TBODY - $element.find("table").append(node.outerHTML); - this.bodyTemplate = node.innerHTML; - $compile($element.find("tbody"))($scope); - }; - - this._addRepeatToRow = function(node, rowFilter, paggingFilter){ - var tr = angular.element(node).find("tr"); - - tr.attr("ng-repeat","item in $filtered = (data" + rowFilter + ")" + paggingFilter); - if(!tr.attr("ng-click")){ - tr.attr("ng-click","setSelected(item)"); - } - - tr.attr("ng-class","{'selected-row':ifSelected(item)}"); - }; - - this._checkEditableContent = function(node){ - var innerModel,findModelRegex=/\{\{:*:*(.*?)\}\}/g; - Array.prototype.forEach.call(node.querySelectorAll("[editable]"), function(td){ - innerModel = td.innerHTML.replace(findModelRegex,'$1'); - td.innerHTML = "
{{" + innerModel + "}}
"; - }); - }; - - this.setCurrentPage = function(_currentPage){ - $scope.currentPage = _currentPage; - }; - - $scope.setSelected = function(item){ - if( $scope.select==="multiply"){ - if(!ctrl._containsInSelectArray(item)){ - $scope.selectedModel.push(item); - }else{ - $scope.selectedModel.splice($scope.selectedModel.indexOf(item),1); - } - }else{ - $scope.selectedModel = item; - } - }; - - this._containsInSelectArray = function(obj) { - if($scope.selectedModel.length) + $controller('objectTableSortingCtrl', {$scope: $scope}); + var ctrl = this; + + this._init = function() { + $scope.headers = []; + $scope.fields = []; + $scope.display = $scope.display || 5; + $scope.paging = angular.isDefined($scope.paging) ? $scope.paging : true; + $scope.sortingType = $scope.sortingType || 'simple'; + $scope.currentPage = 0; + $scope.customHeader = false; + + if ($attrs.search == 'separate') { + $scope.search = 'separate'; + $scope.columnSearch = []; + + /* ## after changing search model - clear currentPage ##*/ + } else { + /* 'separate' or 'true' or 'false '*/ + $scope.search = typeof($attrs.search) === 'undefined' || $attrs.search === 'true'; + } + + /* GET HEADERS */ + $scope.headers = Util.getArrayFromParams($attrs.headers,'headers'); + + /* GET FIELDS */ + $scope.fields = Util.getArrayFromParams($attrs.fields,'fields'); + + //LOAD FROM EXTERNAL URL + if (!!$attrs.fromUrl) { + this._loadExternalData($attrs.fromUrl); + } + + if (!!$scope.onEdit) { + this.onEdit = $scope.onEdit; + } + + //reinitialize selected model + $scope.selectedModel = $scope.select === 'multiply' ? [] : {}; + + }; + + this.onEdit = $scope.onEdit; + + this._loadExternalData = function(url) { + $scope.dataIsLoading = true; + $http.get(url).then(function(response) { + $scope.data = response.data; + $scope.dataIsLoading = false; + }); + + }; + + this._addHeaderPattern = function(node) { + $scope.customHeader = true; + //add Index to drag + Array.prototype.forEach.call(node.querySelectorAll('[allow-drag]'), function(th, index) { + th.setAttribute('index',index); + }); + node.removeAttribute('ng-non-bindable'); + $element.find('table').prepend(node); + }; + + this._addFooterPattern = function(node) { + $element.find('table').prepend(node); + }; + + this._addRowPattern = function(node, rowFilter, paggingFilter) { + this._checkEditableContent(node); + this._addRepeatToRow(node, rowFilter, paggingFilter); + node.removeAttribute('ng-non-bindable'); + //compile TBODY + $element.find('table').append(node.outerHTML); + this.bodyTemplate = node.innerHTML; + $compile($element.find('tbody'))($scope); + }; + + this._addRepeatToRow = function(node, rowFilter, paggingFilter) { + var tr = angular.element(node).find('tr'); + + tr.attr('ng-repeat','item in $filtered = (data' + rowFilter + ')' + paggingFilter); + if (!tr.attr('ng-click')) { + tr.attr('ng-click','setSelected(item)'); + } + + tr.attr('ng-class','{\'selected-row\':ifSelected(item)}'); + }; + + this._checkEditableContent = function(node) { + var innerModel, findModelRegex = /\{\{:*:*(.*?)\}\}/g; + Array.prototype.forEach.call(node.querySelectorAll('[editable]'), function(td) { + innerModel = td.innerHTML.replace(findModelRegex,'$1'); + td.innerHTML = '
{{' + innerModel + '}}
'; + }); + }; + + this.setCurrentPage = function(_currentPage) { + $scope.currentPage = _currentPage; + }; + + $scope.setSelected = function(item) { + if ($scope.select === 'multiply') { + if (!ctrl._containsInSelectArray(item)) { + $scope.selectedModel.push(item); + }else { + $scope.selectedModel.splice($scope.selectedModel.indexOf(item),1); + } + }else { + $scope.selectedModel = item; + } + }; + + this._containsInSelectArray = function(obj) { + if ($scope.selectedModel.length) return $scope.selectedModel.filter(function(listItem) { - return angular.equals(listItem, obj); + return angular.equals(listItem, obj); }).length > 0; - }; - - $scope.ifSelected = function(item){ - - if( !!$scope.selectedModel && $scope.select==="multiply" ){ - return ctrl._containsInSelectArray(item); - }else{ - return item.$$hashKey==$scope.selectedModel.$$hashKey; - } - }; - - /* Drag-n-Drop columns exchange*/ - this.changeColumnsOrder = function(from,to){ - $scope.$apply(function() { - $scope.fields.swap(from,to); - $scope.headers.swap(from,to); - if(!!$scope.columnSearch){ - $scope.columnSearch.swap(from,to); - } - if(!!ctrl.bodyTemplate){ - var tds = angular.element(ctrl.bodyTemplate).children(), - html="", - tr = document.createElement('tr'), - tbody = document.createElement('tbody'), - attributes = $element.find("tbody").find('tr')[0].attributes; - Array.prototype.swap.apply(tds,[from,to]); - - [].forEach.call(attributes, function(attr,index) { - tr.setAttribute(attr.name, attr.value); - }); - - for (var i = 0,length=tds.length; i