So I'm trying to enable a button as soon as I enter a value in the TextField. The only way it is enabled is if i click outside the TextField after I put a value inside the Textfield. I know i'm missing something small but I still haven't found the correct way. I would appreciate your advice .
The code for the TextField and LoadingButton
the Window
I have included only the relevant part.
import { useState } from "react";
export default function Home() {
const [name, setName] = useState("");
const hanldeUserInput = (e) => {
setName(e.target.value);
};
return (
<Dialog>
<TextField onChange={hanldeUserInput} value={name} />
<LoadingButton disabled={name === ""}>Save</LoadingButton>
</Dialog>
);
}
You could keep track of the current value inside your textfield and store it inside the state.
const [txtFieldValue, setTxtFieldValue] = useState<string>('')
and write a function which is triggered on the change event in your textfield:
function handleTxtFieldChange(event) {
if (event.target.id === 'myTextFieldId') {
setTxtFieldValue(event.target.value)
}
}
And then you can adjust your textfield:
<TextField
id={'myTextFieldId'}
// ... all your other stuff
onChange={(event) => {
handleTxtFieldChange(event)
}}
/>
and you can then use the set txtFieldValue to render the button like:
{txtFieldValue != '' ? <Button /> : <></>}
or if you just want to disable it you can just use the
txtFieldValue != ''
as a boolean.
Related
I have an issue with my code below. When you click the add code button, it adds the code to the monaco code editor which is great. However, if you type some more code in the editor or erase whats currently there and then press the 'Add code' button, nothing is added. It's just blank.
Is there a way to whenever that 'Add code' button is clicked it clears everything in the editor and just adds the setAddCode state when the button is clicked?
And here is the code:
import { useState, useRef, useEffect } from "react";
import Editor from "#monaco-editor/react";
export default function IndexPage() {
const [input, setInput] = useState("");
const [addCode, setAddCode] = useState("# code goes here");
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
setInput((editorRef.current = editor));
editorRef.current = editor;
}
return (
<div>
<div className="code-editor">
<Editor
width="100vh"
height="40vh"
theme="vs-dark"
fontSize="14"
defaultLanguage="python"
defaultValue=""
value={addCode}
onMount={handleEditorDidMount}
/>
</div>
<br />
<button onClick={() => setAddCode("print('Hello World!')")}>
Add code
</button>
</div>
);
}
The way the Editor component is set up, it will only change the value in the editor if you pass a different value prop. It's probably doing something similar to the following:
const Editor = ({ value }) => {
const [codeToDisplay, setCodeToDisplay] = useState(value);
useEffect(() => {
setCodeToDisplay(value);
}, [value]);
// etc
In your parent component, when you call setAddCode("print('Hello World!')") the first time, that'll result in the child component seeing a difference in how it was called - the value prop changed - so it'll know that there's something different to display, and update its own internal state appropriately. When you press the button again, the addCode value will stay the same - the Editor component doesn't see any difference, so it won't update.
To fix it, you can listen for changes from inside Editor by using its onchange prop to update the state in the parent component when the code inside the editor changes - that way, when you click the button later, the prop will be different, and the editor will know to update its internal state.
export default function IndexPage() {
const [input, setInput] = useState("");
const [codeValue, setCodeValue] = useState("# code goes here");
const editorRef = useRef(null);
function handleEditorDidMount(editor, monaco) {
setInput((editorRef.current = editor));
editorRef.current = editor;
}
return (
<div>
<div className="code-editor">
<Editor
width="100vh"
height="40vh"
theme="vs-dark"
fontSize="14"
defaultLanguage="python"
defaultValue=""
value={codeValue}
onChange={(newValue) => { setCodeValue(newValue); }}
onMount={handleEditorDidMount}
/>
</div>
<br />
<button onClick={() => setCodeValue("print('Hello World!')")}>
Add code
</button>
</div>
);
}
I have the following component which uses the TextField:
const BarcodeField = ({disableEnter, ...rest})=>{
return <TextField {...(disableEnter && { onKeyDown: {(e)=>e.key === 'Enter' && e.preventDefault()} })} {...rest}>
}
and I consume it somewhere else as follows:
import BarcodeField from '...etc path'
const PosCalculator = ()=>{
return (
<>
<BarcodeField disableEnter fullWidth />
</>
)
}
I want to set the BarcodeField from the PosCalculator component focused forever, even if the user clicked outside the component on the body of the page.
But how?
I want also to be able to toggle the force focus state based on a condition
I think you can try this:
const inputRef = useRef();
inputRef.current.focus() //inside useEffect
This is just an idea
Hello I am trying to make a component out of react bootstrap toggle group buttons using formik, the component works and pass the data correctly, but it just won't reset the buttons to "no button pressed at all" when I reset the form (the last pressed button is still checked,although the value of the togglebuttons being null(as intended)).
import React, { useState, useEffect } from "react";
import "./style.scss";
import { ToggleButtonGroup, ToggleButton } from "react-bootstrap";
const ToggleButtonsGrp = (props) => {
const [toggleValue, setToggleValue] = useState(props.state);
useEffect(() => {
props.formik.setFieldValue(props.formName, JSON.parse(toggleValue));
props.formik.setFieldTouched(props.formName);
}, [toggleValue]);
return (
<ToggleButtonGroup
id="toggleButtonGroup"
name="toggleButtonGroup"
className="toggleButtonGroup"
onChange={(value) => setToggleValue(value)}
>
{props.toggleButtons.map((opt) => (
<ToggleButton
key={opt.name}
id={`toggle-${opt.name}`}
type="radio"
name={props.formName}
className={`toggleBtn ${
opt.value === toggleValue ? "toggleBtn-Off" : "toggleBtn-active"
}`}
checked={opt.value === toggleValue}
value={opt.value}
>
{opt.name}
</ToggleButton>
))}
</ToggleButtonGroup>
);
};
tried to add a useEffect like this:
const [update,SetUpdate] = useState(0);
useEffect(() => {
if(!props.state) //when it resets or first time
setUpdate(update+1) //this would force a rerender
}, [props.state]);
It didn't solve the problem so I removed this.
The external form looks like this:
<Formik
initialValues={someFieldName:null}
onSubmit={(values, { resetForm }) => {
...//some logic
resetForm()
...
}}
>
{(formik)=>(
...
<ToggleButtonsGrp
toggleButtons={SomeButtons}
formName="someFieldName"
state={formik.values.someFieldName}
formik={formik}
/>
..
)}
</Formik>
while SomeButtons built like:
[{
name:"someName",
value:"someValue"
},
{
name:"someName2",
value:"someValue2"
}]
In the end I don't need to reset the form, leaving it if someone wants a challenge.
Sadly can't close the question myself.
I am using react-admin and react-rrule-generator (https://github.com/Fafruch/react-rrule-generator). Create / Adding records is working fine while using rrule widget. But whenever I try to edit a record, the widget should have its values automatically filled based on the record's values. But the value is always the default one provided by the widget itself. Here is my code:
main_file.jsx
export const JobCreate = (props) => {
return (
<Create {...props}>
<SimpleForm>
<CustomRRuleInput name="recurrency" label="Recurrency" />
</SimpleForm>
</Create>
)
}
recurrency_field.jsx
export const CustomRRuleInput = (props) => {
const {
input: { onChange },
meta: { touched, error },
} = useInput(props)
return (
<Labeled label={props.label}>
<RRuleGenerator
onChange={onChange}
name={props.name}
/>
</Labeled>
)
}
If I add value={props.record.recurrency} in RRuleGenerator component, I can't change values because I kind of fixed / hardcoded its value which is constant even if I try to change them. If this widget had a prop called defaultValue then it would have worked out!
How can I achieve this?
If you check closely the documentation's Inputs/Writing your own input part you will notice that custom input compoenents using either useField or useInput hooks still receive the source prop which is passed inside the input as part of the hook parameters.
Try this:
Inside main_file.jsx
<CustomRRuleInput source="recurrency" label="Recurrency" />
Inside recurrency_field.jsx
const {
input: { name, onChange },
meta: { touched, error },
} = useInput(props)
return (
<Labeled label={props.label}>
<RRuleGenerator
onChange={onChange}
name={name}
/>
</Labeled>
)
Never mind I did it! I can use this for creation as well as updating records. I also used rrule library for converting rrule to human readable text which gets displayed in TextInput field just below RRule widget. The text dynamically changes when you change data in RRule widget.
recurrency_field.jsx
import RRuleGenerator from "react-rrule-generator"
import React, { useState } from "react"
import { useInput, Labeled, TextInput } from "react-admin"
import { rrulestr } from "rrule"
export const CustomRRuleInput = (props) => {
const record = props.record
const {
input: { onChange },
} = useInput(props)
const [state, setState] = useState(record[props.name])
return (
<>
<Labeled label={props.label}>
<RRuleGenerator
onChange={(val) => {
setState(val)
onChange(val)
}}
value={state}
name={props.name}
/>
</Labeled>
<TextInput
fullWidth
disabled
label={"RRule Text"}
value={state ? rrulestr(state).toText() : ""}
/>
</>
)
}
main_file.jsx
<CustomRRuleInput name="recurrency" label="Recurrency(r rule)" />
I've tried creating a custom hook, following the examples an article about handling forms in react using hooks. I should also add I'm very new to react.
This is the content of hooks/useInput.js:
import { useState } from "react";
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(event) {
console.log(event.target.name);
console.log(event.target.value);
setValue(event.target.value);
}
return [value, handleChange];
}
export default useInput;
In a component I have the following:
import useInput from "hooks/useInput";
export default function Address(props) {
const [fullName, setFullName] = useInput("");
return (
<FormControl fullWidth>
<CustomInput
required
labelText="Full name"
id="fullName"
formControlProps={{
fullWidth: true
}}
value={fullName}
onChange={setFullName}
/>
</FormControl>
);
}
When I try to input some text (or even if I try to change the default state), nothing happens.
Any breakpoint that I set in useInput.js are not hit and no logging appears in the console.
Where am I going wrong?
If you want to see your current input value with a button click you can see like this. I didn't even change your userInput.js file. I can see the updated value by doing this and console as well.
export default function Address(props) {
const [fullName, setFullName] = useInput("");
return (
<>
<input
placeholder="Name"
value={fullName}
onChange={setFullName}
/>
<button onClick={() => {
console.log(fullName);
}}>Submit</button>
</>
);
}
Since I don't know about your CustomInput, I have written this with default input and button. Please check your CustomInput correctly. Because default input is working.