Preventing users from entering non-digits in input text field with React native - event-handling

I dont want to allow user to type the alphabets in the input as per the same functionality of keypressevent of jquery/javascript.

you should use a TextInput Component white the prop keyboardType = {"number-pad"}
import { TextInput } from "react-native";
then use it as
<TextInput
keyboardType = {"number-pad"}
// add more props ...
/>
for all the props you can add see this link

Try replace method in JS by replacing non alphabet character with empty string.
Code
import React, { Component } from 'react';
import { AppRegistry, TextInput } from 'react-native';
export default class UselessTextInput extends Component {
constructor(props) {
super(props);
this.state = { inputText: '' };
}
onChanged (text) {
this.setState({
inputText: text.replace(/[A-Za-z]/g, ''),
});
}
render() {
return (
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1, marginTop: 200}}
onChangeText={(text)=> this.onChanged(text)}
value={this.state.inputText}
/>
);
}
}
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);

You can check by using the isNaN() JS built-in function in your input to prevent the user to type alphabet letters;
const Text = "hello";
const Number = "1234";
console.log(isNaN(Text)) // true
console.log(isNaN(Number)) // false

Related

Register is not a function when passing as a prop?

I use react-hook-form for the first time. I was reading the docs and followed along. Likewise, I already laid out my components and styled them. Now I am trying to alert the data out after the form submits.
This is the ContactForm
import React, { useState } from 'react';
import * as S from './style';
import { PrimaryButton } from '#element/Button';
import TextInput from '#element/TextInput';
import { useForm } from 'react-hook-form';
export const ContactForm = () => {
const { register, handleSubmit } = useForm();
const [firstName, setFirstName] = useState('');
const onSubmit = (data) => {
alert(JSON.stringify(data));
};
return (
<S.ContactFormWrapper onSubmit={handleSubmit(onSubmit)}>
<TextInput
name={'firstName'}
label={'First Name'}
state={firstName}
setState={setFirstName}
placeholder={'John'}
type={'text'}
width={'48%'}
options={{
maxLength: '20',
minLength: '2',
required: true,
}}
register={register}
/>
<PrimaryButton type={'submit'} text={'Send Message'} />
</S.ContactFormWrapper onSubmit={handleSubmit(onSubmit)}>
)
}
This is my Custom created TextInput
import React, { useEffect, useState } from 'react';
import * as S from './style';
const TextInput = ({
name,
label,
placeholder,
state,
setState,
type,
width,
register,
options,
}) => {
const [isActive, setIsActive] = useState(false);
return (
<S.TextInputWrapper inputWidth={width}>
<S.Label htmlFor={name} isActive={isActive}>
{label}
</S.Label>
<S.Input
placeholder={placeholder}
type={type}
name={name}
id={name}
{...register(name, options)}
onChange={(event) => setState(event.target.value)}
onFocus={() => setIsActive(true)}
onBlur={() => setIsActive(false)}
/>
</S.TextInputWrapper>
);
};
export default TextInput;
Error Message
TypeError: register is not a function {...register(name, options)}
I was searching on StackOverflow there was a Post, but the Answer was confusing for me and the Questioner Code was much different than mine. Because I think the error occurred because I use styled-components, and it is nested deep. I am confused because I was reading the docs and followed along.
If I spread the Error says, register is not a function else if I not spread it then the error is ... spread is required.
Hopefully you can bring light to my confusion.
Kind regards
Kuku
The simplest solution is to take advantage of react hook form's context and use the useFormContext hook.
Input Component
import { useFormContext } from "react-hook-form";
const TextInput = ({ name, options }) => {
const { register } = useFormContext();
return (
<S.Input
name={name}
{...register(name, options)}
/>
</S.TextInputWrapper>
);
};
Remove the input register function from the parent form
export const ContactForm = () => {
...other functions
return <TextInput name={'firstName'} options={{maxLength: '20' }} />;
}
An even simpler solution is to let react-hook-form control the form values and use the useController hook or Controller component.
import { useController } from "react-hook-form";
const TextInput = ({ name, options }) => {
const { field } = useController({ name, rules: options });
return <S.Input name={name} {...field} />
};
You can also get the input states using the useContoller hook to reduce the number of events your using.
import { useController } from "react-hook-form";
const TextInput = ({ name, options }) => {
const {
field,
fieldState: { error, invalid, isDirty, isTouched }
} = useController({ name, rules: options });
};
useFormContext is a good solution explained by #Sean W
Here is another solution without useFormContext, you can use register as usual instead of passing it as a prop. You just have to forward the ref of your TextInput.
👉🏻 You can find an instance here: https://stackoverflow.com/a/68667226/4973076

