-
Notifications
You must be signed in to change notification settings - Fork 3.4k
textarea: long textarea causes scroll jumping issues #3070
Comments
This is happening because of this line in growTextarea(): node.style.height = "auto"; This handles the shrinking (and also expanding, but as far as I can see it is really here for shrinking) of the textarea by setting the height back to auto. I took a stab at a fix for this today as it was interfering with a part of my project, and perhaps this will work for anyone looking for a temp fix... I have only tested this on webkit. In src/components/input/input.js: Add the variable minTextAreaHeight to setupTextarea(), we will use this for saving the initial height to limit shrinking. function setupTextarea() {
var node = element[0];
var onChangeTextarea = $mdUtil.debounce(growTextarea, 1);
var minTextareaHeight;
... Adjust the scroll event listener to call the same textarea change function. Remove onScroll as it will no longer be needed. element.on('scroll', onChangeTextarea); growTextarea becomes: function growTextarea() {
node.scrollTop = 0;
var height = getHeight();
if (height) node.style.height = height + 'px';
} getHeight becomes: function getHeight() {
var line = node.scrollHeight - node.offsetHeight;
var height = Number(window.getComputedStyle(node)["height"].replace("px", ""));
var lineHeight = Number(window.getComputedStyle(node)["line-height"].replace("px", ""));
var newHeight = height + (line >= 0 ? line : lineHeight*-1);
//cache the initial height that can be adjusted using 'rows'
if (!minTextareaHeight) {
minTextareaHeight = height
}
if (newHeight <= minTextareaHeight) {
return minTextareaHeight;
} else {
return newHeight;
}
} As I mentioned, I am sure this is a better way of doing this. |
Also, this is a dupe of #3024 |
@mckenzielong, I applied the fix you proposed for my application and textarea behaves fine now. Thank you! |
This also happens when the textarea is in a tab container. When you don't have md-dynamic-height on, the jumping starts much sooner. When you do have md-dynamic-height applied to the tabs, then the scrollbar doesn't jump until it reaches the bottom of the mdcontent area. I havent tried @mckenzielong's fix yet, but I'll update if it works for me. |
@mckenzielong Your fixed worked for me, even in a tab container. There is still a slight jump when a newline is added (press enter key), but as soon as you start typing, the textarea focuses on the correct line, without jumps. I think that is reasonable, and isn't that annoying. Another thing is if you select the content of the textarea and press the backspace, the content is deleted, including the newlines, but the textarea stays the same size. When you start typing again the content area shrinks everytime you hit a key, but there wasn't actually anything in the content area... This didn't happen with the old text area, but I don't find it to be too much of an issue. here is a screenrecording of the issue This isn't too much of an issue, and the textarea is a ton better after this fix, so I think this fix outweighs the minor new issues. If this works in all of the use cases you can think of, and hasn't broken anything else, then I suggest you submit a pull request. I'm sure the developers would appreciate it, since they have 700+ open issues right now. |
👍 have the same issue in my project as well. Looking forward to the official fix. |
Same problem here. @mckenzielong This fix worked, thank you! Hope this fix makes it into the repo soon. |
Here is a different (better?) fix based on how iron-autogrow-textarea works. This gets rid of the case when the textarea doesn't collapse based on a large delete (as @WhiteAbeLincoln demonstrated above.) Again, I have only tested this on webkit. First add the following css: md-input-container .md-textarea-container {
display: inline-block;
position: relative;
padding:0;
border-bottom: none;
}
md-input-container .md-textarea-container textarea {
height: 100%;
position: absolute;
width: 100%;
padding:0;
}
md-input-container .md-textarea-container .md-textarea-mirror {
padding-top: 2px;
padding-left: 2px;
padding-right: 2px;
width: 100%;
min-height: 56px;
visibility: hidden;
word-wrap: break-word;
} Next, in input.js, make the following changes: element.on('scroll', onChangeTextarea); Adjust setupTextarea() function setupTextarea() {
var mirror = angular.element('<div class="md-textarea-mirror"></div>');
var onChangeTextarea = $mdUtil.debounce(growTextarea, 1);
var minTextareaHeight;
element.wrap('<div class="md-textarea-container md-input"></div>');
element.after(mirror);
... Adjust growTextarea() function growTextarea() {
var rows = element.prop('rows');
//see https://github.com/PolymerElements/iron-autogrow-textarea/blob/master/iron-autogrow-textarea.html
var tokens = element.val().replace(/&/gm, '&').replace(/"/gm, '"')
.replace(/'/gm, ''').replace(/</gm, '<').replace(/>/gm, '>').split('\n');
while (rows > tokens.length) {
tokens.push('');
}
mirror.html(tokens.join('<br>') + ' ');
} |
This issue didn't get closed, but I assume this should be addressed and fixed by commit: Whether new bugs appear is likely a separate story. |
Please reopen. The issue still present in demo, same root cause: node.style.height = "auto"; |
Reopened. |
Just a small fix to @mckenzielong getHeight function. so that the text area will collapse to the right size after a massive deletion: function getHeight() {
var line = node.scrollHeight - node.offsetHeight;
var height = Number(window.getComputedStyle(node)["height"].replace("px", ""));
var lineHeight = Number(window.getComputedStyle(node)["line-height"].replace("px", ""));
var newHeight = node.value.split('\n').length * lineHeight; //This Will set the new height to the number of lines in the Value of node
//cache the initial height that can be adjusted using 'rows'
if (!minTextareaHeight) {
minTextareaHeight = height;
}
if (newHeight <= minTextareaHeight) {
return minTextareaHeight;
} else {
return newHeight;
}
} Hope this helps |
@ricardosaracino Your IE11 hack unfortunately doesn't work for me. :/ We also tried event.stopPropagation() on keydown and keyup whithout success. We had the same issue with scroll jumping in long textareas when clicking inside the textarea in IE11. We solved that problem with event.stopPropagation() on the click event. |
The issue still exists |
Just FYI, this likely won't be fixed unless someone from the community comes up with a fix and opens a PR for it. I will be happy to help support, verify the fix, and work to get it merged, but I will be focused on P1-P2 issues for the next few months. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I just tried to reproduce this on iOS (iPad OS 14.0) using Safari 14, but I was not able to do so on https://material.angularjs.org/1.2.0/demo/input#basic-usage. If anyone can provide a reproduction demo and steps for iOS, please let me know. I'll try to take a look on Windows soon. |
I tried to reproduce this on macOS using Firefox 80.0.1 with an updated CodePen but I was not able to reproduce it. I had to fix up the CodePen a bit to get it to render properly since the way that |
Just want to chip in here, not related to angular material, but a native solution to this scrolling issue with auto-height trigger to do a calculation. What I've done, is before setting the height to auto for the textarea, have another element next to it take over the current height, and when the new height is calculated, apply this also to that other element. This way, the space stays reserved and the page won't notice a height-drop when setting the textarea to auto. You could see this as some sort of memoization pattern for the height :) Pseudo code below: <textarea id="my-textarea" />
<div id="my-textarea-stub" /> calculateTextareaHeight() {
const textarea = document.querySelector('#my-textarea');
const textareaStub = document.querySelector('#my-textarea-stub');
// store the reserved height in our stub element before setting "auto"
textareaStub.style.height = textarea.style.height;
textarea.style.height = 'auto';
// some real calculations here...
let someCalculatedHeight = 2000;
// reset the textarea height, and after that, reset the stub height
textarea.style.height = `${someCalculatedHeight}px`;
textareaStub.style.height = textarea.style.height; |
Seeing this issue as well in Catalina / Safari 14 using an angular directive to manually change the textarea height. |
Place a
textarea
inside a content pane (ie.md-content
ormd-dialog-content
). As one starts to create a very long message that span many rows and causes overflow to occur and scrollbars to show, one will notice that when you type anything, the scrollbar will jump to the top of the overflow content pane. If one tries to type text, the screen will jump down to the text (which is what the browser does automatically) but then the screen is immediately jumped back up to the top of the scrolling content.The result is that you cannot see what you're typing once you get to a very long text message. Additionally, the scroll jumping causes headaches. Somewhere along the line, I think someone is doing some sort of scroll reset or setting the scrollTop.
You can duplicate this using the Demo on ngmaterial website.
https://material.angularjs.org/latest/#/demo/material.components.input
Simply keep creating new rows and making the overflown content type expand until it begins to jump.
The text was updated successfully, but these errors were encountered: