I don't want any space before the input and after the input like " text" and "text " does not allow so I replace the white space but when we copy "text " from notepad and paste over the input and want to remove the space it throws error like "can not read property of undefined reading target".so how to do like when user give space front and back its automatically replace whitespace
const handleKeyDown = (e) => {
if (e.key === " ") {
e.preventDefault();
}
};
const handleChangeWhiteSpace = (e) => {
if (e.target.value.includes(" ")) {
e.target.value = e.target.value.replace(/\s/g, "");
}
};
<MyInput
type="text" style={{width:'240px'}}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
onBlur={formik.handleBlur}
onChange={(e)=>{formik.handleChange(e);handleChangeWhiteSpace()}}
onKeyDown={handleKeyDown}
name="input"
id="input"
autoFocus={false}
autoComplete="off"
/>
using regex the following should work, you can test it at regex101:
e.target.value = e.target.value.replace(/^[ \t]+|[ \t]+$/gm, "");
the cleaner solution would be what sojin suggested
e.target.value = e.target.value.trim()
Replace
const handleChangeWhiteSpace = (e) => {
if (e.target.value.includes(" ")) {
e.target.value = e.target.value.replace(/\s/g, "");
}
};
With this
const handleChangeWhiteSpace = (e) => {
e.target.value = e.clipboardData.getData('Text').trim();
};
To register changes when you paste text inside the text field use the onPaste event
onPaste={handleChangeWhiteSpace}
Final Code
const handleKeyDown = (e) => {
if (e.key === " ") {
e.preventDefault();
}
};
const handleChangeWhiteSpace = (e) => {
e.target.value = e.target.value.trim();
};
<MyInput
type="text" style={{width:'240px'}}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
onBlur={formik.handleBlur}
onPaste={handleChangeWhiteSpace}
onChange={(e)=>{formik.handleChange(e);
handleChangeWhiteSpace()}}
onKeyDown={handleKeyDown}
name="input"
id="input"
autoFocus={false}
autoComplete="off"
/>
use normalize={(value, prevVal, prevVals) => value.trimStart()} after rules{[]} in form.item
for prevent whitespace before value in antd input
for example check selected code in image ==>
enter image description here
To dont allow to send only spaces you can use normalize prop
<MyInput
type="text" style={{width:'240px'}}
normalize={(value) => value.trimStart()}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
and then you can remove all of the spaces inside of this function
const onFinish = (values) => {
//values.input1=values.input1.trim() or whatever
}
btw this function you can use to remove all the spaces
const remove = (str) => str.trim().replace(/\s\s+/g, ' ')
Related
I have a form. In the form I getting brandName, supplierName, and date of expiry from the user.
I am usinf TextField from mui library and submit button.
I want to disable submit button on empty form fields and enable it when user filled all the inputs
here is my code for declaring useStates
const[brandName, setBrandName] = useState("");
const[supplierName, setSupplierName] = useState("");
const[expiryDate, setExpiryDate] = useState(null);
const[brandNameError, setBrandNameError] = useState(false);
const[supplierNameError, setSupplierNameError] = useState(false);
const[expiryDateError, setExpiryDateError] = useState(false);
const[submitButton, setSubmitButton] = useState(true);
and here is all function which i used to validate my inputs
// checking brandName Error
const brandNameValidateOnBlur = ()=>{
if(brandName === ""){
setBrandNameError(true);
}
}
// checking supplier name error
const supplierNameValidateOnBlur = ()=>{
if(supplierName === ""){
setSupplierNameError(true);
}
}
// checking expiry date
const expiryDateValidateOnBlur = ()=>{
if(expiryDate === ""){
setExpiryDateError(true);
}
}
// now checking all inputs again if all inputs are good then
// button should be enabled
const checkAllInputs = ()=>{
if(brandName !== "" && supplierName !== "" && expiryDate !== ""){
setSubmitButton(false);
}else{
setSubmitButton(true);
}
}
and here is the rest of code
<TextField fullWidth id="productName" label="Product Name"
value={brandName.toLowerCase()} variant="outlined"
onChange={(data)=>{setBrandName(data.target.value.toUpperCase());checkAllInputs()}}
onBlur={brandNameValidateOnBlur}
onFocus={()=>setBrandNameError(false)}
error={brandNameError}
helperText = {brandNameError ? "Enter Brand Name" : ""}
/>
<TextField id="supplierName"
label="Supplier Name"
value={supplierName.toLowerCase()} variant="outlined"
onBlur={supplierNameValidateOnBlur}
onFocus={()=>setSupplierNameError(false)}
error={supplierNameError}
helperText={supplierNameError ? "Enter Supplier Name " : ""}
onChange={(data)=>{setSupplierName(data.target.value.toUpperCase());checkAllInputs()}} />
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DesktopDatePicker
label="Date Expiry"
inputFormat="MM/DD/YYYY"
value={expiryDate}
onBlur={expiryDateValidateOnBlur}
onFocus={()=>setExpiryDateError(false)}
error={expiryDateError}
helperText={expiryDateError ? "Enter Expiry Date ": ""}
onChange={(selectedDate)=>
{setExpiryDate(selectedDate.format("MM/DD/YYYY"));checkAllInputs()}}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
<Button type='button' variant='contained' id="submitButton" disabled={submitButton}
style={{backgroundColor:'orangered'}} onClick={addData}>Add Data</Button>
now problem is when i enter a single word my useState is updated but my checkAllInputs not working as i want to be like if i enter a word my checkAllInputs method runs before setting of state as i enter second entry then it works like I want to be so i did not know what i am doing wrong
I TRY useEffect hook like that
useEffect(()=>{
checkAllInputs();
},[brandName, supplierName, expiryDate]);
its working fine as i accepted but I read that it should be a expensive to use useEffect
and an other approach which i use
const checkAllInputsWithDom = ()=>{
let brandNameEntry = document.getElementById("brandName").value;
let supplierNameEntry = document.getElementById("supplierName").value;
let expiryDateEntry = document.getElementById("expiryDate").value;
if(brandNameEntry !=="" && supplierNameEntry !== "" && expiryDateEntry !== ""){
setSubmitButton(false);
}else{
setSubmitButton(true);
}
}
it is working out of box but I thing in react this is against react principles to direct manipulate
dome elements can I do it with out using useeffect hook like only with my metohd and one more thing
this did not set expiryDate error in date field
As long as you're keeping the input values in state, you don't need another variable storing the button state as well. You can calculate it at render time. (Read more about avoiding redundant state here.)
You could do something like this:
const Component = () => {
const[brandName, setBrandName] = useState("");
const[supplierName, setSupplierName] = useState("");
const[expiryDate, setExpiryDate] = useState("");
const disabled = brandName.length === 0 && supplierName.length === 0 && expiryDate.length === 0
return (
<>
<input value={brandName} onChange={(e) => setBrandName(e.target.value)}/>
<input value={supplierName} onChange={(e) => setSupplierName(e.target.value)}/>
<input value={expiryDate} onChange={(e) => setExpiryDate(e.target.value)}/>
<button disabled={disabled}>Button</button>
</>
)
}
here is the link for codesandbox I have a suggestion for you to refactor this 6 use States with just one useState as an object having all the values like the following:
const initialValues = {
brandName: "",
supplierName: "",
expiryDate: "",
brandNameError: "",
supplierNameError: "",
expiryDateError: ""
};
and then update it with a generic handleInputChange like below:
const handleInputChange = (e) => {
//const name = e.target.name
//const value = e.target.value
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
let isEmpty = Object.values(values).some((x) => x === "");
console.log(isEmpty);
setIsDisabled(isEmpty);
};
FOR YOUR SOLUTION
You will have to just check all the values and just create a boolean with isDisabled so when all of those values are empty then it will only set to false.
I have created a code snippet for you, it needs some improvement but it will serve your purpose. Link already at the top and here as well
as suggested by Eduardo Motta de Moraes
I used this for making my button enabled after all inputs validate
const disabled= brandName.length === 0 || supplierName.length === 0 || expiryDate.length === 0;
this solve my problem
thanks for Eduardo Motta de Moraes for this
In the form in the phone field, I use a mask based on the Imask library.
I am trying to make it when focusing with both the mouse or the tab on the field, a full mask with brackets appears, and the cursor is set to the initial input position. There is a problem here: either an incomplete mask appears, or only +38, or the cursor moves to the end due to a taboo on the field.
I can't clear the phone field after submitting the form, I get warning:
Element value was changed outside of mask. Syncronize mask using
mask.updateValue() to work properly.
const phone = document.querySelector('.phone');
const name = document.querySelector('.name');
const form = document.querySelector('#form');
if (phone) {
phone.onfocus = () => {
newIMask(phone)
}
form.addEventListener('keydown', function(e) {
if (e.key == 'Tab') {
if (phone.value === '') {
let tabMask = IMask(
phone, {
mask: '+38( 000) 000-00-00',
lazy: false
});
}
}
});
}
function newIMask(phone) {
let phoneMask = IMask(
phone, {
mask: '{+38} (000) 000-00-00',
lazy: false
});
phone.value = phoneMask.unmaskedValue; //если закомментировать, то по табу курсор сместиться вконец
}
document.getElementById("form").addEventListener('submit', function(e) {
e.preventDefault();
phone.value = "";
window.open('mailto:mail#example.com?name=' + name.value + '&body=' + phone.value);
});
<script src="https://unpkg.com/imask"></script>
<form id="form">
<input type="text" name="name" class="name">
<input type="tel" name="phone" class="phone">
<input type="submit" value="Отправить">
<form>
UPD
With this insertion of the code, I sort of solve the issue with the tab
const form = document.querySelector('#form');
form.addEventListener('keydown', function (e) {
if(e.key == 'Tab') {
if(phone.value === '') {
let tabMask = IMask(
phone, {
mask: '+38( 000) 000-00-00',
lazy: false
});
}
}
});
but each digit is entered with a warring:
Warring: Element value was changed outside of mask. Syncronize mask
using mask.updateValue() to work properly.
and the phone field is not cleared when sending.
Could you help me with finding the right solution?
This warning happens because you need to configure the Imask and inside the configuration have functions which catch input value.
Use prepare (value, masked) option for preprocessing input and commit
(value, masked) option for postprocessing after UI is deactivated
And for work correctly need only to use mask.updateOptions to update options.
const phone = document.querySelector('.phone');
const name = document.querySelector('.name');
const form = document.getElementById('form');
const maskOptions = {
mask: '',
lazy: false,
placeholderChar: '#',
overwrite: true,
prepare: value => value, // onChange event
commit: value => (phone.value = value), // set value to phone number
};
// Init IMask
const mask = IMask(phone, maskOptions);
if (phone) {
form.addEventListener('keydown', e => {
if (e.key == 'Tab') {
// Update options "mask" after pressed Tab key
mask.updateOptions({
mask: '{+38}(000)000-00-00',
});
}
});
}
phone.addEventListener('focus', () => {
// Update options "mask" after focused
mask.updateOptions({
mask: '{+38}(000)000-00-00',
});
});
form.addEventListener('submit', e => {
e.preventDefault();
console.log('sending phone number ', phone.value);
// Update options & clear up values after submit form
mask.updateOptions({
mask: '',
commit: (value, masked) => {
value = '';
masked._value = '';
},
});
phone.blur();
name.value = '';
window.open(
'mailto:mail#example.com?name=' + name.value + '&body=' + phone.value
);
});
<script src="https://unpkg.com/imask"></script>
<form id="form">
<input type="text" name="name" class="name" >
<input type="tel" name="phone" class="phone">
<input type="submit" value="Отправить">
<form>
I have input feild which takes a input (interest) from user and after hitting the Enter key adds the interest to the interests array. Then the elements in this array are displayed on screen via the Domain component as the user goes on adding. The Domain component contains an icon X (cross) which on click should delete the selected/clicked element from the array. Right now the last element in the array is getting removed after clicking.
How can I resolve this? Here is the code:
function Demo() {
const [interest, setinterest] = useState("");
const [interests, setinterests] = useState([]);
const domainSelection = (e) => {
if (e.key === "Enter" && interest.length > 0) {
setinterests((interests) => [...interests, interest]);
setinterest("");
}
};
const RemoveDomain = (e) => {
var arr = [...interests];
var index = arr.indexOf(e.target.value);
arr.splice(index, 1);
setinterests(arr);
};
const Domain = ({ interest }) => {
return (
<span>
{interest}
<span>
<X onClick={RemoveDomain} />
</span>
</span>
);
};
return (
<div>
<Input
name="intersts"
type="text"
placeholder="eg Machine Learning .. "
value={interest}
required={true}
onChange={(e) => setinterest(e.target.value)}
className="interest-input inputs"
onKeyDown={domainSelection}
/>
{interests.map((interest, i) => (
<Domain
interest={interest}
// Prevent duplicate keys by appending index:
key={interest + i}
/>
))}
</div>
);
}
export default Demo;
I think e.target.value is undefined.
Use Filter, This might help
const RemoveDomain = (value) => {
var arr = interests.filter((item) => item !== value);
setinterests(arr);
};
const Domain = ({ interest }) => {
return (
<span>
{interest}
<span>
<X onClick={() => RemoveDomain(interest)} />
</span>
</span>
);
};
I have a webpage written in React (but it should not be strictly relevant to that question) that is composed by several inputs, let's call them Name, Surname and Code.
To work quickly, the insertion of the code is done with a Barcode Scanner that works as external keyboard. My idea is that if some field is focused, the keypress is inserted in the focused input but, in case no input is focused, I want to automatically focus and fill the Code input.
Is there a way to that it easily?
let inputName = document.querySelector('input[name="name"]');
let inputSurname = document.querySelector('input[name="surname"]');
let inputCode = document.querySelector('input[name="code"]');
let focusedInput = null;
[inputName, inputSurname, inputCode].forEach((input) => {
input.addEventListener('blur', () => {
focusedInput = null;
});
input.addEventListener('focus', () => {
focusedInput = input;
});
});
document.body.addEventListener('keypress', () => {
if (focusedInput == null) {
inputCode.focus();
}
});
<div>
<label>Name</label>
<input type="text" name="name" />
</div>
<div>
<label>Surname</label>
<input type="text" name="surname" />
</div>
<div>
<label>Code</label>
<input type="text" name="code" />
</div>
const surnameInput = document.getElementById('surname-input');
... (= do for all inputs)
let activeInput;
surnameInput.onFocus = () => { activeInput = surnameInput };
...
surnameInput.OnBlur = () => { activeInput = undefined };
...
document.addEventListener('keypress', (ev) => {
const input = activeInput ?? codeInput;
input.value += valueOftheKey;
}
You'd obviously have to evaluate if the key that was pressed has a value which you can add to the input, but I think this should give you an Idea of what to do. I haven't tried it out though, so it might not completely work.
Also: I'm not sure if it's the most efficient way, but it's an option.
EDIT: Answer by Kostas is better ;) except for the null...you should use undefined
I'm trying to prevent my TextInput from getting values like $,%,^,&,(,) etc. Basically my TextInput should allow letters only. My approach is as follows. But still i'm able to input these other characters. How can i prevent special characters from the TextInput
restrict(event) {
const regex = new RegExp("^[a-zA-Z]+$");
const key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
if (!regex.test(key)) {
event.preventDefault();
return false;
}
}
<TextInput
underlineColorAndroid='transparent'
allowFontScaling={false}
style={styles.questionText}
onKeyPress={e => this.restrict(e)}
value={firstNameState}
/>
the onKeyPress event on android does not work very well.
That is why I have chosen to use a method that eliminates these characters and then save it wherever you want, just as it might change the state of your field.
restrict = text => text.replace(/[`~0-9!##$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '')
I have to block special characters by this line of code.
var format = /[!##$%^&*()_+-=[]{};':"\|,.<>/?]+/;
if(format.test(string)){ }
You may define your OnChange event handler using your regex, where you will check if the input string matches your regex with /^[^!-\/:-#\[-`{-~]+$/.test(text):
const {useState} = React;
const App = () => {
const [value, setValue] = useState("");
const onChange = e => {
const input = e.currentTarget.value;
if (/^[^!-\/:-#\[-`{-~]+$/.test(input) || input === "") {
setValue(input);
}
};
return (
<div className="App">
<input
value={value}
onChange={onChange}
underlineColorAndroid='transparent'
allowFontScaling={false}
/>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>