Auto-scroll to bottom of the messages - javascript

I am working on a chat app, everytime I put a message I need to scroll to the bottom in order to see the new messages. So, as in a regular chat, I need to provide the functionality that the user may be able to see the last messages without manually scrolling to the bottom.
I am using React, is there a css way? or can you tell me the best way to do that ?
let me show you some code
this is the main component
render () {
let messages = this.props.chatMessages.map((message) => {
return <ChatItem info={message.info} me={message.me} player={message.player} message={message.message} />;
});
let chatForm;
if (this.props.mode === 'player') {
chatForm = <ChatForm onAddMessage={this.addMessage} />;
}
return <div className="Chat">
<ul className="Chat__messages">{messages}</ul>
<hr />
<div>{chatForm}</div>
</div>;
}
here are the ChatItem and ChatForm components
render () {
let item;
const { message, player, me, info } = this.props;
if (info) {
item = <li><em>{message}</em></li>;
}
else if (me) {
item = <li><strong>Me: {message}</strong></li>;
}
else {
item = <li><strong>{player}:</strong> {message}</li>;
}
return item;
}
render () {
return <div className="ChatForm">
<input
className="ChatForm__input"
placeholder="Your message..."
ref="newMessage"
onKeyDown={this.onKeyDown}
autofocus="true" />
</div>;
}
ADDING INFO
I need something like this http://codepen.io/TimPietrusky/pen/ylkFs
Look at this part
// Scroll the latest line of output
output.scrollTop(
output[0].scrollHeight - output.height()
);
how should I adapt it to my code on React ?

One way to do it is to compare current and previous/next props in a lifecycle event such as componentDidUpdate and scroll to bottom if a new message was added. For example:
componentDidUpdate(prevProps) {
// Check if new message was added, for example:
if (this.props.messages.length === prevProps.messages.length + 1) {
// Scroll to bottom
}
}

Related

this.router.routeReuseStrategy.shouldReuseRoute = () => false;

this.router.routeReuseStrategy.shouldReuseRoute = () => false;
I have applied this sort of line in order to make the component UI updated everytime. But in some other cases it start to refreshing the page event if it should reuse the route.
How can we overcome this issue?
Actually in my application there are three tabs in left panel. In each tab there are some listings clicking on list items opens the content on right panel. But in one of the listing there is a common UI that is getting open on some list item, but the problem is that when we don't apply above sort of code then the UI is not getting updated. But if we apply the code then the UI is updated everytime we click on other list item. But the problem is that when we apply this code it start to refresh the page everytime we click on other list in different tabs also, that should not be the case.
If we apply this code this.router.routeReuseStrategy.shouldReuseRoute = () => false; then how can we revert this functionality under this.router?
To take less risks I'm just reverting it back to what it was once the reload is done:
refresh() {
const prev = this.router.routeReuseStrategy.shouldReuseRoute;
const prevOSN = this.router.onSameUrlNavigation;
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([this.router.url]);
setTimeout(() => {
this.router.routeReuseStrategy.shouldReuseRoute = prev;
this.router.onSameUrlNavigation = prevOSN;
}, 0);
}
I have the same issue, I changed that line for this:
// override the route reuse strategy
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this.router.events.subscribe((evt) => {
if (evt instanceof NavigationEnd) {
// trick the Router into believing it's last link wasn't previously loaded
this.router.navigated = false;
// if you need to scroll back to top, here is the right place
window.scrollTo(0, 0);
}
});
I don't even know if this works well or do the same thing.
private saveRouterStrategyReuseLogic: any;
ngOnInit() {
// Save logic
this.saveRouterStrategyReuseLogic = this.router.routeReuseStrategy.shouldReuseRoute;
this.router.routeReuseStrategy.shouldReuseRoute = (future, curr) => { return false; };
}
ngOnDestroy() {
this.router.routeReuseStrategy.shouldReuseRoute =
this.saveRouterStrategyReuseLogic;
}

