Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(input): Sizes textareas properly when the container is shown
Browse files Browse the repository at this point in the history
Added an optional md-detect-hidden attribute for textareas inside of
md-input-containers. This will check on every digest cycle whether the
element was hidden and is now shown, and will auto-size the textarea
properly.

Fixes #1202. Closes #4726.
  • Loading branch information
Michael Chen authored and ThomasBurleson committed Oct 6, 2015
1 parent 8367118 commit 16f92ec
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 1 deletion.
26 changes: 26 additions & 0 deletions src/components/input/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ function labelDirective() {
* @param {string=} placeholder An alternative approach to using aria-label when the label is not
* PRESENT. The placeholder text is copied to the aria-label attribute.
* @param md-no-autogrow {boolean=} When present, textareas will not grow automatically.
* @param md-detect-hidden {boolean=} When present, textareas will be sized properly when they are revealed after being hidden. This is off by default for performance reasons because it guarantees a reflow every digest cycle.
*
* @usage
* <hljs lang="html">
Expand Down Expand Up @@ -341,6 +342,31 @@ function inputTextareaDirective($mdUtil, $window, $mdAria) {
var height = node.offsetHeight + line;
node.style.height = height + 'px';
}

// Attach a watcher to detect when the textarea gets shown.
if (angular.isDefined(element.attr('md-detect-hidden'))) {

var handleHiddenChange = function() {
var wasHidden = false;

return function() {
var isHidden = node.offsetHeight === 0;

if (isHidden === false && wasHidden === true) {
growTextarea();
}

wasHidden = isHidden;
};
}();

// Check every digest cycle whether the visibility of the textarea has changed.
// Queue up to run after the digest cycle is complete.
scope.$watch(function() {
$mdUtil.nextTick(handleHiddenChange, false);
return true;
});
}
}
}
}
Expand Down
79 changes: 78 additions & 1 deletion src/components/input/input.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('md-input-container directive', function() {
var $compile, pageScope;
var $rootScope, $compile, $timeout, pageScope;

beforeEach(module('ngAria', 'material.components.input'));

Expand All @@ -9,6 +9,12 @@ describe('md-input-container directive', function() {
pageScope = $injector.get('$rootScope').$new();
}));

beforeEach(inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
$timeout = $injector.get('$timeout');
}));

function setup(attrs, isForm) {
var container;

Expand Down Expand Up @@ -258,4 +264,75 @@ describe('md-input-container directive', function() {

expect(element.hasClass('md-input-has-value')).toBe(true);
});

describe('Textarea auto-sizing', function() {
var ngElement, element, ngTextarea, textarea, scope, parentElement;

function createAndAppendElement(attrs) {
scope = $rootScope.$new();

attrs = attrs || '';
var template =
'<div ng-hide="parentHidden">' +
'<md-input-container>' +
'<label>Biography</label>' +
'<textarea ' + attrs + '>Single line</textarea>' +
'</md-input-container>' +
'</div>';
parentElement = $compile(template)(scope);
ngElement = parentElement.find('md-input-container');
element = ngElement[0];
ngTextarea = ngElement.find('textarea');
textarea = ngTextarea[0];
document.body.appendChild(parentElement[0]);
}

afterEach(function() {
document.body.removeChild(parentElement[0]);
});

it('should auto-size the textarea as the user types', function() {
createAndAppendElement();
var oldHeight = textarea.offsetHeight;
ngTextarea.val('Multiple\nlines\nof\ntext');
ngTextarea.triggerHandler('input');
scope.$apply();
$timeout.flush();
var newHeight = textarea.offsetHeight;
expect(newHeight).toBeGreaterThan(oldHeight);
});

it('should not auto-size if md-no-autogrow is present', function() {
createAndAppendElement('md-no-autogrow');
var oldHeight = textarea.offsetHeight;
ngTextarea.val('Multiple\nlines\nof\ntext');
ngTextarea.triggerHandler('input');
scope.$apply();
$timeout.flush();
var newHeight = textarea.offsetHeight;
expect(newHeight).toEqual(oldHeight);
});

it('should auto-size when revealed if md-detect-hidden is present', function() {
createAndAppendElement('md-detect-hidden');

var oldHeight = textarea.offsetHeight;

scope.parentHidden = true;
ngTextarea.val('Multiple\nlines\nof\ntext');
ngTextarea.triggerHandler('input');
scope.$apply();
$timeout.flush();

// Textarea should still be hidden.
expect(textarea.offsetHeight).toBe(0);

scope.parentHidden = false;
scope.$apply();

$timeout.flush();
var newHeight = textarea.offsetHeight;
expect(textarea.offsetHeight).toBeGreaterThan(oldHeight);
});
});
});

0 comments on commit 16f92ec

Please sign in to comment.