Toggle text on pressing the button in react native

I am new to react native and I want to toggle text on pressing the button, but the problem is that when I press button the text changed but when I press it again nothing happen. Here is my code:
enter image description here
When you use react hooks, you configure the component to do things after it renders. If you declare a variable outside of a useState hook, it will be reset on every render. This is what happens to your isTrue variable. Read more about the rules of hooks here.
You also don't need to evaluate isTrue == true, you can just call isTrue, it will have the same effect.
export default function App() {
var startingText = "First text"
const [isTrue, setIsTrue] = useState(true)
const [outputText, setOutputText] = useState(startingText)
function textChange() {
setIsTrue(!isTrue)
return isTrue ? startingText : setOutputText("Text Changed")
}
return(
<View>
<Text>{outputText}</Text>
<Button title="Change Text" onPress={textChange}/>
</View>
)
}
You can simplify the code even further by removing the boolean variable and moving the logic of selecting which text value to set in the textChange function directly using a ternary operator.
export default function App() {
var startingText = ""
const [outputText, setOutputText] = useState(startingText)
function textChange() {
setOutputText(outputText === startingText ? "Text Changed" : startingText)
}
return(
<View>
<Text>{outputText}</Text>
<Button title="Change Text" onPress={textChange}/>
</View>
)
}
Try to change the function on:
const [tooggle, setToggle] = useState(false);
function textChange() {
setToggle(!tooggle);
return isTrue === tooggle
? setOutputText('first')
: setOutputText('second');
}
Example of toggle:
import React, { useState } from 'react';
import { Button, View, Text } from 'react-native';
const ToggleFunction = () => {
const [outPutText, setOutputText] = useState('first');
const [tooggle, setToggle] = useState(false);
function textChange() {
setToggle(!tooggle);
return tooggle ? setOutputText('first') : setOutputText('second');
}
return (
<View
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}
>
<Text>{outPutText}</Text>
<Button title="button" onPress={textChange} />
</View>
);
};
export { ToggleFunction };

How to Decorate a text with Modifier in Draft.js

I'm trying to decorate some text, but instead of making the process managed by a regex strategy, it should be the results of an ajax call to specify which peace of text to decorate. Is it possible to use any method from Modifier library? My idea is to call something inside the onChange method and modify the editorstate.
Any idea would be appreciated.
My solution uses a custom decorator and a dynamic regex, this combination might help achieve the effect you are hoping for.
Code structure follows this example to decorate tweets in draftjs.
You can replace the string array (var arr = ["one", "two", "three"]) in the code with an ajax call.
import React, { Component } from 'react';
import { Editor, EditorState, CompositeDecorator } from 'draft-js';
const styles = {
handle: {
color: 'black',
backgroundColor: '#FF7F7F',
direction: 'ltr',
unicodeBidi: 'bidi-override',
},
};
// arr can be accessed from an ajax call
var arr = ["one", "two", "three"]
const HANDLE_REGEX = new RegExp("(?:[\\s]|^)(" + arr.join("|") + ")(?=[\\s]|$)", 'gi')
function handleStrategy(contentBlock, callback, contentState) {
findWithRegex(HANDLE_REGEX, contentBlock, callback);
}
function findWithRegex(regex, contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
}
const HandleSpan = (props) => {
return (
<span
style={styles.handle}
data-offset-key={props.offsetKey}
>
{props.children}
</span>
);
};
class App extends Component {
constructor(props) {
super(props);
const compositeDecorator = new CompositeDecorator([
{
strategy: handleStrategy,
component: HandleSpan,
}
]);
this.state = {
editorState: EditorState.createEmpty(compositeDecorator),
};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<div className="container-root">
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
placeholder="Write..."
ref="editor"
spellCheck={true}
/>
</div>
);
}
}
export default App;

