How to Prevent Auto Scroll to top when user clicks on the particular list value.

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



How to Prevent Auto Scroll to top when user clicks on the particular list value.



This component is called by a Parent component which is further called by a Parent component. If you want I can provide that details also. I hope that I will get some cool suggestions/solutions. I am stuck at this and not getting how to get rid of this.


import React from "react";
import PropTypes from "prop-types";
import moment from "moment";
import Scrollbars from "react-custom-scrollbars";
import _ from "lodash";
const LOADER_USER_COUNT = 10;
import timeFormat from "d3-time-format";
import timeHour from "d3-time";
import scaleTime, scaleBand from "d3-scale";
import axisTop from "d3-axis";
import Axis from "./Axis";
import ReactToolTip from "react-tooltip";

const DATEFORMAT = "YYYYMMDD";

class EmployeeList extends React.Component
constructor(props)
super(props);


getNameList(options)
const
fullName,
lastSeen,
activeClass,
showSelection,
isChecked,
userId,
yScale
= options;
let handleUserSelection = this.props;

let checkBoxClass = showSelection
? "downloadCheckBox active"
: "downloadCheckBox";
isChecked ? (checkBoxClass += " selected") : "";
let initials = fullName.split(" ");
return (
<g className="hoverClass">
/*`0,$yScale(userId) - 5 300,$yScale(userId) - 5 300,$yScale(userId) + 44 0,$yScale(userId) + 44 0,$yScale(userId) - 5`*/
<polyline
className="firstHover"
points=`0,$yScale(userId) + 46 300,$yScale(userId) + 46`
style= fill: "none", stroke: "lightgrey", strokeWidth: "1"
/>
<circle
cx="35"
cy=yScale(userId) + 17
r="17"
stroke="black"
strokeWidth="2"
fill="none"
className=`user-img $activeClass`
/>
<text
x="26"
y=yScale(userId) + 23
fill="black"
className="employeeFNLN"
>
initials[0].charAt(0).toUpperCase() +
(initials[1] && initials[1].charAt(0)
? initials[1].charAt(0)
: initials[0].charAt(1))
</text>
<g className=`user-details $activeClass`>
<text x="57" y=yScale(userId) + 14 fill="black">
fullName
</text>
<text x="57" y=yScale(userId) + 34 fill="black" className="time">
lastSeen
</text>
</g>
<circle
cx="265"
cy=yScale(userId) + 20
r="10"
onClick=() =>
handleUserSelection( id: userId, checked: !isChecked );

stroke="none"
strokeWidth="1"
className=checkBoxClass
/>

<polyline
onClick=() =>
handleUserSelection( id: userId, checked: !isChecked );

className="path check"
fill="none"
stroke="white"
strokeWidth="1"
strokeLinecap="round"
strokeMiterlimit="10"
points=`260,$yScale(userId) + 22 263,$yScale(userId) +
25 270,$yScale(userId) + 18`
/>
</g>
);


getLoadingList()
return (
<ul
className="employee-list stats attendance col-3"
style= width: "100%"
>
[...Array(LOADER_USER_COUNT)].map((k, i) =>
return (
<li key=i className="row user-item-loader">
<div className="col-3">
<div className="user-img offline">
<div className="animated-background sb-avatar" />
</div>
</div>
<div className=`col-9 user-details`>
<div className="animated-background user-name" />
<div className="animated-background last-seen" />
</div>
</li>
);
)
</ul>
);


render()
const
loading,
employees: emp,
selectedUser,
showSelection,
selectedExecutives,
showSelectAll,
sortBy,
isFieldForce,
// isSidebarOn,
// progress,
date,
// product,
executives: executivesObj ,
// filters: sortBy ,
todayProgress: checkins ,
userId,
startDate,
endDate,
dateRange,
mobileView,
selectUser,
selectSlice,
timeDiff,
assignmentData,
selectOptionClassName,
filterCount
= this.props;

let axisStartDate = startDate;
let axisEndDate = dateRange ? endDate : startDate;
// let today = checkins[startDate];
let _d = date === "today" ? moment().format(DATEFORMAT) : date;
let employees = JSON.parse(JSON.stringify(emp));

