root element is undefined while pagination - javascript

I ma using element ui el-pagination like this
<el-pagination
#size-change="handleChange"
#current-change="CurrentChange"
:current-page.sync="currentPage"
:page-sizes="[50, 100, 150, 300]"
:page-size="pageSize"
popper-class="popper"
layout="sizes, prev, pager, next"
:total="getTotal"
/>
i have the methods defined
CurrentChange(val) {
this.currentPage = val;
},
i have created a mixin called as pagination.js
because this pagination is used at many places, so i added some keyboard events in it like this
document.querySelectorAll('ul.el-pager li.number').forEach((element, index) => {
element.addEventListener('keyup', function (e) {
if (e.key == 'Enter' || e.key == 'Space') {
this.$root.CurrentChange(element.innerHTML);
}
});
})
but i am getting undefined
i tried the console.log(this.$root) and i getting undefined, what i am missing here, i though the root has all the vue can fetch from

this inside the keyup event handler will refer to the element itself, not the component instance, you need to get this value ( as the component instance ) from outside the forEach callback function.
const that = this;
document.querySelectorAll('ul.el-pager li.number').forEach((element, index) => {
element.addEventListener('keyup', function (e) {
if (e.key == 'Enter' || e.key == 'Space') {
that.$root.CurrentChange(element.innerHTML);
}
});
})

Related

Listener for keydown is triggered multiple times instead of once

I have the following code:
undoButton.onclick = undoFunction;
document.addEventListener("keydown", (e) => {
if ((e.ctrlKey || e.metaKey) && e.code === "KeyZ") {
e.preventDefault();
undoFunction();
}
});
function undoFunction() {
console.log("undo function...");
}
When I click the button, as excepted, the function code runs once, and so does the console.log, but when I use the key stroke, the function is running a multiple times, up to hundreds of so-called loops at some scenarios. Any suggestion why? I tried to used e.repeat = false but had no luck. Thanks!
Use keyup instead. The keydown event triggers as long a key is hold down. keyup only triggers when a key is released.
var undoButton = document.getElementById('undoButton');
undoButton.onclick = undoFunction;
document.addEventListener("keyup", (e) => {
if ((e.ctrlKey || e.metaKey) && e.code === "KeyZ") {
e.preventDefault();
undoFunction();
}
});
function undoFunction() {
console.log("undo function...");
}
<input id="undoButton" type="button" value="Undo" />

Enter key for Route another page

I have a input for searchbox. I must make like; Write my words fors search then after i press enter it must need go another page with input value. So i can access that value with query string. So how can i route another page with value of input after i press enter ? Thank you for help! I Just add That codes for catch enter press.
useEffect(() => {
const listener = (event) => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
alert("Enter key was pressed. Run your function.");
event.preventDefault();
}
};
document.addEventListener("keydown", listener);
return () => {
document.removeEventListener("keydown", listener);
};
}, []);
You don't necessarily have to set an event listener, using onKeyDown event handler will also do. Enter key has a code of 13, so we just have to detect that.
Keep your value in a state (here, myValue), detect that you've pressed Enter key (here, using keyPressHandler method), and finally, pass the parameter to your route.
import {useHistory} from "react-router-dom"
function App() {
let history = useHistory();
const [myValue, setMyValue] = useState("");
const handleChange = ({ target: { value } }) => {
setMyValue(value);
};
const keyPressHandler = (e) => {
if (e.which === 13) {
// alert("You pressed enter!");
history.push("/process/" + myValue);
}
};
return (
<div className="App">
<input value={myValue} onKeyDown={keyPressHandler} onChange={handleChange} />
</div>
);
}
UPDATE:
According to MDN Web Docs, e.which is non-standard [Source] and e.keyCode is deprecated [Source], so you should be using e.key instead like:
const keyPressHandler = (e) => {
if (e.key=== 'Enter') {
// alert("You pressed enter!");
history.push("/process/" + myValue);
}
};
Working CodeSandbox Link

How to stop onClick invocation, on Enter click event

I have a div that has subscription for both onClick and onKeyPress (Enter click).
the desired behaviour for mouse click is: first click - open popup, second click - close popup.
the desired behaviour for enter click is: open popup.
when tabbing the focus to the div and click enter the subscribed method is fired twice, and it needs to be fired only once.
since, the same function is called twice on enter click, it opens and closes the popup.
i tried the followings:
subscribe to keyUp/keyDown instead of onKeyPress.
checking, in the onClick subscription if the event.detail === 0, but it was 0, when enter clicked also.
in onClick, checking if the event.type === 'mousedown', but it was always equal to 'click'
subscribe to onMouseDown/Up instead of onClick, the enter clicked stopped working.
this is the component firing the event
const eventPressHandler = e => {
if (e.key === 'Enter') {
return handleEventClick(e, true);
}
if (e.key === 'Tab' || (e.shiftKey && e.key === 'Tab')) {
return closeExpanded();
}
}
return (
<>
<div
onClick={handleEventClick}
onKeyPress={eventPressHandler}
className={st(
classes.root,
{ isAllDay, isInPopper, isMultiDay, isMobile, isAgenda, isCut, isWeekend },
className
)}
>
{event}
</div>
{popper}
</>
)
};
this is the handler in the parent component:
const handleEventClick = (eventElement, isKeyClicked) => {
isKeyClicked && setIsEventEventEntered(true);
setExpanded(
expanded || type === EventTypes.ShowMore ?
null :
eventElement.currentTarget,
() => {
onEventExpanded && onEventExpanded(expandedData) // i use custom hook to fire functions after the setState
}
);
}
I looked in a lot of similar issues but none of them had solution that worked for me.
i solved it like this:
onClick={e => e.detail === 1 && handleEventClick(e) }
onKeyUp={eventPressHandler}

