On hover of any of the above items I want to surround item with a box having grey color background.
and onclick I want to change it to something like below (surround with a box having background color as text color, change text color to white and have a x in the box). Clicking on x should bring it back to the normal state as depicted in image 1.
Current code:
export default class GridSummary extends Component {
renderJobStateSummary() {
const jobCountSummaryDiv = [];
if (this.props.jobStateCount.size !== 0) {
jobCountSummaryDiv.push('Summary: ');
for (const state of ['Total', ...jobStatesPriorityOrder]) {
if (this.props.jobStateCount.has(state) &&
this.props.jobStateCount.get(state) !== 0) {
const cssClass = `${JOB_STATES_CSS_CLASS[state]} clickable`;
jobCountSummaryDiv.push(
<span
className={cssClass}
role="link"
tabIndex="-1"
key={state}
>
{JOB_STATE_DISPLAY_NAME[state]}: {this.props.jobStateCount.get(state)}
</span>
);
jobCountSummaryDiv.push(' | ');
}
}
}
return jobCountSummaryDiv;
}
render() {
return (
<div className="summary-panel">
{ this.renderJobStateSummary() }
</div>
);
}
}
Try with pseudo class combination of :hover and :active. For guest it likes button.
In style border option use combination of inset and outset, it gives very good visuel.
Related
I'm trying to change the color of a div when it is clicked.
this is the structure of the div
<li v-for="monomer in monomers">
<div :style="monomerButton" #mouseover="hover = true" #mouseleave="hover = false"
#click="selectMonomer($event)" class="monomer-button">
<p class="monomer-symbol">{{monomer.symbol}}</p>
</div>
</li>
this is the function that is called when the onclick event is called
selectMonomer(event) {
// If the p element gets clicked, get the div that contains the p element
let element = event.target.nodeName === "P" ? event.target.parentElement : event.target
element.style.backgroundColor = "rgba(44, 224, 203, 0.5)"
}
The color does change and remains that way as long as I keep my mouse over the div. When the mouse leaves the div though, the color reverts to it's original color. Clicking it again will change it again but revert right back when the mouse leaves again.
How do I get the div to keep the color?
Edit:
monomerButton: {
backgroundColor: getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog)
}
The background color is dependent on the kind of monomer it is.
Edit2:
The entire component (lets call it component A) is in a nested for loop inside of a different component (component B). component B looks something like this:
<component B>
<ul>
<li v-for="monomer type in monomer types">
<component A :monomers="monomers of that type"></component A>
</li>
<ul>
</component B>
so for every kind of monomer, like Glycine + glycine analogs, Cysteine + cysteine analogs, a component is made. This component (component A) creates a small, square div with text in it for each analog. this is why getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog) can just take the first element because all the divs in a single instance of component A need to be the same color.
So, thanks to #Shoejep, I figured out an answer.
// component A
mounted() {
this.monomers.forEach(monomer => {
monomer.selected = false
})
}
In the mounted hook I gave each monomer a 'selected' attribute. Ofcourse they all start out as not selected.
// component A
<div :style="monomerButton(monomer)" #mouseover="hover = true" #mouseleave="hover = false" #click="selectMonomer(monomer)" class="monomer-button">
<p class="monomer-symbol">{{monomer.symbol}}</p>
</div>
I made the :style attribute use the retun value of getMonomerStyle() which is defined as:
// component A
getMonomerStyle(monomer) {
return {
backgroundColor: monomer.selected ? "rgba(131, 222, 226, 0.8)" : getNodeColor(this.monomers[0].polymerType, this.monomers[0].naturalAnalog),
border: this.monomers[0].monomerType === "Terminal" ? "2px dashed" : "1px solid"
}
}
When a mononer is clicked, that monomer is emitted to the parent component. This is so that all other instances of component A also know which monomer is selected.
then it's just simply setting the selected attribute to true for the selected monomer and setting the selected attribute to false for the previously selected monomer.
if (this.previousSelected) {
this.previousSelected.selected = false
}
monomer.selected = true
this.previousSelected = monomer
You could do something like the snippet I have included below.
Have a selected property on each monomer, then when you calculate the style that should be on div, then you calculate based on whether that monomer is selected or not.
This will also simplify some of the code you presented, because if you click on the p element, then it will bubble up to the div and set the monomer as selected.
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: "#app",
data: {
monomers: [{
polymerType: "Test",
naturalAnalog: "Test",
symbol: "Test",
selected: false
},
{
polymerType: "Hello",
naturalAnalog: "Hello",
symbol: "Hello",
selected: false
},
{
polymerType: "World",
naturalAnalog: "World",
symbol: "World",
selected: false
}
],
hover: true
},
methods: {
getNodeColor: function(polymerType, naturalAnalog) {
return "lightblue";
},
selectMonomer: function(monomer) {
monomer.selected = !monomer.selected;
},
monomerButton: function(monomer) {
return `backgroundColor: ${monomer.selected ? "pink" : this.getNodeColor(monomer.polymerType, monomer.naturalAnalog)}`;
}
}
});
ul {
list-style: none;
padding: 0;
margin: 0;
}
li div {
padding: 8px;
}
li {
margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="monomer in monomers">
<div :style="monomerButton(monomer)" #mouseover="hover = true" #mouseleave="hover = false" #click="selectMonomer(monomer)" class="monomer-button">
<p class="monomer-symbol">{{monomer.symbol}}</p>
</div>
</li>
</ul>
</div>
I have a column for buttons to toggle a modal. The problem is, I don't want to display the button for every single row. I only want to display the button on the first entry of the color.
Note that the colors are unpredictable (you don't know what colors will be displayed beforehand).
For example,
color toggler
black +
red +
red //don't display it here
yellow +
blue +
blue //don't display it here
blue //don't display it here
orange +
red +
black +
black //don't display it here
blue +
I have try to go through the document and some example, but I can't seem to find a solution to it (maybe something that I missed ?).
What I did was storing the first color in the state. Then I did with the theCheckFunc:
let flag = true
if (nextColor !== this.state.color)
this.setState({color: nextColor})
flag = false
return flag
Then in the columns I did.
Cell: props => (this.theCheckFunc(props) && <div onClick={somefunc}> + <div>)
However, everything seems to be frozen. The browser doesn't even respond.
Any good suggestion on how to do this ?
Don't use state with this, since you don't want to re-render based on new input. Instead, compute the array as part of the render.
For example, assuming that when you get to your render statement, you have a random array of colors like this:
['red', 'red', 'black', 'purple', 'purple']
Then this function could create the array you need with the data for render:
function getTableRowData(arr) {
let tableRowData = []
arr.forEach((color, n) => {
let toggler = true
if (n !== 0 && arr[n - 1] === color) {
toggler = false
}
tableRowData.push({ color, toggler, })
})
return tableRowData
}
Then you can iterate over the tableRowData in your render return and have it display the way you want to.
First set your color control variables in state or in class wherever you choose. In this example i'm choosing to control them over state.
constructor(props) {
super(props);
this.state = {
firstRedAlreadyHere: false,
firstBlueAlreadyHere: false,
firstGrayAlreadyHere:false,
....
...
}
}
then open a function to prepare a table. Later Use that function in render() to put table on component.
function putValuesToTable()
{
let table = [];
for (let i = 0; i < (YOUR_LENGTH); i++) {
{
let children = []; /* SUB CELLS */
/* IF RED COLOR IS NEVER CAME BEFORE, PUT A BUTTON NEAR IT */
if(!this.state.firstRedAlreadyHere)
children.push(<td>
<SomeHtmlItem></SomeHtmlItem></td> <td><button </button></td>)
/* ELSE DON'T PUT BUTTON AND CHANGE STATE. */
else
{
children.push(<SomeHtmlItem></SomeHtmlItem>);
this.state.firstRedAlreadyHere = true;
}
table.push(<tr>{children}</tr>);
}
}
return table;
}
I am changing state directly instead of this.setState(); because I don't want to trigger a refresh :). In render function, call putValuesToTable like this
render()
{
return (<div>
<table>
<tbody>
<tr>
<th>SomeParameter</th>
<th>SomeParameter2</th>
</tr>
{this.putValuesToTable}
</tbody>
</table>
</div>);
}
Use this example to extend your code according to your aim.
I'm creating a gameBoard, and having trouble toggling background colors for button divs. The toggle works for individual clicks on the "buttons" (styled divs), but when I click adjacent buttons it requires two clicks to get the next button to change its background color. How can I get adjacent buttons to toggle on first click? I've read some related posts like (Changing style of a button on click) but still struggling to get this working -
Related code below,
full code: https://jsfiddle.net/lydiademi/kt2qgfpr/
TY!
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
color: '#FFF',
color_white: true,
currentWord: '',
board1: [],
row1: ["aaafrs","aaeeee","aafirs","adennn","aeeeem"],
}
this.clicked = this.clicked.bind(this);
}
componentWillMount() {
let letter1 = '';
this.state.row1.forEach(die => {
letter1 = die[Math.floor(Math.random() * 6)].toUpperCase();
if (letter1 === 'Q') {
this.state.board1.push("Qu")
} else {
this.state.board1.push(letter1);
}
})
}
clicked(event) {
//change background color
let newColor= this.state.color === "#FFF" ? "#ACCEEC" : "#FFF";
this.setState({ color: newColor });
event.target.style.backgroundColor = newColor;
}
render () {
return (
<div id="board">
<div className="row">
{
this.state.board1.map((letter, index) => {
return (
<div className="btn" onClick={(e) => {this.clicked(e)}}>
{letter}
</div>
)
})}
</div>
)
}
Issue is :
You are maintaining one variable for all the elements bg toggle,
So the code is working as it should,
There is no need for maintaining state for that.
What you can do is :
Set extra attribute data-color like this
<div className="btn" data-color='#FFF' onClick={(e) => {this.clicked(e)}}>
And change bg color and attr based upon data-color , onClick like this
clicked(event) {
// get current color of element
let currentColor = event.target.attributes['data-color'].value;
// apply condition based upon currentColor
let newColor = currentColor === "#FFF" ? "#ACCEEC" : "#FFF";
// set the bg color
event.target.style.backgroundColor = newColor;
// change the data-color value to currentColor
event.target.setAttribute('data-color' , newColor);
// add letter to state.currentWord
let letter = event.target.innerText;
this.setState({ currentWord: this.state.currentWord + letter })
}
Here is the link to working fiddle :
https://jsfiddle.net/vivekdoshi2/kt2qgfpr/2/
I am basically wanting to do individual selected states on divs that I am rendering in a loop. I can only see a way to change the color of all of the rendered divs, but rather I wish to change the color of which ever one was clicked. Below is the code for the loop.
renderSports() {
const {sports} = this.props
return sports.valueSeq().map(sport => this.renderActualSports(sport))
},
renderActualSports(sport) {
const {sportCount} = this.props
return (
<div className="sportSeparator">
{sport} {this.renderCount(sportCount.get(sport))}
</div>
)
},
This will basically just render a list of some sports. I want to change the color of a selected sport on click.
You will need to store the items that were clicked in your component state.
Assuming you would store this highlighted items in this.state.highlighted and that your sport variable is a string or number:
renderActualSports(sport) {
const {sportCount} = this.props
return (
<div
className="sportSeparator"
onClick={this.highlight(sport)}
style={{color: this.state.highlighted.indexOf(sport) > -1 && 'red' : ''}}
>
{sport} {this.renderCount(sportCount.get(sport))}
</div>
)
},
highlight(sport) {
return () => {
this.setState({highlighted: [...this.state.highlighted, sport]});
}
}
So what you are doing is onClick on the div you add that sport to the this.state.highlighted array and when displaying the list. you check if that sport is in the array and if yes you change the color using an inline style
So i have an array like this const divs = ["Text 1","Text 2","Text 3"].
I create divs (a small menu) from this array in my render function
var createThreeDivs = divs.map((category) => {
return <div key={category} onClick={this.handleClick} className="myDivClass">{category}</div>
});
I want to style one of these divs when i click on them, and the remove the styling on the rest of them. So when i select one of the divs it gets a color and removes the color on the rest of them
In normal javascript with no virtual DOM i could do like this:
handleClick(e) {
//remove styling from others
var allDivs = document.getElementsByClassName("myDivClass");
for(var i = 0; i < allDivslength; i++) {
allDivs[i].classList.remove("myDivClass-styled");
}
//Add styling class to selected,
e.target.classList.add("myDivClass-styled");
}
But this manipulate the DOM directly. How do i do something like this in React?
I have seen examples of how this can be done using state with only one element and by not having an array creating the divs. But i can't come up with a good solution for this scenario. Any suggestions?
Using the component's state you can update the color based on the active div. Update the index of the active div when the user clicks, and when the index equals the div that was clicked on update the color of that div.
See example below.
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
active: 0
};
}
render() {
const divs = ["Text 1", "Text 2", "Text 3"];
const updateActiveDiv = (value) => {
this.setState(() => {
//this line will reset the value to
//null if same element is clicked twice
if(value === this.state.active) {
value = null;
};
return {
active: value
}
});
};
let divText = divs.map((div, i) => {
let color = this.state.active === i ? 'red' : 'black';
return <div style={{ color }} onClick={() => updateActiveDiv(i)}>{div}</div>;
});
return (
<div>
{ divText }
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Pass current text from html
handleClick = (text)=>{
this.setState({activeText:text})
}
Inside create div function add class dynamically
Div className = { stat condition ? Class : no class }