get nested element from OnClicks target react - javascript

I'm trying to change Button's appearance onClick and then will have another button to save the set according to a check and then shipped to database.
With code below I have the button changing appearance/color but not the icon. The icon is nested within the button element like so:
<td key={i}>
<button
onClick={this.schedulerTableTimeChange}
className="waves-effect waves-light btn"
>
<i className="material-icons">check_box</i>
</button>
</td>
So can get the whole element with item.target and change the color with item.target.className = x but I also want to change the child element of the nested <i>child</i> as well to change the icon. How can I do this?
Here is my entire onClick:
schedulerTableTimeChange(item){
const green = 'waves-effect waves-light btn';
const red = 'waves-effect waves-light red btn';
if(item.target.className === red){
item.target.className = green
//change <i> child here here
}else if(item.target.className === green){
item.target.className = red
//change <i> child here here
}
}
also using materialize-css which accounts for the color and icon changes based on className

I would suggest a Button component, something like this:
import React, { Component } from "react";
class Button extends Component {
state = { checked: false };
clickHandler = e => {
this.setState({ checked: !this.state.checked });
if (this.props.onClick) {
this.props.onClick(e);
}
};
render() {
const { checked } = this.state;
const green = "waves-effect waves-light btn";
const red = "waves-effect waves-light red btn";
return (
<button onClick={this.clickHandler} className={checked ? green : red}>
<i className="material-icons">
{checked ? "check_box" : "somethingelse"}
</i>
</button>
);
}
}
export default Button;
Of course change somethingelse to the correct icon name... Here's a demo
HTH
-Ted

Related

Stimulus Framework - connect() not work when change with javascript

I create a stimulus controller and use on a div element.
Now when change innerHTML of this div element with click on a button, text change but color not change to red and connect() not work.
<div data-controller="test">
<span>This text color change to red</span>
<button type="button" data-action="test#changeColor">click</button>
</div>
test_controller.js
...
connect() {
this.element.style.color = "red";
}
changeColor(event) {
this.element.innerHTML = "<span>HelloWorld!</span>"
}
...
Two issues
You need to target the span, as this.element will be the element with the data-controller on it. See https://stimulus.hotwired.dev/reference/targets
You will need to set the target's color in the connect method AND the controller's changeColor method for it to change when the element connects (DOM loads) and when the button is clicked. See https://stimulus.hotwired.dev/reference/lifecycle-callbacks
import { Controller } from '#hotwired/stimulus';
export default class extends Controller {
static targets = ['label'];
connect() {
this.changeColor();
}
changeColor() {
const element = this.labelTarget;
element.innerText = 'HelloWorld!';
element.style.color = 'red';
}
}
<div data-controller="test">
<span data-test-target="label">This text color change to red</span>
<button type="button" data-action="test#changeColor">click</button>
</div>

Using an anchor element to remove a label in a contentEditable div