JavaScript race condition without async code?

I seem to be encountering a race condition with a function of mine even though I am not using async functions in it
window.focusElem = (elem, overrideGroupNextFocus) => {
if (!elem) return
console.log(`FOCUS: ${elem.id}`)
if (store.getState().app.isExitVisible &&
elem.id !== 'exitExitButton' &&
elem.id !== 'exitBackButton'
) {
return
}
// Remove focus class from existing focused elements
Array.from(document.querySelectorAll('.focus')).forEach(e => {
console.log(`FOCUS: ${elem.id} removing focus from ${e.id}`)
e.classList.remove('focus')
})
const parentFocusGroup = findParentFocusGroup(elem)
let elemToFocus = elem
const focusGroupNextFocusId = parentFocusGroup ? parentFocusGroup.getAttribute('data-focusgroup-next-focus') : ''
if (!overrideGroupNextFocus &&
focusGroupNextFocusId &&
document.activeElement.id !== focusGroupNextFocusId) {
elemToFocus = parentFocusGroup.querySelector(`#${focusGroupNextFocusId}`) || elem
}
store.dispatch(setFocusElem(elemToFocus.id))
if (elemToFocus.id.startsWith('appNav')) {
Array.from(document.querySelectorAll('.active')).forEach(e => e.classList.remove('active'))
elemToFocus.classList.add('active')
document.querySelector('.app-wrapper').setAttribute('data-sidebar', 'open')
} else if (!elemToFocus.hasAttribute('data-focus-inmodal')) {
document.querySelector('.app-wrapper').setAttribute('data-sidebar', 'closed')
}
lastFocused = elemToFocus
console.log(`FOCUS: ${elem.id} add focus to ${elemToFocus.id}`)
elemToFocus.classList.add('focus')
document.dispatchEvent(new CustomEvent('app:focusChanged', { detail: elemToFocus }))
}
function findParentFocusGroup(elem) {
if (elem.hasAttribute('data-focusgroup')) {
return elem
}
const parent = elem.parentNode
if (parent && parent.nodeType !== 9) return findParentFocusGroup(parent)
}
I notice if this function is called in fast succession, I can get the following output in console:
FOCUS: history0
FOCUS: history0 removing focus from vodBannerProgram
FOCUS: vodBannerProgram
FOCUS: vodBannerProgram add focus to vodBannerProgram
FOCUS: history0 add focus to history0
Notice, it seems like this function is called for history0 first then vodBannerProgram. But it seems like it executed halfway for history0 then proceeded to vodBannerProgram then back again? forEach are synchronous correct?
There is no race condition without async. You don't display enough code to find it (if this is the case). Check the following code:
setFocusElem
store.dispatch

Notify sibling component of key down events

I have an <input/> which defines an onKeyDown prop which is fired when a key is pressed. In the callback, I check if the keycode matches a certain key (in this case, the up or down arrow keys).
I need to notify a sibling component that is in the same render() method as the <input/> whenever one of the matching keys is pressed.
Here is the relevant code:
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
console.log('up arrow pressed')
}
//Handle down arrow press.
if (keyCode == 40) {
console.log('down arrow pressed')
}
}
render() {
return (
<div className="chat-input">
{this.state.showCommandPopup && <CommandPopup input={this.state.inputValue}/> }
<form onSubmit={this.handleSubmit.bind(this)}>
<Input onKeyDown={this.handleKey.bind(this)} value={this.state.inputValue} onChange={this.onInputChange.bind(this)} className="chat-input-comp" placeholder="Say something. You can use / to search, and . for commands." action='Send'/>
//....
</form>
</div>
);
}
How can I notify my <CommandPopup/> component whenever the up or down arrow key is pressed?
Step 1.
You need to call setState inside handleKey() method. Once setState is called parent as well as child component will re-render.
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
this.setState({keyvalue:keyCode})
console.log('up arrow pressed')
}
//Handle down arrow press.
if (keyCode == 40) {
console.log('down arrow pressed')
this.setState({keyvalue:keyCode})
}
// It will call render() Method
}
Step 2.
Inside CommandPopup component you need to add, componentWillReceiveProps(newProps).
Inside componentWillReceiveProps(newProps), you will get the updated value of input={this.state.inputValue}
componentWillReceiveProps(newProps){
console.log(newProps.keyvalue,'keycode')
}
You just need to raise an event, nothing prevents you to use js events. But I think you are not doing the proper way, since react is not an event base framework, and there is maybe a better solution to this problem using a state container like redux or mobx.
On your CommandPopup component you just need to subscribe to the event.
class CommandPopup extends Component {
componentDidMount() {
window.addEventListener('keyUp', () => {
console.log('Key UP ...');
});
window.addEventListener('keyDown', () => {
console.log('Key DOWN ....');
});
}
render() {
return (
<div>Something ...</div>
);
}
}
And just dispatch the event:
handleKey(e) {
let keyCode = e.keyCode;
//Handle up arrow press.
if (keyCode == 38) {
const ev = new Event('keyUp', { 'bubbles': true, 'cancelable': false });
document.dispatchEvent(ev);
}
//Handle down arrow press.
if (keyCode == 40) {
const ev = new Event('keyDown', { 'bubbles': true, 'cancelable': false });
document.dispatchEvent(ev);
}
}
render() {
return (
<div className="chat-input">
{this.state.showCommandPopup && <CommandPopup input={this.state.inputValue}/> }
<form onSubmit={this.handleSubmit.bind(this)}>
<Input onKeyDown={this.handleKey.bind(this)} value={this.state.inputValue} onChange={this.onInputChange.bind(this)} />
</form>
</div>
);
}
Again maybe you should take a look to mobx computed values, this is the kind of problem they can solve.
Hope this help.

Categories