I am making a very simple autocomplete section in a react application.
Code as follows,
index.js
import React from 'react';
import { render } from 'react-dom';
import Autocomplete from './Autocomplete';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'left',
};
const items = ['Moscow', 'Ufa', 'Tver', 'Alma ata'];
function onAutoCompleteHandle(val) {
alert(val);
}
const App = () => (
<div style={styles}>
<Autocomplete items={items} onAutocomplete={onAutoCompleteHandle.bind(this)}/>
</div>
);
render(<App />, document.getElementById('root'));
autocomplete.js
Render method:
const showSuggest = {
display: this.state.show ? 'block' : 'none',
}
return (
<div>
<input type="text"
className="autoCompleteInput"
onChange={this.handleChange}
ref={input => { this.textInput = input; }}
onClick={this.handleClick}
onKeyPress={this.handleKeyPress}
/>
<span className='suggestWrapper' style={showSuggest}>
<ul className='suggestAutocomplete'>
{this.state.items.map((item, i) => {
return
<li key={i} onClick={this.selectSuggestion}>
{item}
</li>
})}
</ul>
</span>
</div>
)
Complete working example: https://codesandbox.io/s/react-autocomplete-nbo3n
Steps to reproduce in the above given sandbox example:
-> Click on the input box.
-> Enter single alphabet eg.., a .
-> This gives the two items as result Ufa, Alma ata .
-> Press the down arrow key in keyboard.
As nothing happens here, unable to select any of the dropdown items.
As of now things work only if we move the mouse over the dropdown and select any item but I am in the need to implement the same behaviour for key down and enter.
Expected behaviour:
-> On keydown/keyup should be able to navigate the dropdown list items.
-> On click enter key on an item then that item should be the selected one.
I have tried assigning ref={input => { this.textInput = input; }} to the ul list items suggestAutocomplete but that also doesn't help..
Really I am stuck with this for very very long time. I humbly request you to consider this question.
It is also okay if you change this existing code, but I need to have both mouse selection and keyboard selection as well in the autocomplete..
Initialize a state with value -1
Add an event on keyDown
something like this:
handleKeyDown(e) {
if (e.keyCode == 40) { //down
this.setState({active: ++this.state.active})
} else if (e.keyCode == 38) { //up
this.setState({active: --this.state.active})
} else if (e.keyCode == 13) { //enter
e.preventDefault();
if (this.state.active > -1) {
this.selectSuggestion();
}
}
};
On click, reset the state to -1 again.
Check this: https://codesandbox.io/s/react-autocomplete-cf2yd
Related
I am working on leaflet map and trying to show popup (<l-popup), when I press ENTER key and also when my marker is on active state then when on Enter press the popup show popup.
I have looked through leaflet map doc : https://vue2-leaflet.netlify.app/components/LPopup.html#demo
but cannot find any props or event that do what I want.
<l-marker
v-for="(loc, index) in locations"
:key="index"
#keydown.enter="openPopupOnEnterPress(index)"
// #keyup.enter = "showPopup = true"
>
data() {
return {
showPopup: false,
}
}
methods: {
openPopupOnEnterPress(e) {
if (e.keyCode === 13 || e.key === "Enter") {
alert("Enter was pressed");
} else {
console.log("Enter was not pressed");
}
},
}
The event or the function openPopupOnEnterPress(e) doesnot event triggers at all.
Any help will be much appreciated
<l-marker
v-for="(loc, index) in locations"
:key="index"
#keydown.enter.native="openPopupOnEnterPress(index)"
tabindex="0"
/>
I tried to write the function "checkVal" but it does not work for me.
I would be happy to some help with this.
This is what the function "checkVal" should do:
1. The user should be allowed only 2 attempts to enter a value of the "TextInput" field.
2. If the condition is met for the first time then "Teken_1_Modal" should be displayed and also a checkbox should be displayed below the TextInput field - if the user has marked the checkbox then "Teken_2_Modal" and also "Dial" will appear.
Once the checkbox is checked then the check cannot be removed afterwards ..
3. If the condition is met a second time then "Teken_2_Modal" and also "Dial" must be displayed .
import CheckBox from '#react-native-community/checkbox';
import { Teken_1_Modal } from '../components/Teken_1_Modal';
import { Teken_2_Modal } from '../components/Teken_2_Modal';
import { Dial } from '../components/Dial';
function App() {
const [toggleCheckBox, setToggleCheckBox] = useState(false)
//////////START FUNCTION ////////////////////////
function checkVal() {
const [count, setCount] = useState(0) // flag, can be between 0 to 2, will be reset after press it.
// The flag is per parameter {requestId} !!
if (count == 2) {
return; // exit the function
}else{
count ++
if (item.Immediate_Report_Min == null && item.Immediate_Report_Max !== null && inputValue >
item.Immediate_Report_Max) ||
(item.Immediate_Report_Min !== null && item.Immediate_Report_Max == null && inputValue <
item.Immediate_Report_Min) ||
(item.Immediate_Report_Min !== null && item.Immediate_Report_Max !== null && (inputValue > max ||
inputValue < min))
// then
if (count == 1) {// first try
<Teken_1_Modal />
setToggleCheckBox(toggleCheckBox); //in case of Check of the checkBox so u cant uncheck after !!
// then
if (count == 2) {// second try
<Teken_2_Modal />
< Dial />
setToggleCheckBox(toggleCheckBox);
}
////////////////////END FUNCTION////////////////////////////
return (
<View>
<View style={styles.ParamViewInput}>
<TextInput
style={styles.ParamTextInput}
blurOnSubmit={true}
autoCapitalize="none"
autoCorrect={false}
keyboardType="number-pad"
maxLength={6}
placeholder="input.."
onChangeText={(text) => onChangeInput(index, text)}
value={inputMeasurement[index]}
onBlur={() => console.log('onBlur for index:', index)}
/>
<Text style={styles.label_C}>{item.Parameter_Units}</Text>
<TouchableOpacity onPress={() => {
setHistory_ModalVisible(item.Parameter_Code);
}} style={styles.ParameterUnit}>
<Text style={styles.Hlable}>H</Text>
</TouchableOpacity>
{<Text style={styles.SignText}>{icon}</Text>}
</View>
<CheckBox
disabled={false}
value={toggleCheckBox}
onValueChange={(newValue) => setToggleCheckBox(newValue)}
/>
<History_Modal reqId={requestId} paramId={item.Parameter_Code}
modalVisible={isHistory_ModalVisible == item.Parameter_Code}
setModalVisible={() => {
setHistory_ModalVisible(false);
}}
/>
</View>
);
}
Assuming checkVal is something you are calling multiple times after something is being updated, you should not have a useState() inside the function. Since once the function is called and disposed, the count state is also disposed.
Hooks should only be used inside functional components, not some other function that you call multiple times upon users action.
Put the const [count, setCount] = useState(0); outside along with toggleCheckBox
Then try to achieve the same effect. Also where are trying to call setCount and where are you using count ? Does it need to be in state ?
in my text box I need to use all this methods onKeyDown, onMouseUp and onChange.
when I try to select the text in my textbox onMouseUp event is calling,
after selection if I delete its calling onChange method.
is it possible to avoid, since onselection and deletion of that text I need to call another api fetchSearch
I debugged by putting consoles but still not successful
can you tell me how to fix it.
providing my code snippet below and sandbox below
all my code is present inside Button.js which is iniside containers folder
https://codesandbox.io/s/loving-moon-0h0fm
const onKeyDown = e => {
console.log("e.keyCode", e.keyCode);
if (e.keyCode === 8) {
console.log("delete---->", e.target.value);
getPosts(channel);
if (e.target.value === "") {
console.log("onKeyDown delete empty value--->", e.target.value);
fetchSearch(channel);
}
}
};
const onMouseUp = e => {
console.log("onMouseUp e.keyCode", e.keyCode);
if (e.target.value === "") {
console.log("onMouseUp delete empty value--->", e.target.value);
fetchSearch(channel);
}
};
return (
<div>
{/* <button
onClick={() => {
getPosts(channel);
getAlert();
}}
className="btn btn-primary btn-lg btn-block"
>
Get top news
</button> */}
<InputBase
// className={classes.input}
placeholder="Search Google Maps"
inputProps={{ "aria-label": "Search Google Maps" }}
onChange={e => {
console.log("onChange e.target.value--->", e.target.value);
getPosts(channel);
}}
onKeyDown={() => {
// getPosts(channel);
onKeyDown();
}}
onMouseUp={() => {
// getPosts(channel);
onMouseUp();
}}
//onKeyDown={onKeyDown}
// onMouseUp={this.onMouseUp}
/>
</div>
);
To ignore delete key presses in onChange method you could add the following to the first line of your onChange method:
if(e.target.value == '') return
Your onChange method would now do nothing if the text box is empty (e.g. user just pressed delete)
Similarly you could filter out the case where text is selected from the onMouseUp event e.g.:
if(window.getSelection().toString().length > 0) return
You can use similar if statements to filter out all non wanted event triggers.
Something I like about the textarea element is that allows automatic spell checker. This is not happening with input text element. I need an element like textarea that will only show one line and never go to a next line even if the user press enter. I tried row='1' but doesn't matter if the user press enter the content moves to a next line. This could also be a react component. Exist something like that?
Like this:
document.querySelector('textarea').addEventListener('keydown', (e) => {
if (e.keyCode === 13) e.preventDefault();
});
textarea {
white-space: nowrap;
overflow:hidden;
}
<textarea rows="1"></textarea>
As your question tagged ReactJS
import React from 'react';
class App extends React.Component {
handleTextArea = (e) =>{
let lineCount = 0;
if (e.keyCode == 13) {
lineCount++;
}
if (lineCount >= 1) { // set here how may lines you want
e.preventDefault();
return false;
}
}
render() {
return (
<div>
<textarea onKeyDown={this.handleTextArea}>only one line</textarea>
</div>
)
}
}
export default App
I am trying to create a text area element, where on load it should display a "1. ". The user can then type a sentence and hit return. Upon return it should render a "2." in the next line. When a user is on a line that has no text and clicks backspace, it should delete the number and return the focus to the previous number point. To illustrate this: User is on line "2." -> They press backspace which removes the "2." bullet point. -> returns them to the last character of line "1."
So far i have figured out this much:
const React = require('react');
const TextArea = React.createClass({
getInitialState: function() {
return {
textAreaVal: '1. '
};
},
editTextArea: function(value) {
this.setState({
textAreaVal: value
});
},
render: function() {
return (
<div className={"container"}>
<textarea autoFocus className={"proposal-textarea"} wrap="hard" defaultValue ={this.state.textAreaVal}
onChange={this.editTextArea} />
</div>
);
},
});
module.exports = TextArea;
Does anyone have any thoughts on the best way I can accomplish this?
What you're looking for is Reacts onKeyDown event.
Same way you have onChange set up, set up a function for onKeyDown that sends to this.handleKeyDown(event). Within that function, test event.charCode to determine which key was pressed (enter should be 13 and backspace should be 8), and then apply the necessary actions as needed.
EDIT: Moving my comment to the answer block;
To handle the incrementing number, simply add a secondary state element, lineNumber. Initialize it to 1 at start. Whenever you detect a keypress of Enter, increment lineNumber and append "\n" + this.state.lineNumber + ". " to your textAreaVal.
Well, look at this fiddle
const { Component, PropTypes } = React;
class NumberedTextArea extends Component {
constructor() {
super();
this._onKeyDown = this._onKeyDown.bind(this);
this.state = {
counter: 2,
text: `1. `
}
}
_onKeyDown(e) {
console.log(e.keyCode);
if (e.keyCode ===13) {
console.log(this.refs.text.value);
this.refs.text.value = `${this.refs.text.value}\n${this.state.counter++}. `;
e.preventDefault();
e.stopPropagation();
}
}
render() {
const style = {
height: 300,
width: 200
};
return (
<textarea ref="text" onKeyDown={this._onKeyDown} style={style}>
{this.state.text}
</textarea>
);
}
}
ReactDOM.render(
<NumberedTextArea />,
document.getElementById('root')
);