How to use useEffect() correctly?

I want to change style by scrolling.
This code isn't working correctly
.
When I rolling up and down too many times and too fast, then the browser is going to freeze, crash.
I think I used useEffect() wrong. How can I solve this issue.
const ArticleItem = ({title, content, active, chapter, program, id, scrollPos}) => {
const ref = useRef(null);
const client = useApolloClient();
useEffect(() => {
if(ref.current.offsetTop <= (scrollPos + 200)) {
client.writeData({data: {
curChapter: chapter.num,
curArticle: id,
curProgram: program.name
}});
}
});
if(active === false)
return ( // Inactive Article
<div className='section-item' ref={ref}>
<h2>{title.toUpperCase()}</h2>
<ReactMarkdown source={content} />
<br />
</div>
)
return ( // Active Article
<div className='section-item active' ref={ref}>
<h2>{title.toUpperCase()}</h2>
<ReactMarkdown source={content} />
<br />
</div>
)
}
As a Result, I faced this warning.
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
I think this is the reason of issue?!
Based on my comment above, you need to include the dependency array for useEffect also. In the current way it is running infinitely. Probably you want to include scrollPos into that thus it would only triggered once scrollPos is changing.
Try the following:
useEffect(() => {
if(ref.current.offsetTop <= (scrollPos + 200)) {
client.writeData({data: {
curChapter: chapter.num,
curArticle: id,
curProgram: program.name
}});
}
}, [scrollPos]);
I hope this helps!
Well, the problem is triggered all the time you can use the scroll event listener and make your changes when this event is triggered.
const [scrollItem, setScrollItem] = useState(null);
const handleScroll() {
if(scrollItem) {
// logic goes here
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []); // initialize event only once
return (
<div ref={setScrollItem}>
...
</div>
);
EDIT
Avoid that solution, #norbitrial is right

How to simulate long press with react js?

I want to trigger long press event with click event. is there any way to that in react js?
something close to this, is the jQuery trigger() function. but i want something like trigger("longPress") or open up right click menu with left click in react. both mentioned (long press trigger / open up right click menu) are ideal for me
you can do this hack by get hold time
https://stackblitz.com/edit/react-d1txdm
export default function App() {
let triggerTime;
return (
<div>
<h1>Try on Google Chrome Desktop</h1>
<p>Open the console log to see how the event gets triggered.</p>
<p>The event should not get triggered if there is a long click.</p>
<img
src="https://via.placeholder.com/200.png/09f/fff"
onClick={(e) => {
if (triggerTime > 1000) return;
else console.log('normal click');
}}
onMouseDown={() => {
triggerTime = new Date().getTime();
}}
onMouseUp={() => {
let thisMoment = new Date().getTime();
triggerTime = thisMoment - triggerTime;
}}
/>
</div>
);
}
What about something like this:
const myComponent = () => {
let clickHoldTimer = null;
const handleMouseDown = () => {
clickHoldTimer = setTimeout(() => {
//Action to be performed after holding down mouse
}, 1000); //Change 1000 to number of milliseconds required for mouse hold
}
const handleMouseUp = () => {
clearTimeout(clickHoldTimer);
}
return (
<div onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} />
)
}

PrimeNg TabView with ConfirmDialog