let emp2 = employees ? JSON.parse(JSON.stringify(employees)) : ;
let shiftMapping = this.props.shifts;
if (loading)
return this.getLoadingList();
// return isFieldForce
// ? this.getLoadingList()
// : [
// // this.props.getSearchBar(this.props.search, this.props.product),
// <div className="col-12 row">
// <div className="col-3 row">this.getLoadingList()</div>
// <div className="col-9 row">/* <Slice userId=emp._id date="today" /> */</div>
// </div>
// ];

let userIds = ;

axisStartDate === "today"
? (axisStartDate = moment().format(DATEFORMAT))
: (axisStartDate = startDate);

axisEndDate === "today"
? (axisEndDate = moment().format(DATEFORMAT))
: (axisEndDate = endDate);

let dynamicAxis = this.getDynamicValuesForAxis(
shiftMapping,
checkins[startDate],
startDate
);
// const date = startDate;
if (date != "today")
employees.forEach(e =>
if (!e.userData[date])
e.userData[date] =
userFirstSeen: undefined,
userLatestTime: undefined
;

);


if (sortBy === "lastseen")
employees.sort((a, b) => );
else if (sortBy === "firstseen")
employees.sort((a, b) =>
if (
!a.userData[date].userFirstSeen &&
!b.userData[date].userFirstSeen
)
return 0;

if (
!a.userData[date].userFirstSeen &&
b.userData[date].userFirstSeen !== ""
)
return 1;

if (
a.userData[date].userFirstSeen !== "" &&
!b.userData[date].userFirstSeen
)
return -1;

if (a.userData[date].userFirstSeen && b.userData[date].userFirstSeen)
let keyA = new Date(a.userData[date].userFirstSeen),
keyB = new Date(b.userData[date].userFirstSeen);
// Compare the 2 dates
if (keyA > keyB) return 1;
if (keyA < keyB) return -1;
return 0;

);


let axisStartTime = dynamicAxis.min;
let axisEndTime = dynamicAxis.max;

let userIDs = ;
let progressObject = ;
let progressObjectFinish = ;

// console.log(today);
if (userId && userId.length > 0)
userIDs = userId;
userIDs.forEach(id =>
;
);
else
emp2.map(exec => );


employees.forEach(e =>
userIds.push(e._id);
);

let xScale = scaleTime()
.domain([new Date(axisStartTime), new Date(axisEndTime)])
// .range([0, this.props.containerWidth - (mobileView ? 0 : 50)]);
.range([0, 800]);

var xAxis = axisTop(xScale)
.tickFormat(timeFormat("%I %p"))
.ticks(timeHour.every(timeDiff));

let svgHeight = 55.9841 * userIDs.length;

let yScale = scaleBand()
.domain(userIds)
.range([0, 56 * userIds.length]);

return (
<div
className=
showSelection
? "employee-list stats attendance selection-height"
: "employee-list stats attendance"

>
/* <ReactToolTip multiline=true /> */
<svg
width="100%"
height= filterCount ? "80" : "50"
viewBox="0 0 1200 1200"
preserveAspectRatio="xMidYMin slice"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<filter id="dropshadow" height="100%" width="100%">
<feOffset result="offOut" in="SourceGraphic" dx="20" dy="20" />
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
</filter>
</defs>
<foreignObject height="50" width="25%">
this.props.getSearchBar(this.props.search, this.props.product)
</foreignObject>
<g transform="translate(330, 30)">
<Axis axis=xAxis mobileView />
</g>
<foreignObject height="30" width="25%" y="50">
//employee usage only
showSelection ? (
<div className=selectOptionClassName>
selectedExecutives.length ? (
<span className="float-left selection-total">`$
selectedExecutives.length
selected`</span>
) : null
showSelectAll ? (
<a href="#" onClick=this.props.handleSelectAll>
Select All
</a>
) : null
selectedExecutives.length != 0 ? (
<a href="#" onClick=this.props.handleSelectNone>
Clear
</a>
) : null
</div>
) : filterCount ? (
<div
key="filterCount"
className="pointer p-2 text-center"
style= color: "#adadad"
onClick=() =>
if (window.innerWidth < 573)
//close menu sidebar
this.props.setSidebar(false);

this.props.openFilterNavigation(!this.props.filterSidebar);

>
<span className="position-relative">
<i className="fa fa-filter filter-icon" aria-hidden="true" />
filterCount ? <span className="red-bubble" /> : null
</span>" "
filterCount filterfilterCount > 1 ? "s" : "" applied
</div>
) : null
</foreignObject>
</svg>
<Scrollbars style= flex: "1 1 0" >
<svg
// width="100%"
// height=svgHeight
viewBox=`0 0 1200 $svgHeight`
preserveAspectRatio="xMidYMin slice"
xmlns="http://www.w3.org/2000/svg"
>
<g transform="translate(0, 10)">
employees.map((emp, index) => )
</g>
</svg>
employees.length === 0 ? (
<h5 className="text-center mt-2">No Data Found</h5>
) : null
</Scrollbars>
</div>
);


