From 5e7b44fcf5b76a176fdcb06f98276eca2bca58cf Mon Sep 17 00:00:00 2001 From: Jesus Rodriguez Date: Mon, 10 Mar 2014 16:35:32 +0100 Subject: [PATCH] refactor(datepicker): use ng-if to increase performance --- misc/test-lib/helpers.js | 3 + src/datepicker/datepicker.js | 20 +++--- src/datepicker/test/datepicker.spec.js | 95 ++++++++++++++++---------- template/datepicker/popup.html | 2 +- 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/misc/test-lib/helpers.js b/misc/test-lib/helpers.js index 4d9d606397..d822958e24 100644 --- a/misc/test-lib/helpers.js +++ b/misc/test-lib/helpers.js @@ -13,6 +13,9 @@ beforeEach(function() { var element = angular.element(this.actual); return element.hasClass('ng-hide') || element.css('display') == 'none'; + }, + toBeGone: function() { + return this.actual.length === 0; } }); }); diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js index 89498b85a5..3bf796eaac 100644 --- a/src/datepicker/datepicker.js +++ b/src/datepicker/datepicker.js @@ -451,19 +451,21 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar; + scope.popup = {}; + scope.getText = function( key ) { return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text']; }; attrs.$observe('datepickerPopup', function(value) { - dateFormat = value || datepickerPopupConfig.datepickerPopup; - ngModel.$render(); + dateFormat = value || datepickerPopupConfig.datepickerPopup; + ngModel.$render(); }); // popup element used to display calendar var popupEl = angular.element('
'); popupEl.attr({ - 'ng-model': 'date', + 'ng-model': 'popup.date', 'ng-change': 'dateSelection()' }); @@ -518,9 +520,9 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon // Inner change scope.dateSelection = function(dt) { if (angular.isDefined(dt)) { - scope.date = dt; + scope.popup.date = dt; } - ngModel.$setViewValue(scope.date); + ngModel.$setViewValue(scope.popup.date); ngModel.$render(); if ( closeOnDateSelection ) { @@ -531,7 +533,7 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon element.bind('input change keyup', function() { scope.$apply(function() { - scope.date = ngModel.$modelValue; + scope.popup.date = ngModel.$modelValue; }); }); @@ -539,7 +541,7 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon ngModel.$render = function() { var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : ''; element.val(date); - scope.date = parseDate( ngModel.$modelValue ); + scope.popup.date = parseDate( ngModel.$modelValue ); }; var documentClickBind = function(event) { @@ -603,7 +605,7 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon } scope.$on('$destroy', function() { - $popup.remove(); + $popup.next().remove(); element.unbind('keydown', keydown); $document.unbind('click', documentClickBind); }); @@ -624,4 +626,4 @@ function ($compile, $parse, $document, $position, dateFilter, datepickerPopupCon }); } }; -}); +}); \ No newline at end of file diff --git a/src/datepicker/test/datepicker.spec.js b/src/datepicker/test/datepicker.spec.js index cd4c5b8398..183a51b6ae 100644 --- a/src/datepicker/test/datepicker.spec.js +++ b/src/datepicker/test/datepicker.spec.js @@ -1102,7 +1102,7 @@ describe('datepicker directive', function () { })); it('does not to display datepicker initially', function() { - expect(dropdownEl).toBeHidden(); + expect(dropdownEl).toBeGone(); }); it('to display the correct value in input', function() { @@ -1111,18 +1111,20 @@ describe('datepicker directive', function () { }); describe('initially opened', function () { + var wrapElement; + beforeEach(inject(function(_$document_, _$sniffer_) { $document = _$document_; $sniffer = _$sniffer_; $rootScope.isopen = true; $rootScope.date = new Date('September 30, 2010 15:30:00'); - var wrapElement = $compile('
')($rootScope); + wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); it('datepicker is displayed', function() { - expect(dropdownEl).not.toBeHidden(); + expect(dropdownEl).not.toBeGone(); }); it('renders the calendar correctly', function() { @@ -1156,10 +1158,12 @@ describe('datepicker directive', function () { }); it('closes the dropdown when a day is clicked', function() { - expect(dropdownEl.css('display')).not.toBe('none'); + expect(dropdownEl).not.toBeGone(); clickOption(17); - expect(dropdownEl.css('display')).toBe('none'); + + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); }); it('updates the model & calendar when input value changes', function() { @@ -1181,10 +1185,12 @@ describe('datepicker directive', function () { }); it('closes when click outside of calendar', function() { - expect(dropdownEl).not.toBeHidden(); + expect(dropdownEl).not.toBeGone(); $document.find('body').click(); - expect(dropdownEl.css('display')).toBe('none'); + + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); }); it('sets `ng-invalid` for invalid input', function() { @@ -1219,25 +1225,27 @@ describe('datepicker directive', function () { }); it('returns to the input when ESC key is pressed in the popup and closes', function() { - expect(dropdownEl).not.toBeHidden(); + expect(dropdownEl).not.toBeGone(); dropdownEl.find('button').eq(0).focus(); expect(document.activeElement.tagName).toBe('BUTTON'); triggerKeyDown(dropdownEl, 'esc'); - expect(dropdownEl).toBeHidden(); + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); expect(document.activeElement.tagName).toBe('INPUT'); }); it('returns to the input when ESC key is pressed in the input and closes', function() { - expect(dropdownEl).not.toBeHidden(); + expect(dropdownEl).not.toBeGone(); dropdownEl.find('button').eq(0).focus(); expect(document.activeElement.tagName).toBe('BUTTON'); triggerKeyDown(inputEl, 'esc'); $rootScope.$digest(); - expect(dropdownEl).toBeHidden(); + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); expect(document.activeElement.tagName).toBe('INPUT'); }); }); @@ -1265,32 +1273,37 @@ describe('datepicker directive', function () { }); describe('toggles programatically by `open` attribute', function () { + var wrapElement; + beforeEach(inject(function() { $rootScope.open = true; - var wrapElement = $compile('
')($rootScope); + wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); it('to display initially', function() { - expect(dropdownEl.css('display')).not.toBe('none'); + expect(dropdownEl).not.toBeGone(); }); it('to close / open from scope variable', function() { - expect(dropdownEl.css('display')).not.toBe('none'); + expect(dropdownEl).not.toBeGone(); $rootScope.open = false; $rootScope.$digest(); - expect(dropdownEl.css('display')).toBe('none'); + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); $rootScope.open = true; $rootScope.$digest(); - expect(dropdownEl.css('display')).not.toBe('none'); + assignElements(wrapElement); + expect(dropdownEl).not.toBeGone(); }); }); describe('custom format', function () { beforeEach(inject(function() { - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); @@ -1315,7 +1328,8 @@ describe('datepicker directive', function () { describe('dynamic custom format', function () { beforeEach(inject(function() { $rootScope.format = 'dd-MMMM-yyyy'; - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); @@ -1366,16 +1380,18 @@ describe('datepicker directive', function () { } describe('', function () { + var wrapElement; + beforeEach(inject(function() { $rootScope.isopen = true; - var wrapElement = $compile('
')($rootScope); + wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); assignButtonBar(); })); it('should exist', function() { - expect(dropdownEl).not.toBeHidden(); + expect(dropdownEl).not.toBeGone(); expect(dropdownEl.find('li').length).toBe(2); }); @@ -1421,7 +1437,8 @@ describe('datepicker directive', function () { it('should have a button to close calendar', function() { buttons.eq(2).click(); - expect(dropdownEl).toBeHidden(); + assignElements(wrapElement); + expect(dropdownEl).toBeGone(); }); }); @@ -1429,7 +1446,8 @@ describe('datepicker directive', function () { it('should change text from attributes', function() { $rootScope.clearText = 'Null it!'; $rootScope.close = 'Close'; - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); assignButtonBar(); @@ -1441,7 +1459,8 @@ describe('datepicker directive', function () { it('should remove bar', function() { $rootScope.showBar = false; - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); expect(dropdownEl.find('li').length).toBe(1); @@ -1451,7 +1470,8 @@ describe('datepicker directive', function () { describe('`ng-change`', function() { beforeEach(inject(function() { $rootScope.changeHandler = jasmine.createSpy('changeHandler'); - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); assignButtonBar(); @@ -1496,7 +1516,8 @@ describe('datepicker directive', function () { beforeEach(inject(function() { $rootScope.changeHandler = jasmine.createSpy('changeHandler'); $rootScope.date = new Date(); - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); @@ -1524,10 +1545,10 @@ describe('datepicker directive', function () { it('should append to the body', function() { var $body = $document.find('body'), - bodyLength = $body.children().length, - elm = angular.element( - '
' - ); + bodyLength = $body.children().length, + elm = angular.element( + '
' + ); $compile(elm)($rootScope); $rootScope.$digest(); @@ -1536,11 +1557,11 @@ describe('datepicker directive', function () { }); it('should be removed on scope destroy', function() { var $body = $document.find('body'), - bodyLength = $body.children().length, - isolatedScope = $rootScope.$new(), - elm = angular.element( - '' - ); + bodyLength = $body.children().length, + isolatedScope = $rootScope.$new(), + elm = angular.element( + '' + ); $compile(elm)(isolatedScope); isolatedScope.$digest(); expect($body.children().length).toEqual(bodyLength + 1); @@ -1554,8 +1575,8 @@ describe('datepicker directive', function () { beforeEach(inject(function(datepickerConfig) { angular.extend(originalConfig, datepickerConfig); datepickerConfig.showWeeks = false; - - var wrapElement = $compile('
')($rootScope); + $rootScope.isopen = true; + var wrapElement = $compile('
')($rootScope); $rootScope.$digest(); assignElements(wrapElement); })); @@ -1667,4 +1688,4 @@ describe('datepicker directive', function () { expect(getTitle()).toBe('2013'); }); }); -}); +}); \ No newline at end of file diff --git a/template/datepicker/popup.html b/template/datepicker/popup.html index fd48f60663..320ae8455d 100644 --- a/template/datepicker/popup.html +++ b/template/datepicker/popup.html @@ -1,4 +1,4 @@ -