I'm trying to use PrimeNg TabView component along with confirmDialog unsuccessfully, here is my code:
<p-tabView (onChange)="onTabChange($event)" [(activeIndex)]="index">...</p-tabView>
onTabChange(event){
this.confirmationService.confirm({
message: 'Do you confirm ?',
accept: () => {
this.index = event.index;
},
reject:() =>{ }
});
}
Do you have an idea on how to prevent or allow tab change using confirm dialog ?
Thanks
Based on similar solution for material design tabs, here is the solution for my issue:
in html Declare a local variable referencing TabView DOM object:
<p-tabView #onglets>...</p-tabView>
in component.ts, change default function called when click on tab with specific
function to match your case:
#ViewChild('onglets') onglets: TabView;
this.onglets.open = this.interceptOngletChange.bind(this);
...
interceptOngletChange(event: Event, tab: TabPanel){
const result = confirm(Do you really want to leave the tab?);
return result && TabView.prototype.open.apply(this.onglets, argumentsList);
});
}
I had similar problem. Needed show dialog before tab change.
My solution:
HTML
<p-tabView #tabView (onChange)="onChange($event)" />
TS
#ViewChild('tabView') tabView: TabView;
onChange(event: any) {
const previoustab = this.tabView.tabs[this.prevIndex]; //saved previous/initial index
previoustab.selected = true;
const selectedTab = this.tabView.tabs[event.index];
selectedTab.selected = false;
this.tabView.activeIndex = this.prevIndex;
this.nextIndex= event.index;
}
GoToNextTab() {
this.tabView.activeIndex = this.nextIndex;
this.prevIndex= this.nextIndex;
this.tabView.open(undefined, this.tabView.tabs[this.nextIndex]);
}
With this code you will stay on the selected tab without tab style changes.

Javascript mouseDown - cannot read currentTarget of undefined

I have a composent with which I would allow maintaining click in order to call multiple function by push-holding. My action dispatch a simple function to Redux reducers.
The objective of my component is to allow people decrease quantity of their order by maintaining a mouse's click. So that it, to allowing visitors have a more fluent user experience.
When I trigger the function my console returns me :
Cannot read property 'currentTarget' of undefined
When I click alone one time it is great. But when I mouseDown it fails with the above message.
Here my reactComponent.js:
import React, {Component} from 'react'
import style from "./OrderRibbon.css";
import equal from 'deep-equal';
export default class OrderRibbon extends Component {
t;
start = 100;
decreaseQuantity = (e) => {
e.preventDefault();
this.props.decreaseOrder(this.props.id)
}
addOrder= (e) => {
e.preventDefault();
this.props.addOrder(this.props.id)
}
orderPushing = (e) => {
e.preventDefault();
this.orderRepeat(e);
}
orderRepeat = (e) => {
if( e.currentTarget.attributes.name.value ){
console.log("EVENT NAME IN ORDER REAPEAT: ", e.currentTarget.attributes.name.value)
}else{
console.log("EVENT NAME IN ORDER REAPEAT: ", e.target.attributes.name.value)
}
if(e.currentTarget.attributes.name.value === "addOrder"){
this.addOrder
}else{
this.decreaseQuantity
}
this.t = setTimeout(this.orderRepeat, this.start);
this.start = this.start / 2;
}
// STOP Calling function
onMouseUp = () => {
clearTimeout(this.t);
this.start = 100;
}
render(){
return (
<div className={style.order_ribbon_layout} >
<div className={`${style.title} ${style.details_element}`} >
{this.props.title}
<div className={style.quantity} >
<div className= {style.quantity_icon}></div>
<span className= {style.quantity_number} > {this.props.quantity} </span>
</div>
</div>
<div className={style.price} >
{this.props.price * this.props.quantity}
</div>
<div className={style.quantity} >
<div
onMouseUp={this.onMouseUp}
onMouseDown={this.orderPushing}
name="decreaseQuantity"
onClick={this.decreaseQuantity}
className={ `${style.cardButton}`}
id={style.decreaseQuantity}></div>
<div
onMouseUp={this.onMouseUp}
onMouseDown={this.orderPushing}
name="addOrder"
onClick={this.addOrder}
className={ `${style.addButon}`}
// ${style.details_element}
id={style.addArticle}></div>
</div>
</div>
)
}
}
I wcan't figure out what is going wrong, if any body have an hint, would be great.
You have event binding issue. You can define like this:
orderPushing = () => (e) => {
e.preventDefault();
this.orderRepeat(e);
}
Or, keeping the same as you currently have, you may use inline event binding like this:
onMouseDown={(e) => this.orderPushing(e)}

Categories

Resources