getDynamicValuesForAxis(shiftMapping, todayProgress, date)
if (Object.keys(shiftMapping).length && todayProgress != undefined)
let retVal =
min: undefined,
max: undefined
;

if (date === "today")
date = moment().format(DATEFORMAT);


let shiftTiming = ;
_.each(shiftMapping, shift =>
if (shift.dObjectDetails.enabled === false) return;
shiftTiming.push(
startHour: parseInt(shift.dObjectData.start_hour),
endHour: parseInt(shift.dObjectData.end_hour)
);
);

let shiftSort = _.sortBy(shiftTiming, el =>
return el.startHour;
);

retVal =
min: moment(date, DATEFORMAT)
.hour(shiftSort[0].startHour)
.minute(0),
max:
shiftSort[shiftSort.length - 1].endHour < shiftSort[0].startHour
? moment(date, DATEFORMAT)
.add(1, "day")
.hour(shiftSort[shiftSort.length - 1].endHour)
.minute(0)
: moment(date, DATEFORMAT)
.hour(shiftSort[shiftSort.length - 1].endHour)
.minute(0)
;

let startObject = ,
endObject = ;

_.each(todayProgress, el =>
el &&
el.progress &&
el.progress.length &&
startObject.push(el.progress[0]);
el.progress &&
el.progress.length &&
endObject.push(el.progress[el.progress.length - 1]);
);

startObject = _.sortBy(startObject, el =>
if (el) return el.start;
);

endObject = _.sortBy(endObject, el =>
if (el) return el.end;
);

if (
startObject[0] &&
startObject[0].start &&
moment(retVal.min).isAfter(moment(startObject[0].start))
)
retVal.min = moment(startObject[0].start);


if (
endObject[endObject.length - 1] &&
endObject[endObject.length - 1].end &&
moment(retVal.max).isBefore(moment(endObject[endObject.length - 1].end))
)
retVal.max = moment(endObject[endObject.length - 1].end);


return retVal;
else
return
min: moment(date, DATEFORMAT).startOf("day"),
max: moment(date, DATEFORMAT).endOf("day")
;



componentDidUpdate()
ReactToolTip.rebuild();


// handleHover(item, hover)
// // console.log("g tag style from hover:::::", this.refs["gTag" + item].style);
// hover ? (this.refs["gTag" + item].style.filter = "url(#dropshadow)") : (this.refs["gTag" + item].style = "");
//
}

EmployeeList.propTypes =
selectedUser: PropTypes.object,
progress: PropTypes.object,
assignmentData: PropTypes.object,
resetUserSelection: PropTypes.func.isRequired,
selectUser: PropTypes.func.isRequired,
handleUserSelection: PropTypes.func,
loading: PropTypes.bool,
employees: PropTypes.array.isRequired,
showSelection: PropTypes.bool,
isFieldForce: PropTypes.bool,
sortBy: PropTypes.string,
date: PropTypes.string,
product: PropTypes.string,
selectedExecutives: PropTypes.array,
isSidebarOn: PropTypes.bool,
isLiteVersion: PropTypes.bool,
;

export default EmployeeList;



Please suggest me that, why it is getting auto scroll to the top? I am stuck at this. Every suggestion would be highly appreciated. Thank you in advance





Can you trim down your code? It's tough to get through the markup
– SoluableNonagon
Aug 8 at 14:11





2 Answers
2



in your onClick try


onClick=(event) =>
event.preventDefault();
handleUserSelection( id: userId, checked: !isChecked );