How can I use props to auto-populate editable redux-form fields in React?

I'm new to React so I've tried to show as much code as possible here to hopefully figure this out! Basically I just want to fill form fields with properties from an object that I fetched from another API. The object is stored in the autoFill reducer. For example, I would like to fill an input with autoFill.volumeInfo.title, where the user can change the value before submitting if they want.
I used mapDispatchtoProps from the autoFill action creator, but this.props.autoFill is still appearing as undefined in the FillForm component. I'm also confused about how to then use props again to submit the form. Thanks!
My reducer:
import { AUTO_FILL } from '../actions/index';
export default function(state = null, action) {
switch(action.type) {
case AUTO_FILL:
return action.payload;
}
return state;
}
Action creator:
export const AUTO_FILL = 'AUTO_FILL';
export function autoFill(data) {
return {
type: AUTO_FILL,
payload: data
}
}
Calling the autoFill action creator:
class SelectBook extends Component {
render() {
return (
....
<button
className="btn btn-primary"
onClick={() => this.props.autoFill(this.props.result)}>
Next
</button>
);
}
}
....
function mapDispatchToProps(dispatch) {
return bindActionCreators({ autoFill }, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(SelectBook);
And here is the actual Form where the issues lie:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { createBook } from '../actions/index;
class FillForm extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
onSubmit(props) {
this.props.createBook(props)
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
const { fields: { title }, handleSubmit } = this.props;
return (
<form {...initialValues} onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<input type="text" className="form-control" name="title" {...title} />
<button type="submit">Submit</button>
</form>
)
}
export default reduxForm({
form: 'AutoForm',
fields: ['title']
},
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}), {createBook})(FillForm)
I think you're mixing up connect and reduxForm decorators in the actual form component. Currently your code looks like this (annotations added by me):
export default reduxForm({
// redux form options
form: 'AutoForm',
fields: ['title']
},
// is this supposed to be mapStateToProps?
state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
}),
/// and is this mapDispatchToProps?
{createBook})(FillForm)
If this is the case, then the fix should be as simple as using the connect decorator as it should be (I also recommend separating this connect props to their own variables to minimize confusions like this):
const mapStateToProps = state => ({
initialValues: {
title: state.autoFill.volumeInfo.title
}
})
const mapDispatchToProps = { createBook }
export default connect(mapStateToProps, mapDispatchToProps)(
reduxForm({ form: 'AutoForm', fields: ['title'] })(FillForm)
)
Hope this helps!

material-ui textfield with japanese

Excuse my poor English.
'TextField' of material-ui have problem with japanese input.
when use it inside 'Dialog' tag.
First letter is determined without consideration.
for example, entering 'da' should be 'だ', 'pa' should be 'ぱ'.
but it become 'dあ' and 'pあ' because first letter is determined automatically.
when first letter is entered, it should be suspended
until second letter inputted.
does anyone have idea?
import React, { Component } from 'react';
import Dialog from 'material-ui/Dialog';
import TextField from 'material-ui/TextField';
export default class MyModal extends Component {
constructor(props) {
super(props);
this.state = {
question: '',
};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange(event) {
this.setState({
question: event.target.value,
});
}
render() {
return (
<Dialog
open
>
<TextField
value={this.state.question}
onChange={this.onInputChange}
/>
</Dialog>
);
}
}
I think it's a material-ui bug. I found 2 solutions to work around it.
1: Don't put value state of TextField in Dialog. You should write like below:
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
question: '',
};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange(event) {
this.setState({
question: event.target.value,
});
}
render() {
return (
<TextField
value={this.state.question}
onChange={this.onInputChange}
/>
);
}
}
export default class MyModal extends Component {
render() {
return (
<Dialog
open
>
<MyForm />
</Dialog>
);
}
}
2; Or you can extend material-ui TextField with a little fix. This way is pretty dangerous. But it works fine for me now. (I'm using material-ui 0.15.4)
export default class FixedTextField extends mui.TextField {
handleInputChange = (event) => {
if (this.props.onChange) this.props.onChange(event, event.target.value);
}
}