I would like to add on a input a thousand separator using React Hooks but I'm not sure how. I have tried the below code so far and is not working.
Can you please point out what could be the issue and how can I implement this?
Thank you.
const MainComponent = () => {
const [value, setValue] = useState(0);
const numberWithComma = () => {
return (+value).toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
}
return (
<div>
<input
type="number"
onChange={numberWithComma}
placeholder="0"
/>
</div>
);
}
You want a controlled form input, so one which gets given a value, and an onInput handler.
You also need it to be a type="text" to allow for the commas to be added, or Chrome will not allow you to set that. However, then to prevent non-numeric chars being added you need another function to strip them out before setting the value.
See the below working snippet:
const {useState} = React;
const MainComponent = () => {
const [value, setValue] = useState(0);
const addCommas = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const removeNonNumeric = num => num.toString().replace(/[^0-9]/g, "");
const handleChange = event =>
setValue(addCommas(removeNonNumeric(event.target.value)));
return (
<div>
<input type="text" value={value} onInput={handleChange} />
</div>
);
};
// Render it
ReactDOM.render(
<MainComponent/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Related
I have an input wuth "ok" button on a page and I want to write a number in my input, then by pressing the button, Input tags should be prepared for me according to the amount of the number I had entered
For example, if I enter the number 4 in my input and then click the OK button, 4 input tags will be created for me.
How can I write this code in react js?
I tried the folloing code but it's not working... .
import {useState} from "react";
const makeInputComponent = () => {
const [numberOfProcess, setNumberOfProcess] = useState(null)
const returnInput = ()=>{
return <input type="text" />
}
const makeInput = () => {
for (let i = 0; i < Number(numberOfProcess); i++) {
returnInput()
console.log(i)
}
}
return (
<div>
<label> enter your number </label>
<input type="text" value={numberOfProcess} onChange={(event)=>setNumberOfProcess(event.target.value)} />
<button onClick={ makeInput } > ok </button>
</div>
)
}
export default makeInputComponent ;
You can try this code.
const [numInputs, setNumInputs] = useState(0)
const createInputs = () => {
const inputArray = []
for (let i = 0; i < numInputs; i++) {
inputArray.push(<input type="text" key={i} />)
}
return inputArray
}
return (
<div>
<input
type="number"
value={numInputs}
onChange={(e) => setNumInputs(+e.target.value)}
/>
<button onClick={createInputs}>OK</button>
{createInputs()}
</div>
)
Solution:
Here is what you can do, take the value from the input and when button is pressed with that input value create a array of that length and then map that array for creating input box.
export default function App() {
const[val,Setval]=useState("")
const[inputbox,Setinputbox]=useState([])
const handleClick=()=>{
const array=new Array(val*1).fill(0)
Setinputbox(array)
}
return (
<div className="App">
<input type="number" value={val} onChange={e=>Setval(e.target.value)}/>
<button onClick={handleClick}>Submit</button>
<div>
{inputbox.map((val,index)=>{
return(
<input key={index} type="text"/>
)
})}
</div>
</div>
);
}
I am following a tutorial exercise and I got the following error
Objects are not valid as a React child
I know this error is related to the object as I am trying to access the object but it needs an individual item of an object but not sure.
Why cannot the map loop over each item in the array?
Following is my code
var template = <h1>Indecision App</h1>;
var app = {
title: 'Indecision App',
subtitle: 'yo',
options: []
}
let count = 0;
function checkSubtitles (subtitle){
if(subtitle){
return <p>{subtitle}</p>
}else{
return undefined
}
}
function reset(){
count = 0;
reRenderApp();
}
function increaseCount(){
count++;
reRenderApp();
}
function onSubmitHandle(e){
e.preventDefault();
const options = e.target.elements.options;
app.options.push(options);
reRenderApp();
e.target.elements.options.value = ''
}
function removeAll(){
app.options = [];
reRenderApp();
}
function reRenderApp(){
var templateTwo = (
<div>
<h1>{app.title}</h1>
{checkSubtitles(app.subtitle)}
<p>Count: {count}</p>
<p>Array Length: {app.options.length > 0 ? app.options.length : '0 Items'}</p>
<ol>
{app.options.map((item)=>{
return <li key={item}>{item}</li>
})}
</ol>
<hr></hr>
<form onSubmit={onSubmitHandle}>
<input type="text" name="options" />
<input type="submit" value="Push to the Array" />
<input type="reset" value="Empty my list" onClick={removeAll} />
</form>
<button onClick={()=>{
increaseCount();
}}>Increase Count</button>
<button onClick={()=>{
reset();
}}>Reset Count</button>
</div>
)
ReactDOM.render(templateTwo, appRoot)
}
var appRoot = document.getElementById('app');
reRenderApp();
<body>
<div id="app"></div>
<script src="https://unpkg.com/react#16.0.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.0.0/umd/react-dom.development.js"></script>
<script src="./app.js"></script>
</body>
</html>
The main problem is, as you mentioned: Objects are not valid as a React child
But, what is happening?
If we go into:
function onSubmitHandle(e){
e.preventDefault();
// Line 1
const options = e.target.elements.options;
app.options.push(options);
reRenderApp();
// Line 2
e.target.elements.options.value = ''
}
So in Line 1, you're pushing options into the options array.
But, then in Line 2, we can notice options has an attribute (so, it's an object)
So, if you change Line 1, from:
const options = e.target.elements.options;
To this:
const options = e.target.elements.options.value;
It'd work.
Also, to check what I'm saying you have 2 options:
option 1: console.log
function onSubmitHandle(e){
e.preventDefault();
const options = e.target.elements.options;
console.log({ options })
app.options.push(options);
reRenderApp();
e.target.elements.options.value = ''
}
option 2: make that option a valid child of react with JSON.stringify()
<ol>
{app.options.map((item, index)=>{
return <li key={index}>{JSON.stringify(item)}</li>
})}
</ol>
You can do
{app.options.length && app.options.map((item)=>{
return <li key={item}>{item}</li>
})}
But you must be sure that "item" here is not an object as you can't render an object
The reason for this is that your options array is going to be filled with elements as you're pushing the input element with the name of "option" into your array - this elements are objects in JS which you can't render out as list items.
Use React State to store anything that's going to change in the UI - in this case your list of options> So rather than doing
var app = {
title: 'Indecision App',
subtitle: 'yo',
options: []
}
let count = 0;
Do:
const [options, setOptions] = React.useState([]);
const [count, setCount] = React.useState(0);
Title and subtitle are probably not going to change, so just put them in h1 & h2 elements - if they are, then use the state pattern again.
Get rid of the two inputs with types of "submit" & "reset" just use normal button elements instead.
You'll also need an onchange event on your input where the text will go in and each time the onchange event is fired (i.e, when a user types) you'll need to save the input text
const [inputText, setInputText] = React.useState('');
const handleChange = (e) => {
const {value} = e.target;
setInputText(value)
}
<input type="text" value={inputText} onChange={handleChange}/>
Then in your onHandleSubmit function, just have
const onHandleSubmit = () => {
setOptions([...options, inputText]);
setInputText('')
}
This should work
This is the button tag and onclick function :
<Button
id="save-btn"
className="btn-save"
disabled={true}
onClick={handleSaveBtnClick}
>
Save
</Button>
const handleSaveBtnClick = () => {console.log("testing")}
I'm using another button to enable/disable this button, this is the code for that button:
const handleEditClick = (index) => {
// this is for input fields and it works fine:
document.querySelectorAll(".card-" + index + " .toggle-edit-input").forEach((field) => {
field.disabled = !field.disabled;
});
// this piece of code does not work:
document.getElementById("save-btn").disabled = false;
if (document.getElementById("save-btn").disabled = false) {
document.getElementById("save-btn").onclick = handleSaveBtnClick;
}
};
if I remove the disabled option then the button works fine but I need it to be disabled unless edit button is clicked.
what could be wrong here ? I have tried most of the methods
Your enable/disable code isn't how you do this with React. Instead of directly manipulating the DOM, you use a flag in your state for the component that determines whether the button is enabled, and you set / clear that flag. When your component renders, render the disabled attribute using the flag, like this (I used button rather than Button, not knowing which of the several libs you're using that gives you a Button component):
const {useState} = React;
function Example() {
const [saveEnabled, setSaveEnabled] = useState(true);
const handleSaveBtnClick = () => {
console.log("testing");
};
return (
<div>
<div>
<button
id="save-btn"
className="btn-save"
disabled={!saveEnabled}
onClick={handleSaveBtnClick}
>
Save
</button>
</div>
<div>
<label>
<input
type="checkbox"
checked={saveEnabled}
onClick={() => setSaveEnabled(f => !f)}
/>
Save enabled
</label>
</div>
</div>
);
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
Obviously, the "Save enabled" checkbox there is just so you can see what happens when the flag is set/cleared. The key things are:
The saveEnabled state flag
Using disabled={!saveEnabled} in Button (button)
You can also use the "old" but good class component approach instead of functional one as suggested before.
In this case you will need something like this:
class Example extends React.Component {
state = {enabled: false}
handleSaveBtnClick = () => {
console.log("testing");
};
handleEnableBtnClick = () => {
console.log(this.state);
let newStatus = !this.state.enabled
this.setState({ enabled: newStatus })
}
render() {
return (
<div>
<div>
<button
id="save-btn"
className="btn-save"
disabled={!this.state.enabled}
onClick={this.handleSaveBtnClick}
>
Save
</button>
</div>
<div>
<label>
<input type="checkbox" checked={this.state.enabled} onClick={this.handleEnableBtnClick} />
Save enabled
</label>
</div>
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I want to fill the inputs value of a form with default values once the modal is opened
I did it with pure javascript using document.getElementById(textId).value='some value as follow:
for(var i=0; i<details_data.length;i++){
let textId='text'+i;
let amountId='amount'+i;
document.getElementById(textId).value=details_data[i].text
}
This worked fine. but I want to know how to do it with React since I don't believe this is a best practice.
what i tried is to set the input value like this:
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
But this woudn't let me change the value of the input. it just set the default value, and when i type in the input the value woudn't change as I want.
This is my code
const [details_data,set_details_data]=useState([
{'text':'','amount':''}
])
// called this function on `onChange` and store the data in `details_data`
function details_handler(e){
let name=e.target.name;
let value=e.target.value;
details_data[this][name]=value;
set_details_data(details_data);
}
JSX:
(In my case user can add inputs as many as he wants,That's why I put the inputs in a the mapping loop)
{
details_data.map((el,index) => {
let textId='text'+index;
let amountId='amount'+index;
return (
<div key={index}>
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
<input name='amount' id={amountId} onChange={details_handler.bind(index)}/>
</div>
);
})
}
useEffect(() => {
if(detailsProps) {
set_details_data(detailsProps);
}
}, [detailsProps])
where your detailsProps (data from the api) will look something like this
detailsProps = [
{'text':'text1','amount':'100'},
{'text':'text2','amount':'200'}
]
onChange Function
const details_handler = (event, index) => {
const items = [...details_data];
items[index][event.target.name] = event.target.value;
set_details_data(items);
}
your view
{
details_data.map((el,index) => {
return (
<div key={index}>
<input name='text' value={el.text} onChange={(e) => details_handler(e, index)}/>
<input name='amount' value={el.amount} onChange={(e) => details_handler(e, index)}/>
</div>
);
})
}
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>