React How to Dynamically set offsetTop with height to a div - javascript

I am working on a dashboard part of a site and i am very new to reactjs.
I am trying fit everything on a screen so that the user does not have to scroll expect for the table, i hope the code below defines the situation better.
Here is my code:
componentDidMount() {
this.tableHeightOffset();
}
tableHeightOffset() {
var getOffset = this.containerLine.offsetTop;
this.setState({ getOffset });
}
render() {
var findTableHeight = this.state.getOffset;
const tableHeight = {
height: 'calc(100vh - ' + findTableHeight + 'px' + ')'
}
return (
<div className="table-responsive" style={tableHeight} ref={el => this.containerLine = el}>
)
}
How do i get the offset to change when the browser resize or there is a update on the site ?
Also I get the value on findTableHeight but it is not getting the offset from to the top of the window. I was suppose to get 161px of offsetTop but i am only getting 46px.

You could define a resize listener to the window, in order to calculate the new hight. This could be done in componentDidMount():
componentDidMount() {
window.addEventListener('resize', this.tableHeightOffset);
}
Don't forget to remove it before unmounting the component:
componentWillUnmount() {
window.removeEventListener('resize', this.tableHeightOffset);
}
Also offsetTop returns the offset from the parent. In order to find the offset relative to the document, check this article: Finding element's position relative to the document

Here you have api to listen for window size change https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event use it to dynamically change your offset.

Related

Reactjs, How to make scroll stay at current position when scrollable div extends

I'm trying to build a react Chat app and I was going to use the infinite scroll but it doesn't work the way I wanted it to. So I built one myself. I used useref to determine the height and if it reaches to the top it will add more chats. kinda like fb messenger's chat. The problem now is that when I add more chats, once it reaches the top, the scroll bar will continue to go up and not stick in place unlike how react-infinite scroll works.
May I know how I can go through this? Here is my code.
for the scroll:
const onScroll = () => {
if (topDiv.current) {
const { scrollTop, scrollHeight, clientHeight } = topDiv.current;
if(scrollTop === 0){
props.fecthMoreChat()
}
}
};
return(
<div id='scrollableDiv' ref={topDiv} onScroll={()=> onScroll()} style={{height:'100%', padding:'20px', display:'flex', flexDirection:'column', backgroundColor:'#efefef', overflowY:'scroll'}}>
{/* <div style={{visibility:'hidden'}} ref={topDiv}></div> */}
{currentChat.map((chat, index)=>{
return(
<div key={index} style={{textAlign:chat.sender===username?'right':'left'}}>
{chat.message}
</div>
)
})}
<div style={{visibility:'hidden'}} ref={botMsg}></div>
</div>
)
So the answer was actually pretty simple. I just took the current scroll height, saved it in a variable, then waited for the re-render and took the new scroll height. Basically, just subtract the old scroll height with the new scroll height and use that number to set scroll by using scrollTo(). Here is the code:
const onScroll = async () => {
if (chatDiv.current) {
const { scrollTop, scrollHeight, clientHeight } = chatDiv.current;
if(scrollTop === 0){
const pastScroll = scrollHeight
await props.fecthMoreChat()
const currentScroll = (await chatDiv.current.scrollHeight-pastScroll)
await chatDiv.current.scrollTo(0, currentScroll)
}
}
};

Detect bottom of the page on scroll using Vanilla JS in ReactJS

I am developing a React Application and want to Detect the bottom of the page on user scroll using Vanilla JS. I googled it out and found that below check works fine for most of the scenarios -
window.innerHeight + window.scrollY) >= document.body.offsetHeight
It works fine yes when in my react application I have not set height as 100vh in my App.css and index.css. But after setting the height as 100vh in both of them it does not.
I was consoling the values of above params without height as 100vh and below was the output on Galaxy S5 device -
window.innerHeight-> 640 window.scrollY -> 0 document.body.offsetHeight-> 265
Consoling the values of above params with height as 100vh and below was the output on Galaxy S5 device -
window.innerHeight-> 640 window.scrollY -> 0 document.body.offsetHeight-> 640
Below is handleScroll code:
handleScroll = () => {
const {
totalUsersCount, users, currentPage, fetchUsersList,
} = this.props;
console.log('window.innerHeight-> ', window.innerHeight, 'window.scrollY ->', window.scrollY,
'document.body.offsetHeight-> ', document.body.offsetHeight);
if (((window.innerHeight + window.scrollY) >= document.body.offsetHeight)) {
fetchUsersList(currentPage + 1);
}
};
How can I check for the bottom of page scroll, when the height is set as 100vh in Vanilla JS as I doing it in React.
When you set body height to 100vh, scrollHeight will remain the height of your window, whatever total content length actually is. scrollHeight doesn't actually return the height of your whole content (as you'd expect), but the visible space in which it can scroll.
What you want is not height css property value but max-height.
Try changing your css to
body {
/* height: 100vh; */
max-height: 100vh;
overflow: auto;
}
Also I don't think it is good to rely on window height for this, since you might later want to wrap your scrollable area (by adding a header for example), thus you'll loss some extra weight and might get errors in your calculation. If you have a reference (wether in React or with vanilla DOM parsing) to the element that handle the scroll (the one that contains your scrollbar), you can use the following test in your scroll function :
handleScroll = () => {
//...
if (target.scrollTop >= (target.scrollHeight - target.offsetHeight)) {
//... your stuff
}
}
Since for now body is your target, you can just :
handleScroll = () => {
//...
if (document.body.scrollTop >= (document.body.scrollHeight - document.body.offsetHeight)) {
//... your stuff
}
}
You need to use document.body.scrollHeight to get the actual height.
Reference : https://javascript.info/size-and-scroll-window#width-height-of-the-document
UPDATED:
for a specific element use any of the selectors and get its scroll height.
const el = document.getElementById('#id');
const scrollHeight = el.scrollHeight;

