Delete form input value outside of input - javascript

So I have this form that updates the search in real time via storeUserSearch, which is why a value isn't set on input. I'm trying to implement an icon that deletes what's in the input field on click, and also runs the action storeUserSearch('').
The second onClick has no problems by itself. I'm simply trying to get the first onClick to work, and then have them both running at the same time so my click executes both.
<form>
<input
className="searchBox fas fa-search"
type="search"
placeholder="Search"
onChange={event => this.props.storeUserSearch(event.target.value) } />
<i className="fas fa-times-circle" onClick={event => event.target.parentElement.input} onClick={event => this.props.storeUserSearch('')}> </i>
</form>
Edit: Figured out how to reset the value via
onClick={event => event.target.parentElement.firstChild.value=''}
Just need to figure out how to combine the onClicks now.

why you're writing two onClick on same element? just pass a method on its click event and write all the logic there.
i.e:
<i className="fas fa-times-circle" onClick={this.handleIconClick}> </i>
// and in handleIconClick function write the logic.
handleIconClick = (e)=>{
e.target.parentElement.firstChild.value='';
this.props.storeUserSearch('');
}

You can't define two onClick props, one will overwrite the other. You can try something like
onClick={(event) => {event.target.parentElement.firstChild.value=''; this.props.storeUserSearch('')}}
note the semi-colon between the two individual statements

You can only have 1 onClick attribute per component, not multiple. I'm not sure exactly what storeUserSearch function is supposed to do since it's omitted from your code snippet, but based on what you've explained, I think you can achieve what you want to do similar to below:
class SearchForm extends React.Component {
constructor () {
super();
this.state = {
inputValue: ''
};
}
render() {
return (
<div>
<input
type="text"
value={ this.state.inputValue }
onChange={
e => {
this.setState({inputValue: e.target.value})
}
}
/>
<input
type="button"
value="Clear input"
onClick={
() => {
this.setState({inputValue: ''})
}
}/>
<span style={{ display: 'block' }}>Current textbox state: <span style={{ color: 'blue' }}>{this.state.inputValue}</span></span>
</div>
);
}
}
ReactDOM.render(<SearchForm></SearchForm>, document.querySelector('#app'));
<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="app"></div>
Basically we create a component that is made up of a 2 input elements (1 text and 1 button). The approach I took was to simply set the value attribute equal to our component's state.inputValue, which is updated each time a change event occurs on it.
We just hardcode the state.inputValue property to '' when the clear button is pressed.

Related

How to remove added classes from an element in reactjs

