-
-
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"); | |
}; | |
}); |
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();
}
});
}
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:
scope.$watch(attr.ngModel, function () { update(); });
is a bit redondant asupdate
is already a function. On the other part, but this is probably a matter of gut, I'm not a big fan of definingfunction
asvar
.Also, it'd be cool to include a note about the recommended css for those not coming from thomseddon's gist.