In vue, getting the size of an element is smaller in updated and nextTick than expected?

I'm trying to get the height of an element. If I try to get it too early, the height is 0px. I tried many different ways to get the height: in mounted(), in created(), on nextTick(), in updated(), and using window.eventListener, but I either get 0px or a size much smaller than I'd expect it to be (~117px). When I run the same command in the console on the page, I get the size I would expect it to be (~278px). If I resize the window, everything works fine. How can I get it to get the right height from the start?
In a vue file, I have:
mounted() {
this.$nextTick(() => {
this.vtextHeight = (document.getElementById(this.item.id).offsetHeight - document.getElementsByClassName("v-card__title")[0].offsetHeight) + 'px';
console.log("next tick", this.vtextHeight);
});
},
updated() {
this.vtextHeight = (document.getElementById(this.item.id).offsetHeight - document.getElementsByClassName("v-card__title")[0].offsetHeight) + 'px';
console.log("updated", this.vtextHeight);
},
created () {
var page = this;
var itemId = this.item.id;
window.addEventListener('load', () => {
page.vtextHeight = (document.getElementById(itemId).offsetHeight - document.getElementsByClassName("v-card__title")[0].offsetHeight) + 'px';
console.log("on load");
});
window.addEventListener('resize', () => {
page.vtextHeight = (document.getElementById(itemId).offsetHeight - document.getElementsByClassName("v-card__title")[0].offsetHeight) + 'px';
console.log("resize", page.vtextHeight);
});
}
On the page load:
"on load" never gets logged
"next tick 117px" and "updated 117px" gets logged, but that's smaller than I'd expect it to be
On a 1px window resize:
"resize 278px" and "updated 278px" gets logged, which is the value I'd expect it to be.
you can use vue specific ref approach to access DOM elements.
For example :
<div class="v-card__title" ref="vCard" :style="{'width': '100px', 'height': '200px'}">
Access the element height like this,
this.$refs.vCard.offsetHeight + 'px';
You can learn ref attribure here
View similar stack overflow question Get element height with Vuejs here.

How to get the value of scrollY while using overflow?

I've got the following React app where I'm using react-spring to animate between routes and animate different elements based on the current scroll position.
When I use overflow: scroll on the Home component I'm then unable to return anything from my handleScroll method (it just returns 0):
handleScroll(e) {
let windowScrollPosition = window.scrollY
this.setState({ windowScrollPosition: windowScrollPosition }, () => console.log(this.state.windowScrollPosition, 'this.state.windowScrollPosition'))
}
Is there a way around this?
I need to use overflow: scroll to solve this issue unfortunately.
Any help is much appreciated!
Well that would make sense. If you have set an element to scroll that is 100% height then the window would never scroll the element would.
So you need to get the scroll position from the element with elem.scrollTop
You can create a ref to the element in React
constructor(props) {
super(props);
this.scrollContainer = React.createRef();
}
return (
<div className="scroll-container" ref={this.scrollContainer}></div>
)
And then in your handle scroll method use:
handleScroll(e) {
let windowScrollPosition = this.scrollContainer.current.scrollTop | window.scrollY;
this.setState({ windowScrollPosition: windowScrollPosition }, () => console.log(this.state.windowScrollPosition, 'this.state.windowScrollPosition'))
}

Vue.js style working on wrong element

It's really strange.
I'm making floating sidebar in the Vue component, so need to change the css position value between fixed and relative.
so what I did is giving an ID for the sidebar element, and on scroll event, check the position on the page and changed some css values.
Here is my code.
created() {
document.addEventListener('scroll', this.handleScroll);
},
destroyed() {
document.addEventListener('scroll', this.handleScroll);
}
/* ... */
handleScroll(e) {
var doc = document.documentElement;
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
var originWidth = $("#fields-to-move").width() + 2;
if(this.screen_no == 2){
if (280 <= top) {
document.getElementById("fields-to-move").style.position = "fixed";
document.getElementById("fields-to-move").style.top = 10 + 'px' ;
document.getElementById("fields-to-move").style.width = originWidth + 'px';
} else {
document.getElementById("fields-to-move").style.position = "relative";
document.getElementById("fields-to-move").style.top = 'auto' ;
document.getElementById("fields-to-move").style.width = originWidth + 'px';
}
}
}
"fields-to-move" is the ID of DOM element I'm going to change css.
It's working well.
But the problem is that above css ( position: fixed, top:10px and width) also applied on other element without the ID.
There's one thing more need to mention.
The element with the ID is a child element of another one which is mounted with v-if condition.
After the parent element dismounted, the css is applied to the wrong element that's mounted after it.
I'm not sure my explanation is enough. Please let me know if you have any questions above my problem.
Thanks in advance.
If you can provide separeted example in jsfiddle it would be easier to help...
But I belive that this behaviour can caused by some Vue optimizations described here: documentation
edit:
Try to execute entire logic of "handleScroll" in vues nextTick.

Categories

Resources