I have component that renders jsx like this
<section>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
</section>
I want this behavior, when I click the button in the first div, the input in the first div will show. Similarly, I click the button in the third div the input in third div will show.
How you do that in react?
If it were me I would make a new component out of:
show input
Lets call it <InputToggler/>
and then it would have a state of inputHidden for its own input and use classes to determine if it should show or not and the button would have an onclick handler to toggle the state of hidden or shown. Here is a pen showing exactly that
http://codepen.io/finalfreq/pen/VKPXoN
class InputToggler extends React.Component {
constructor() {
super();
this.state = {
inputHidden: true
}
}
toggleInput = () => {
this.setState({
inputHidden: !this.state.inputHidden
})
};
render() {
const inputClass = this.state.inputHidden ? 'hide' : '';
const buttonLabel = this.state.inputHidden ? 'show input' : 'hide input'
return (
<span>
<input type="text" className={inputClass} />
<button onClick={this.toggleInput} id={this.props.item.uniqueID}>
{buttonLabel}
</button>
</span>
)
}
}
This is the concept not the exact code.
Each button should have onClick with callback to a function ex. toggleShow
<button id={item.uniqueID} onClick={this.toggleShow.bind(this)}>show input</button>
toggleShow do something like:
toggleShow(e){
var item = e.target.id;
this.setState({inputClassName1: "hide"})
at the same time the input field classname should refer to the state
Note that I omitted the fact that you have multiple objects, you may want to handle their references in arrays.
Related
I am trying to forward input ref text/string data to a function by clicking the button. but I cant forward or pass the data to my function by using button
--questionRef is my ref input data
--answerQuestion is my function
<input ref={questionRef} size="80"></input>
<button type="button" onClick={answerQuestion} >Enter</button>
I tried to use my button for forward the questionRef input to answerQuestion function but it failed. Also it works when I click enter on my keyboard
Pretty simply:
<input ref={questionRef} size="80"></input>
<button
type="button"
onClick={() => answerQuestion(questionRef)}
>Enter
</button>
Eventually, you can include also the onClick event to your function, depends on what you need to do with it:
<input ref={questionRef} size="80"></input>
<button
type="button"
onClick={(e) => answerQuestion(questionRef, e)}
>
Enter
</button>
Based on Junius L. comment:
const questionRef = useRef()
const answerQuestion = () => {
doSomethingWithRef(questionRef) // questionRef is accessible in whole component scope
}
<input ref={questionRef} size="80"></input>
<button
type="button"
onClick={answerQuestion}
>Enter
</button>
I would like to only be able to select a single checkbox and not all or more than one. I would like to use checkbox instead of radio because I can disable it without having to mark another radio
<C.SingleCard>
<h2>Pizza</h2>
<div>
<hr />
<h3>Flavors</h3>
<hr />
</div>
<div>
<h4>Pepperoni</h4>
<input type="checkbox" name='flavor' />
</div>
<div>
<h4>Chicken</h4>
<input type="checkbox" name='flavor' />
</div>
<div>
<h4>Bacon</h4>
<input type="checkbox" name='flavor' />
</div>
<div>
<button>Add</button>
</div>
</C.SingleCard>
Here's the simplest way I can think of:
Put the options in an array and just keep track of the selected index. Set the index to null if the user selected the same index. Use the index parameter of map to set checked=true on the selected box. The onChange callback will trigger when the user selects one of the boxes, you can ignore the event parameter and just pass the index of the box.
const options = ['pepperoni', 'chicken', 'bacon'];
export default function App() {
const [selected, setSelected] = useState(null);
function onChange(i) {
setSelected((prev) => (i === prev ? null : i));
}
function whatDidIPick() {
console.log(options[selected] || 'nothing');
}
return (
<div>
{options.map((o, i) => (
<label key={i}>
{o}
<input
type="checkbox"
checked={i === selected}
onChange={() => onChange(i)}
/>
</label>
))}
<br />
<button onClick={whatDidIPick}>Log what I picked</button>
</div>
);
}
https://stackblitz.com/edit/react-ts-1uwfcq?file=App.tsx
So I am mapping through an array of objects and looking to display on the page when a radio button is selected. For example, if there are two objects in the array, there will be two radio buttons. If you press radio1, it should render form1. If you press radio2, it should hide form1 and show form2.
I created a property called formIndex to keep track of which button is being pressed so that I know which form to call but I'm having trouble implementing.
Current behavior: on page load, both radios appear with no data rendered yet. When I press radio1, it displays both form1 and form2. When I press radio2, it also displays both form1 and form2.
I'm using LitElement in a TypeScript file.
Here is the property I created. Since I'm mapping through an array starting at 0, I initialized this property to -1:
#state()
formIndex: number = -1;
Here is where I am rendering the forms:
protected renderMultipleForms(formConfig: any): TemplateResult {
return html`
${formConfig?.formHeading ? html`<h3>${formConfig.formHeading}</h3>` : ''}
${formConfig.forms?.map((data: any) => html`
<!-- <adc-radio-group>
<adc-radio-button id="radioBtn" label=${data.label} #click="${this.handleClick}"></adc-radio-button>
</adc-radio-group> -->
<!-- RADIOS -->
<input type="radio" id=${data.label} name="paymentRadios" #click="${this.handleClick}">${data.label} <br />
<!-- RENDERING FORMS -->
<p id=${this.formIndex}>${this.formIndex > -1 ? this.renderForm(data.form, data.paymentIcons) : ''}</p>
`)}
`;
}
Finally, here is the method to handle the clicking of the radios:
protected handleClick(e: any){
if(e.target.id == this._data.forms[0].label){
this.formIndex = 0
} else if(e.target.id == this._data.forms[1].label) {
this.formIndex = 1
}
console.log(this.formIndex);
}
How can I make it to where only the first form is displayed when the first radio is clicked and only the second form is displayed when the second radio is clicked? Thanks!
I would just use conditional rendering as described on the lit.dev docs
A minimal example looks like this:
#customElement('test-cond-render')
export class CondRender extends LitElement {
#state()
selectedForm = -1;
formData = [
{id: 0, title: 'form one'},
{id: 1, title: 'form two'}
];
renderForm() {
if(this.selectedForm === -1) {
return html`
<span>Please select a form</span>
`;
} else if (this.selectedForm === 0) {
return html`
<form action="#" target="_blank">
<p>
Select your interests:<br>
<input type="checkbox" name="movies"> Movies<br>
<input type="checkbox" name="sports"> Sports<br>
<input type="checkbox" name="videogames"> Videogames
</p>
<input type="submit" value="Send data">
</form>
`;
} else if (this.selectedForm === 1) {
return html`
<form action="#" target="_blank">
<p>
Enter your full name: <input type="text" name="fullname">
<input type="submit" value="Send data">
</p>
</form>
`;
} else {
return html`
<span>Something went wrong..</span>
`;
}
}
handleClick(form_id:number) {
console.log('handle click:', form_id);
this.selectedForm = form_id;
}
render() {
return html `
<h2>Cond render</h2>
${this.formData.map((data) =>
html`
<input type="radio" name="form-group" value="${data.id}" id="${data.id}" #click="${this.handleClick.bind(this, data.id)}">
<label for="${data.id}">${data.title}</label>
`
)}
<div>${this.renderForm()}</div>
`;
}
}
Your forms might be more complicated but the principle should be the same.
You can also use the cache directive for the render so it won't re-create the DOM for the selected form every time it is switched.
<div>${cache(this.renderForm())}</div>
I'm trying to create a very simple radio button system within react but cannot get the radio buttons to render correctly. I have attached my code as well as what the output looks like. What can I do to get the radio buttons to properly show up? Thanks!
https://i.imgur.com/N0ik047.png
constructor (props) {
super(props);
var user = props.location.state;
this.state = {
selected: ''
};
}
onChange = e => {
this.setState({selected: e.target.value})
}
render() {
return(
<form onSubmit={this.handleSubmit}>
<h1> Welcome! </h1>
<h4> Are you a: </h4>
<ul>
<li>
<label>
<input
type="radio"
value="student"
checked={value === "student"}
onChange={this.onChange}
/>
<h5> Student </h5>
</label>
</li>
<li>
<label>
<input
type="radio"
value="professor"
checked={value === "professor"}
onChange={this.onChange}
/>
<h5> Professor </h5>
</label>
</li>
</ul>
<button type="submit">Submit</button>
</form>
)
}
}
[1]: https://i.stack.imgur.com/DmU0W.png
There doesn't look to be anything wrong with the markup. I suspect that the styling is preventing the display of the radio buttons. On the image everything is centered - is it possible that the h5 header is rendering over the radio button. If you inspect the source of the web page and see the radio buttons in the DOM that indicates that styling is the issue.
I'd like to generate some HTML to show sucessfull form submission. I can't seem to do it within the handleSubmit Method.
class BookingForm extends Component{
...
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
console.log(name + ' '+value);
this.setState({
[name]: value
});
}
Submit method that I'd like to render html:
handleSubmit(event) {
console.log(this.state.lessonTime)
event.preventDefault();
this.setState({'success':true})
return(
<h1>Success</h1>
);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TimeList defaultTime={this.state.defaultTime}
handleChange={this.handleChange}/>
<br/>
<DateList defaultDate={this.state.defaultDate}
handleChange={this.handleChange}/>
<br/>
<NumberOfLessons defaultNOL={this.state.defaultLessons}
handleChange={this.handleChange}/>
<br/>
<input type="submit" value="Book Lesson" />
</form>
<br/>
</div>
);
}
}
Any ideas on how I can get the success heading to show once submit has been clicked on.
Thanks
I think a better way to handle this is to use state to control the rendering of "success" heading. You can add the following line of code to the place you want to add the header:
{this.state.success && <div> Successful </div> }
I think the reason the html tag returned by handleSubmit in your function doesn't show up is because although it returns the tag, it doesn't know where to put it. If you want to make it work, you'll need to use methods like createElement and appendChild but that's not the way react should work.
If you want your <h1> element to render instead of form on successful completion do this in your render function:
render() {
return (
<div>
{this.state.success?(
<h1>Success</h1>
):(
<form onSubmit={this.handleSubmit}>
<TimeList defaultTime={this.state.defaultTime}
handleChange={this.handleChange}/>
<br/>
<DateList defaultDate={this.state.defaultDate}
handleChange={this.handleChange}/>
<br/>
<NumberOfLessons defaultNOL={this.state.defaultLessons}
handleChange={this.handleChange}/>
<br/>
<input type="submit" value="Book Lesson" />
</form>
<br/>)}
</div>
);
}