I am making a drag n drop sort of game where you match the logos with their corresponding name.
If user matches the logo with the name correctly than the field which you could drop the logo gets additional classes.
Like this:
if (isCorrectMatching) {
event.target.classList.add("dropped");
draggableElement.classList.add("dragged");
event.target.classList.add("dragged");
event.target.setAttribute("draggable", "false");
draggableElement.setAttribute("draggable", "false");
event.target.innerHTML = `<i class="fab fa-${draggableElementBrand}" style="color: ${draggableElement.style.color};"></i>`;
}
If every match is found user can go to next level , my problem is that these additional classes are staying there , how do I remove them ?
I am mapping them out like this:
<div className="containerItems">
{draggableItems.map((x, i) => {
return (
<div className="draggable-items">
<i
onDragStart={(e) => dragStart(e)}
className={`draggable fab fa-${x}`}
id={x}
draggable="true"
ref={draggableOnes.current[i]}
></i>
</div>
);
})}
</div>;
{
matchingPairs.map((x, i) => {
return (
<section className="matching-pairs">
<div className="matching-pair">
<span className="label">{x}</span>
<span
className="droppable"
// ref={droppableOnes.current[i]}
onDragEnter={(e) => dragEnter(e)}
onDragOver={(e) => dragOver(e)}
onDragLeave={(e) => dragLeave(e)}
onDrop={(e) => drop(e)}
data-brand={x}
></span>
</div>
</section>
);
});
}
I can not seem to solve this one, like how do I remove all the classes that I've added when there was a correct matching.
I would like to remove basically everything that I've added in my if (isCorrectMatching) .
I've tried to use refs but it did not work. What is the way to go for this?
In React, you don't directly manipulate DOM elements (well, almost never), including their the class lists. Instead, you keep your state information in the component and use that state information to render the elements that make up your component (including their classes). React will then compare the rendered elements you return with the DOM and make any necessary changes (such as updating the classList). So in your code, when you see that you have a correct matching, you wouldn't directly modify those DOM elements' classList lists, you'd update your state to remember the match, and use that state information in the next render to put the appropriate classes on the elements being rendered.
Here's a simpler example with a tickbox, but it's the same general concept:
const {useState} = React;
const Example = () => {
const [isChecked, setIsChecked] = useState(false);
return <div>
<label>
<input
type="checkbox"
checked={isChecked}
onChange={() => setIsChecked(flag => !flag)}
/>
Ticked
</label>
<div className={isChecked ? "yes" : "no"}>
Example
</div>
</div>;
};
ReactDOM.render(<Example />, document.getElementById("root"));
.yes {
color: green;
}
.no {
color: #d00;
}
label {
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
Note how the state member isChecked determines what classes the div has, and is updated by ticking/unticking the checkbox.

How to get button value when event is propagated

I am making a react button component and the component looks like this
const Button = props => {
return (
<button
style={props.style}
onClick={props.onClick}
className={`btn ${props.color} ${props.loading &&
"loading"} ${props.block && "block"} ${props.className}`}
disabled={props.disabled}
type={props.type}
value={props.value}
>
<span className={"content"}>
{props.icon && <span className={"icon-left"}>{props.icon}</span>}
{props.children}
</span>
{props.loading ? <Spinner /> : null}
</button>
);
};
The issue arises when i try to add a value prop and an event listener to the button component.
If i do that and i try getting the event.target.value value from the onClick handler, it gets to work only when i click other parts of the button, clicking the span text returns an undefined
This seems logical since there is no value on the span, what is the best way i could use to fix this?
You should use event.currentTarget instead of event.target
The currentTarget event property returns the element whose event
listeners triggered the event.
More on reading here.
Use event.currentTarget.
Add an attribute data-value to the span. So on click get the event.currentTarget.value or event.currentTarget.dataset.value
Inside the handler do like this
let m = event.currentTarget.value?
event.currentTarget.value:
event.currentTarget.dataset.value

Build up some UI with mithril.js and jsx

I'm new to javascript and its ecosystem. I'm trying to build some components using mithril.js. My goal is to have a component that shows some properties and provides a couple of button for each of them. Just to learn about mithril.js and jsx. Here is what I did so far:
const m = require("mithril");
var Something = {
_increase: function(category) {
console.log("increase category: "+category);
},
_decrease: function(category) {
console.log("decrease category: "+category);
},
view: function(vnode) {
return <div>
{Object.keys(vnode.attrs.categories).map((category)=> {
return <div>
<label for={category}>{category}</label>
<input type="number" id={category} value={vnode.attrs.categories[category]} />
<button type="button" onclick="{this._increase(category)}">MORE</button>
<button type="button" onclick="{this._decrease(category)}">LESS</button>
</div>
})}
</div>
}
}
export default Something;
Well, component seems to work fine, node doesn't complain and labels and buttons and fields are displayed on page, but, when I click on a button, nothing happen. It looks like event isn't fired. What's wrong?
Two things: (1) I think you should just put the function into the onclick handler braces instead of encoding the function in a string. (2) It looks like you're immediately invoking the function, not declaring that the onclick handler is a function that uses the category argument. Try passing in an anonymous function with no arguments, that way you when the onclick event is fired it can take in the category as a parameter:
onclick={() => this._increase(category)}
onclick={() => this._decrease(category)}

Toggle prop passed on one of many targets in ReactJS

Just starting off with ReactJS and have a project where I am showing an accordion of issues and including a details area that is hidden on the start.
There is a button in the accordion bar that should pass a prop to the child element to hide or show them. I have refs on the button and on the details child compoment and added a function to call the function and pass the ref of the details area. I am just not sure how to dynamically change the class hidden on one of many areas and not all of them.
Not sure if putting a class on each element and then learning how to toggle the particular child's class is better or changing the prop to the child.
I can get to the change function but am drawing a blank from there and all the googling shows how to do one element with a grand change of state but I need individual elements.
Here is what I have so far.
Parent
...
<AccordionItem key={item.id} className={iconClass} title={`${item.area}`} expanded={item === 1}>
{
item.issues.map(issue => {
let trim = (issue.issue.length>21) ? `${issue.issue.substring(0,22)}...`: issue.issue;
return (
<div className="issue-bar container-fluid">
<div className="row issue-bar-row">
<span className="issue-title"><img src={CriticalRed} alt="Critical"/> {trim}</span>
<span className="btns">
<button className="btn btn-details" onClick={() => this.showDetail(`details-${issue.id}`)}>Details</button>
</span>
</div>
<IssuesDetails ref={`details-${issue.id}`} issue={issue} shouldHide={true} />
</div>
)
})
}
<div>
</div>
</AccordionItem>
...
Child
export default class IssuesDetails extends Component{
render(){
let issueDetails = classNames( 'issue-details', { hidden: this.props.shouldHide } )
return(
<div className={issueDetails}>
<div className="issues-details-title">
<h3>{this.props.issue.issue}</h3>
</div>
<div className="issues-details-details">
{this.props.issue.details}
</div>
<div className="issues-details-gallery">
<ImageGallery source={this.props.issue.photos} showPlayButton={false} useBrowserFullscreen={false} />
</div>
<button className="btn btn-success">Resolve</button>
</div>
)
}
}
Thanks for any help you provide or places you can send me!
If i'm understanding correctly, you need to be able to swap out shouldHide={true} in certain circumstances. To do this, you'll want your parent component to have a state object which indicates whether they should be hidden or not.
Exactly what this state object looks like depends on what sort of data you're working with. If the issues is a single array, then perhaps the state could be an array of booleans indicating whether each issue is expanded or not. I suspect you may have a more nested data structure, but i can't tell exactly since some of the code was omitted.
So assuming you have an array, it might look like this (i've omitted some things from the render method for brevity):
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
hidden: (new Array(props.issues.length)).fill(false),
};
}
showDetail(index) {
let newHidden = this.state.hidden.slice();
newHidden[index] = true;
this.setState({
hidden: newHidden
});
}
render() {
return (
<AccordionItem>
{this.props.issues.map((issue, index) => {
<div>
<button onClick={() => this.showDetail(index))}/>
<IssuesDetails issue={issue} shouldHide={this.state.hidden[index]}/>
</div>
})}
</AccordionItem>
);
}
}
Take a look at these:
https://codepen.io/JanickFischr/pen/xWEZOG
style={{display: this.props.display}}
I think it will help with your problem. If you need more information, please just ask.

Select and change a specific element in ReactJS

I am trying to toggle the colours of two buttons in ReactJS. I can set the active state property of the selected button OK, but I can't work out how to change the style of another button (calcY) based on my selection (of calcX).
The code is brittle but I am pretty new to react and any pointers on best practices would be appreciated. PS also I am using react-bootstrap for the Form and buttons.
const MyForm = React.createClass({
handleChange(event, attribute) {
let eventValue = event.target.value;
if (attribute === 'calcX'){
this.setState({active: true});
this.setState({bsStyle: 'info'});
let calcXBtn = ReactDOM.findDOMNode(this.refs.calcBtnGroup.refs.calcX);
calcXBtn.setState({bsStyle: 'default'});
}
...
}
render() {
return (
<Form onSubmit={this.handleSubmit} horizontal>
<FormGroup>
<ButtonGroup ref="calcBtnGroup">
<Button active className='btn btn-info' ref="calcX" onClick={(event) => this.handleChange(event, 'calcX')}>Calculate X</Button>
<Button className='btn btn-default' ref="calcY" onClick={(event) => this.handleChange(event, 'calcY')}>Calculate Y</Button>
</ButtonGroup>
...
);
}
});
module.exports = MyForm;
You can set the className or style based of an element (or subcomponent) on the state of your component. It's nice to use a ternary operator and ES6 template literals here.
<Button ref="calcX" className=`btn ${this.state.active ? 'btn-info' : 'btn-default'}` onClick={(event) => this.handleChange(event, 'calcX')}>Calculate X</Button>
What this does, is setting a className based on the state of your component. The <Button> component always has a btn className. If state.active is true, the class btn-info will be added. Otherwise btn-default will be added.
So the only thing you have to do now, is set the state in your handleChange method and the classNames will be rendered appropriately.
Edit: it's not really necessary to use refs here. It's almost never necessary to use refs. You want use React events (onChange, onSubmit, etc.) to set input values on the state, and render those values in the value in your inputs. These are called controlled components. You can read more about it in the official documentation: https://facebook.github.io/react/docs/forms.html

Categories

Resources