-
-
Save enapupe/2a59589168f33ca405d0 to your computer and use it in GitHub Desktop.
angular.module("myApp").directive("autoGrow", function(){ | |
return function(scope, element, attr){ | |
var update = function(){ | |
element.css("height", "auto"); | |
var height = element[0].scrollHeight; | |
if(height > 0){ | |
element.css("height", height + "px"); | |
} | |
}; | |
scope.$watch(attr.ngModel, function(){ | |
update(); | |
}); | |
attr.$set("ngTrim", "false"); | |
}; | |
}); |
Issues
- If the textarea is invisible it won't come with the automagic height because the scrollheight was zero on modelchange, unless the same model that populates de textarea makes it visible.
Wow, working even better than the shadow hack trick while being terribly simple. Do you actually use it on a large project? Seems to be well supported so I think I'll go with it! May I suggest the following:
return function (scope, element, attrs) {
function update () {
element.css("height", "auto");
var height = element[0].scrollHeight;
if (height > 0) element.css("height", height + "px");
}
scope.$watch(attrs.ngModel, update);
attrs.$set("ngTrim", "false");
}
scope.$watch(attr.ngModel, function () { update(); });
is a bit redondant as update
is already a function. On the other part, but this is probably a matter of gut, I'm not a big fan of defining function
as var
.
Also, it'd be cool to include a note about the recommended css for those not coming from thomseddon's gist.
Note: textarea won't resize if the ng-maxlength
is exceeded, which is probably a good thing. Actually the $watcher
on ngModel doesn't fire anymore.
Love it. My only wish is that the textarea
did not start out defaulting to two lines. Any idea how to get it to start with a single line, then expand by a line at a time as it does? I guess scrollHeight
is doing that?
Here it is in CoffeeScript, injected into a larger project:
autoGrow = ->
(scope, element, attrs) ->
update = ->
element.css 'height', 'auto'
height = element[0].scrollHeight
element.css 'height', height + 'px' if height > 0
scope.$watch attrs.ngModel, update
attrs.$set 'ngTrim', 'false'
# Register
App.Directives.directive 'autoGrow', autoGrow
Fixed for my purposes, though still curious if there might be a more elegant way to somehow control the children element sizes instead:
autoGrow = ->
(scope, element, attrs) ->
update = ->
if element[0].scrollWidth > element.outerWidth isBreaking = true else isBreaking = false
element.css 'height', 'auto' if isBreaking
height = element[0].scrollHeight
element.css 'height', height + 'px' if height > 0
scope.$watch attrs.ngModel, update
attrs.$set 'ngTrim', 'false'
# Register
App.Directives.directive 'autoGrow', autoGrow
@kimardenmiller can I use your code in my project ?
if I can convert your coffee code to native js code 😃
I have written my version with little changes
angular.module('mayApp')
.directive('autogrow', function () {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
// hidding the scroll of textarea
element.css('overflow', 'hidden');
var update = function(){
element.css("height", "auto");
var height = element[0].scrollHeight;
if(height > 0){
element.css("height", height + "px");
}
};
scope.$watch(attrs.ngModel, function(){
update();
});
attrs.$set("ngTrim", "false");
}
};
});
on view layer
<textarea autogrow class="form-control" rows="10" placeholder="Enter ..." ng-model="content.body" ng-maxlength="16777215" ng-minlength="10" required name="content"></textarea>
Thanks guys! Works perfect! There does however seem to be an issue with Chrome (Version 46.0.2490.80 (64-bit) on Mac). Setting the element height twice every keystroke (first to auto, then to the desired height) causes a slight but annoying delay while typing. Any suggestions to solve that?
Thanks a lot.
thank you! It works for me on Chrome 57 and IOS 9.
Thank you ! works for me too.
@muratsplat
Excellent Work! Thanks!
In case someone uses debounced model updates - this will just work with a timeout, which is not very nice, so i changed the code a bit to also listen to the input event:
angular.module('myApp').directive('autogrow', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
// hide scroll of textarea
element.css('overflow', 'hidden');
var autogrow = function () {
element.css('height', 'auto');
var height = element[0].scrollHeight;
if(height > 0){
element.css('height', height + 'px');
}
};
// using 'input' event on element, because of debounced model update
element.on('input', autogrow);
// need this too, for initialize
scope.$watch(attrs.ngModel, autogrow);
}
};
});
@lpsBetty
Your trick of binding input
event is great! Thanks.
PS:
I was implementing autogrowing
textarea in ionic 1
modal template while I should consider a delay effect of modal opening. So I added a modal.shown
watcher.
angular.module('myApp').directive('autogrow', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
// hide scroll of textarea
element.css('overflow', 'hidden');
var autogrow = function () {
element.css('height', 'auto');
var height = element[0].scrollHeight;
if(height > 0){
element.css('height', height + 'px');
}
};
// using 'input' event on element, because of debounced model update
element.on('input', autogrow);
// need this too, for initialize
scope.$watch(attrs.ngModel, autogrow);
/////////////////////////////////////////////////
// apply after modal is shown <- ADD HERE
scope.$on('modal.shown', autogrow);
}
};
});
Hope this might help someone.
in case textarea is not yet visible:
if(!element.is(':visible')) {
scope.$watch(function () { return element.is(':visible'); }, function (visible) {
if(visible) {
autogrow();
scope.$applyAsync();
}
});
}
ngTrim is set to false because otherwise angularjs trims newlines and spaces. That makes watch not being fired when you enter new lines/spaces..