I have a React app that has a component using react-contentEditable.
in the image I provided, I need to click on the X and remove that label from the html prop in contentEditable component. contentEditable needs a string for its html prop. I need to somehow update the html prop string to a new string that discards the selected label but keeps the others. my first thought was a button, but I couldnt seem to pass an onClick when the html requires a string... so I defaulted to trying a tag. can an tag somehow remove or change the class of the clicked element in contentEditable?
In my component I have a "add Contacts" button that when clicked updates the contentEditable html to a string with a <label> <span> <a> </a> </span> </label>. I need to figure out how to use an anchor element or maybe a button with some type of onclick to remove the "clicked" element.
in the image I provided, I need to click on the X and remove that label from the html prop in contentEditable component. contentEditable needs a string for its html prop. I need to somehow update the html prop string to a new string that discards the selected label but keeps the others. my first thought was a button, but I couldnt seem to pass an onClick when the html requires a string... so I defaulted to trying a tag. can an tag somehow remove or change the class of the clicked element in contentEditable?
import React, { createRef, Fragment, useState, useEffect} from 'react';
const AddContactTo = ({ toFieldRef, recipients, setRecipients, contactsModal, setContactsModal, toField, setToField }) => {
const addContactsToDiv = () => {
let selectedContactsArray = [] // create and empty array
const Matches = selectedRows.filter((row) => {
const isMatched = contacts.some(contact => { if(contact._id == row) {
selectedContactsArray.push({firstName: contact.firstName, lastName: contact.lastName, phone_number:contact.phone_number, _id: contact._id})
}})
return isMatched
})
const matchedContactsArray = []
selectedContactsArray.map(contact => { // mapping over selected to add html
matchedContactsArray.push((`
<label contentEditable="false" class="p-1 font-weight-bold bg-primary ml-2 text-white rounded-capsule shadow-none fs--3">${contact.firstName + " " + contact.lastName + " "}
<span class="badge fs--1 badge-soft-success badge-pill ml-2">${contact.phone_number}</span>
X // when this <a> is clicked, I need to remove only this element from the html
<span name="indy-contacts" class="d-none">${contact._id}</span>
</label>`))
})
matchedContactsArray.map(contact => { return contact})
const stringifiedRows = matchedContactsArray.toString()
setToField({...toField, html: stringifiedRows})
selectedContactsArray = []
}
export default AddContactTo
Here is the contentEditable div. This is in a parent component
MessageCreateForm.js
import React, { useState, useRef, Fragment } from 'react';
import ContentEditable from 'react-contenteditable';
const MessageCreateForm = () => {
const toFieldRef = useRef()
const handleChange = evt => {
console.log(evt.target.value)
console.log(toField.value)
console.log(toFieldRef)
const indyContacts = document.getElementsByName('indy-contacts')
const indyGroups = document.getElementsByName('indy-groups')
setToField({html: evt.target.value})
};
const handleBlur = (evt) => {
console.log(toFieldRef.current);
console.log(evt.target.value)
};
const handleClick = () => {
console.log(toFieldRef)
}
<ContentEditable
name="to"
innerRef={toFieldRef} // passing our ref instead of state
html={toField.html} // the html = our ref.current property
//value={toField}
onBlur={handleBlur}
onClick={() => {handleClick()}}
onChange={handleChange} // this sets our refs.current = event.target.value
style={{minHeight: "7em", maxHeight: "10em", overflow: "auto"}}
className="border border-2x border-300 bg-light rounded-soft fs-1"
>
</ContentEditable>
export default MessageCreateForm;

adding item in to the dom needs tow click rather than one in react?

I am using this below function (functional component with hooks) to add items in to the Dom.
I want to keep the fontawosome icon in the code, hidden and once the user clicks on a utility div, an icon must show in UI, after the icon shows, the user can add an item in to the movements div the problem is I have to double click all the time to add that mentioned item instead of clicking once!!
any idea what is the deal with double click ?
import React, {useState} from 'react'
import StabelItem from './StabelItem';
import { icon, library } from '#fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faPlusCircle} from '#fortawesome/free-solid-svg-icons';
library.add(faPlusCircle)
function addItems() {
// item component imported !!
let item = [<StabelItem />]
// Icon State !! local
const [icons, setIcon] = useState([]);
// Items State !! local
const [stabelItem, setStabelItem] = useState({items:[]});
// Show the icon so the use can add itmes +
const showIcon = ()=> {
// maipulate the state so the icon can show !!
setIcon(<FontAwesomeIcon onClick={() => {addStabelItem()}} icon={["fas", "plus-circle"]}/>)
}
// add Items !! when clicking on the icon this funtion is inside of showicon !!
const addStabelItem = () => {
setStabelItem({items: [...stabelItem.items, ...item]})
}
return (
<div className="utility" onClick={showIcon}>
<li className="box-item" >
<div className="flexrow" >
<div className='number norest'>Total</div>
<div className='number calc margin-left norest'>0</div>
</div>
<ul className="movements">
{/* itmes gets added!! when icon is getting clicked */}
{stabelItem.items}
{/* icons Show on demand */}
{icons}
</ul>
</li>
</div>
)
}
I think you should edit the function you pass to the icon like this:
setIcon(<FontAwesomeIcon onClick={addStabelItem} icon={["fas", "plus-circle"]}/>)
I had to change the structure making the icon on show, rather than making the state showing it, so ternary operator solved the issue.
function StabelBoxUtility() {
// item component
let item = [<StabelItem />]
// Icon State
const [iconsVisble, setIconVisble] = useState(false);
// Items State
const [stabelItem, setStabelItem] = useState({items:[]});
// show Icon
const showIcon = () => setIconVisble(true)
// add Items !! the icon must be on display
const addStabelItem = () => {
setStabelItem({items: [...stabelItem.items, ...item]})
}
return (
<div className="utility" onClick={showIcon}>
<li className="box-item" >
<div className="flexrow" >
<div className='number norest'>Total</div>
<div className='number calc margin-left norest'>0</div>
</div>
<ul className="movements" >
{stabelItem.items}
{iconsVisble ? <FontAwesomeIcon className="changable margin-left" onClick={addStabelItem} icon={["fas", "plus-circle"]} size="lg" />: null}
</ul>
</li>
</div>
)
}

Having an active state toggler on multiple buttons

I am trying to have my buttons light up once clicked, and dim when clicked twice. To indicate the user has already clicked that button.
const [isActive, setActive] = useState("false");
const handleToggle = () => {
setActive(!isActive);
};
And my buttons are toggling with the following code
<button
type="button"
value="Peperoni, "
className={isActive ? "button btn first" : "button btn firstActive"}
onClick={(event) => {
ToppingPlusMinus(event);
}}
>
Pepperoni
</button>
So far I have this working, however the buttons are all tied to the same state so when one is clicked they all light up. I am stumped on how to downsize this and make each button toggle its active class individually.
I'm aware I could just brute force it with many states for each button, but I know there is a smarter solution on there.
Thank you in advance for your time.
My full code is on a codesandbox here
You need to create a component that tracks its own state and fires the onClick
const ButtonClickable = props => {
const [isActive, setActive] = useState(false);
const handleToggle = (ev) => {
setActive(!isActive);
props.onClick && props.onClick(props.value)
};
return <button
type="button"
className={isActive ? "button btn first" : "button btn firstActive"}
onClick={handleToggle}
>
{props.value}
</button>
}
Then in the parent compoennt
<ButtonClickable onClick={ToppingPlusMinus} value="Peperoni, "/>
<ButtonClickable onClick={ToppingPlusMinus} value="Other, "/>
<ButtonClickable onClick={ToppingPlusMinus} value="Milk, "/>
Note that ToppingPlusMinus becomes ToppingPlusMinus(value)

Add & Remove CSS classes with React

I am new to React. I have a few buttons in a button group:
<div className="btn-group">
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type1")} >Button1</button>
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type2")} >Button2</button>
<button className="btn btn-mini btn-default" onClick={() => this.changeDataType("type3")} >Button3</button>
</div>
Whenever the user clicks on one of the buttons, this button should become the active, selected one. I found out that I need to add the CSS class active to the corresponding button, but I am not sure how to implement this.
I thought about this for a bit. I have a changeDataType function connected to my buttons, in which I do some other stuff. Would I then, in there, somehow manipulate the CSS?
So I guess my questions are first, how to target the button I need to target, and second, how I could change that button's CSS with React.
In react when state changes react re-renders. In your case if you want to change the way something looks then you probably want to force another render. What you can do is have the className be part of state and then update the state when you want, causing the component to re-render with the new className. For example:
constructor() {
super();
this.state = {
className: 'btn'
}
}
render () {
return (
<Button className={this.state.className}>Click me</Button>
)
}
Since the className is bound to state updating state will cause the button to render again with the new className. This can be done like this:
updateClass() {
let className = this.state.className;
className = className + ' ' + 'btn-primary'
this.setState({className})
}
This is an example of the function you can call on the click of a button and update the className for the button.
There's a nice utility you can use for classname logic + joining classNames together
https://github.com/JedWatson/classnames
Based on setting React state for active you could do something like the following. You can get as complex as you need to with the logic. If the logic result is falsy, that key won't be included in the output.
var classNames = require('classnames');
var Button = React.createClass({
// ...
render () {
var btnClass = classNames({
btn: true,
'btn-active': this.state.isActive
});
return <button className={btnClass}>{this.props.label}</button>;
}
});
Here how I did this:
//ChatRoomPage component
function ChatRoomPage() {
const [showActionDropdown, setShowActionDropdown] = useState('hide');
function showActionDropdownHandler(){
console.log("clicked")
if(showActionDropdown=='hide')
setShowActionDropdown('show')
else
setShowActionDropdown('hide')
}
return (
<div>
<button onClick={ () => showActionDropdownHandler() } className="btn " type="button">Actions</button>
<div className={`action_menu ${showActionDropdown}`}>
...
</div>
</div>
);
}
export default ChatRoomPage;

Categories

Resources