Also, the href="#" on anchor tags looks for an ID on the page and will likely scroll you to the top on click.


<a href="#" onClick=this.props.handleSelectAll>
Select All
</a>





I tried that before shooting my question here. No luck yet :(
– shubham saurabh
Aug 9 at 7:56



Finally this is working. I am using ref for setting the scroll position and it is working fine .


import React from "react";
import PropTypes from "prop-types";
import moment from "moment";
import Scrollbars from "react-custom-scrollbars";
import _ from "lodash";
const LOADER_USER_COUNT = 10;
import timeFormat from "d3-time-format";
import timeHour from "d3-time";
import scaleTime, scaleBand from "d3-scale";
import axisTop from "d3-axis";
import Axis from "./Axis";
import ReactToolTip from "react-tooltip";

const DATEFORMAT = "YYYYMMDD";

class EmployeeList extends React.Component
constructor(props)
super(props);


getNameList(options)
const
fullName,
lastSeen,
activeClass,
showSelection,
isChecked,
userId,
yScale
= options;
let handleUserSelection = this.props;

let checkBoxClass = showSelection
? "downloadCheckBox active"
: "downloadCheckBox";
isChecked ? (checkBoxClass += " selected") : "";
let initials = fullName.split(" ");
return (
<g className="hoverClass">
/*`0,$yScale(userId) - 5 300,$yScale(userId) - 5 300,$yScale(userId) + 44 0,$yScale(userId) + 44 0,$yScale(userId) - 5`*/
<polyline
className="firstHover"
points=`0,$yScale(userId) + 46 300,$yScale(userId) + 46`
style= fill: "none", stroke: "lightgrey", strokeWidth: "1"
/>
<circle
cx="35"
cy=yScale(userId) + 17
r="17"
stroke="black"
strokeWidth="2"
fill="none"
className=`user-img $activeClass`
/>
<text
x="26"
y=yScale(userId) + 23
fill="black"
className="employeeFNLN"
>
initials[0].charAt(0).toUpperCase() +
(initials[1] && initials[1].charAt(0)
? initials[1].charAt(0)
: initials[0].charAt(1))
</text>
<g className=`user-details $activeClass`>
<text x="57" y=yScale(userId) + 14 fill="black">
fullName
</text>
<text x="57" y=yScale(userId) + 34 fill="black" className="time">
lastSeen
</text>
</g>
<circle
cx="265"
cy=yScale(userId) + 20
r="10"
onClick=() =>
handleUserSelection( id: userId, checked: !isChecked );

stroke="none"
strokeWidth="1"
className=checkBoxClass
/>

<polyline
onClick=() =>
handleUserSelection( id: userId, checked: !isChecked );

className="path check"
fill="none"
stroke="white"
strokeWidth="1"
strokeLinecap="round"
strokeMiterlimit="10"
points=`260,$yScale(userId) + 22 263,$yScale(userId) +
25 270,$yScale(userId) + 18`
/>
</g>
);


getLoadingList()
return (
<ul
className="employee-list stats attendance col-3"
style= width: "100%"
>
[...Array(LOADER_USER_COUNT)].map((k, i) =>
return (
<li key=i className="row user-item-loader">
<div className="col-3">
<div className="user-img offline">
<div className="animated-background sb-avatar" />
</div>
</div>
<div className=`col-9 user-details`>
<div className="animated-background user-name" />
<div className="animated-background last-seen" />
</div>
</li>
);
)
</ul>
);


render()
const
loading,
employees: emp,
selectedUser,
showSelection,
selectedExecutives,
showSelectAll,
sortBy,
isFieldForce,
// isSidebarOn,
// progress,
date,
// product,
executives: executivesObj ,
// filters: sortBy ,
todayProgress: checkins ,
userId,
startDate,
endDate,
dateRange,
mobileView,
selectUser,
selectSlice,
timeDiff,
assignmentData,
selectOptionClassName,
filterCount
= this.props;

let axisStartDate = startDate;
let axisEndDate = dateRange ? endDate : startDate;
// let today = checkins[startDate];
let _d = date === "today" ? moment().format(DATEFORMAT) : date;
let employees = JSON.parse(JSON.stringify(emp));

let emp2 = employees ? JSON.parse(JSON.stringify(employees)) : ;
let shiftMapping = this.props.shifts;
if (loading)
return this.getLoadingList();
// return isFieldForce
// ? this.getLoadingList()
// : [
// // this.props.getSearchBar(this.props.search, this.props.product),
// <div className="col-12 row">
// <div className="col-3 row">this.getLoadingList()</div>
// <div className="col-9 row">/* <Slice userId=emp._id date="today" /> */</div>
// </div>
// ];

let userIds = ;

axisStartDate === "today"
? (axisStartDate = moment().format(DATEFORMAT))
: (axisStartDate = startDate);

axisEndDate === "today"
? (axisEndDate = moment().format(DATEFORMAT))
: (axisEndDate = endDate);

let dynamicAxis = this.getDynamicValuesForAxis(
shiftMapping,
checkins[startDate],
startDate
);
// const date = startDate;
if (date != "today")
employees.forEach(e =>
if (!e.userData[date])
e.userData[date] =
userFirstSeen: undefined,
userLatestTime: undefined
;

);


if (sortBy === "lastseen")
employees.sort((a, b) => );
else if (sortBy === "firstseen")
employees.sort((a, b) =>
if (
!a.userData[date].userFirstSeen &&
!b.userData[date].userFirstSeen
)
return 0;

if (
!a.userData[date].userFirstSeen &&
b.userData[date].userFirstSeen !== ""
)
return 1;

if (
a.userData[date].userFirstSeen !== "" &&
!b.userData[date].userFirstSeen
)
return -1;

if (a.userData[date].userFirstSeen && b.userData[date].userFirstSeen)
let keyA = new Date(a.userData[date].userFirstSeen),
keyB = new Date(b.userData[date].userFirstSeen);
// Compare the 2 dates
if (keyA > keyB) return 1;
if (keyA < keyB) return -1;
return 0;

);


let axisStartTime = dynamicAxis.min;
let axisEndTime = dynamicAxis.max;

let userIDs = ;
let progressObject = ;
let progressObjectFinish = ;

// console.log(today);
if (userId && userId.length > 0)
userIDs = userId;
userIDs.forEach(id =>
;
);
else
emp2.map(exec => );


employees.forEach(e =>
userIds.push(e._id);
);

let xScale = scaleTime()
.domain([new Date(axisStartTime), new Date(axisEndTime)])
// .range([0, this.props.containerWidth - (mobileView ? 0 : 50)]);
.range([0, 800]);

var xAxis = axisTop(xScale)
.tickFormat(timeFormat("%I %p"))
.ticks(timeHour.every(timeDiff));

let svgHeight = 55.9841 * userIDs.length;

let yScale = scaleBand()
.domain(userIds)
.range([0, 56 * userIds.length]);

let _scrollTop = 0;

return (
<div
className=
showSelection
? "employee-list stats attendance selection-height"
: "employee-list stats attendance"

>
/* <ReactToolTip multiline=true /> */
<svg
width="100%"
height= filterCount ? "80" : "50"
viewBox="0 0 1200 1200"
preserveAspectRatio="xMidYMin slice"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<filter id="dropshadow" height="100%" width="100%">
<feOffset result="offOut" in="SourceGraphic" dx="20" dy="20" />
<feBlend in="SourceGraphic" in2="offOut" mode="normal" />
</filter>
</defs>
<foreignObject height="50" width="25%">
this.props.getSearchBar(this.props.search, this.props.product)
</foreignObject>
<g transform="translate(330, 30)">
<Axis axis=xAxis mobileView />
</g>
<foreignObject height="30" width="25%" y="50">
//employee usage only
showSelection ? (
<div className=selectOptionClassName>
selectedExecutives.length ? (
<span className="float-left selection-total">`$
selectedExecutives.length
selected`</span>
) : null
showSelectAll ? (
<a href="#" onClick=this.props.handleSelectAll>
Select All
</a>
) : null
selectedExecutives.length != 0 ? (
<a href="#" onClick=this.props.handleSelectNone>
Clear
</a>
) : null
</div>
) : filterCount ? (
<div
key="filterCount"
className="pointer p-2 text-center"
style= color: "#adadad"
onClick=() =>
if (window.innerWidth < 573)
//close menu sidebar
this.props.setSidebar(false);

this.props.openFilterNavigation(!this.props.filterSidebar);

>
<span className="position-relative">
<i className="fa fa-filter filter-icon" aria-hidden="true" />
filterCount ? <span className="red-bubble" /> : null
</span>" "
filterCount filterfilterCount > 1 ? "s" : "" applied
</div>
) : null
</foreignObject>
</svg>
<Scrollbars
onScrollFrame=values =>
let scrollTop = values;
_scrollTop = scrollTop;

style= flex: "1 1 0"
ref=ref =>
if (ref)
ref.scrollTop(_scrollTop

>
<svg
// width="100%"
// height=svgHeight
viewBox=`0 0 1200 $svgHeight`
preserveAspectRatio="xMidYMin slice"
xmlns="http://www.w3.org/2000/svg"
>
<g transform="translate(0, 10)">
employees.map((emp, index) => )
</g>
</svg>
employees.length === 0 ? (
<h5 className="text-center mt-2">No Data Found</h5>
) : null
</Scrollbars>
</div>
);


getDynamicValuesForAxis(shiftMapping, todayProgress, date)
if (Object.keys(shiftMapping).length && todayProgress != undefined)
let retVal =
min: undefined,
max: undefined
;

if (date === "today")
date = moment().format(DATEFORMAT);


let shiftTiming = ;
_.each(shiftMapping, shift =>
if (shift.dObjectDetails.enabled === false) return;
shiftTiming.push(
startHour: parseInt(shift.dObjectData.start_hour),
endHour: parseInt(shift.dObjectData.end_hour)
);
);

let shiftSort = _.sortBy(shiftTiming, el =>
return el.startHour;
);

retVal =
min: moment(date, DATEFORMAT)
.hour(shiftSort[0].startHour)
.minute(0),
max:
shiftSort[shiftSort.length - 1].endHour < shiftSort[0].startHour
? moment(date, DATEFORMAT)
.add(1, "day")
.hour(shiftSort[shiftSort.length - 1].endHour)
.minute(0)
: moment(date, DATEFORMAT)
.hour(shiftSort[shiftSort.length - 1].endHour)
.minute(0)
;

let startObject = ,
endObject = ;

_.each(todayProgress, el =>
el &&
el.progress &&
el.progress.length &&
startObject.push(el.progress[0]);
el.progress &&
el.progress.length &&
endObject.push(el.progress[el.progress.length - 1]);
);

startObject = _.sortBy(startObject, el =>
if (el) return el.start;
);

endObject = _.sortBy(endObject, el =>
if (el) return el.end;
);

if (
startObject[0] &&
startObject[0].start &&
moment(retVal.min).isAfter(moment(startObject[0].start))
)
retVal.min = moment(startObject[0].start);


if (
endObject[endObject.length - 1] &&
endObject[endObject.length - 1].end &&
moment(retVal.max).isBefore(moment(endObject[endObject.length - 1].end))
)
retVal.max = moment(endObject[endObject.length - 1].end);


return retVal;
else
return
min: moment(date, DATEFORMAT).startOf("day"),
max: moment(date, DATEFORMAT).endOf("day")
;



componentDidUpdate()
ReactToolTip.rebuild();


// handleHover(item, hover)
// // console.log("g tag style from hover:::::", this.refs["gTag" + item].style);
// hover ? (this.refs["gTag" + item].style.filter = "url(#dropshadow)") : (this.refs["gTag" + item].style = "");
//
}

EmployeeList.propTypes =
selectedUser: PropTypes.object,
progress: PropTypes.object,
assignmentData: PropTypes.object,
resetUserSelection: PropTypes.func.isRequired,
selectUser: PropTypes.func.isRequired,
handleUserSelection: PropTypes.func,
loading: PropTypes.bool,
employees: PropTypes.array.isRequired,
showSelection: PropTypes.bool,
isFieldForce: PropTypes.bool,
sortBy: PropTypes.string,
date: PropTypes.string,
product: PropTypes.string,
selectedExecutives: PropTypes.array,
isSidebarOn: PropTypes.bool,
isLiteVersion: PropTypes.bool
;

export default EmployeeList;






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard