Using jQuery in React to modify CSS of an element - javascript

Hello,
I know its not recommended to use jQuery with react & I am aware of method on react for changing CSS of element but here I am just trying to see if my req can be achieved or not , all i want is to change the colour of li element when corresponding tick icon is clicked for it, I am using a jQuery code
const markdone = () => {
let c = $("#ll")
console.log(c)
$(c).closest("li").css("background-color", "green");
};
but when i am clicking the css gets applied but not on its corresponding li element in my case for ex have attached image when i click on 3 tick icon css gets changed for 1 is there any way i can fix it
attaching whole code below
check markdone function for making css change :
const [input, setValue] = useState("");
const [todos, setTodos] = useState([]);
// passing entered
const handleInput = (event) => {
setValue(event.target.value);
};
const lp = (event) => {
// let c = [1,2,34,55]
event.preventDefault();
// if no input nothing will happen return none
if (!input) return;
// using spread operator its used whenever we need to add array data to exiting array
const newTodos = [...todos, input];
setTodos(newTodos);
// clearing input text
setValue("");
};
const handeldel = (index) => {
// console.log(index)
todos.splice(index, 1);
setTodos([...todos]);
// const newTodos = todos.splice(index, 1);
// setTodos([...newTodos]);
};
const [line, setline] = useState(false);
// const [ll, setll] = useState(false);
const markdone = () => {
let c = $("#ll")
console.log(c)
$(c).closest("li").css("background-color", "green");
};
useEffect(() => {
$(document).ready(function() {
$("#pk").click(function(e) {
// e.preventDefault();
alert('hello')
});
});
});
return ( <
div >
<
h1 id = "pk"
className = "text-center font-weight-bolder alert-info mb-5" >
Tasks To Do < i class = "fas fa-clipboard-list text-success" > < /i> <
/h1> <
div class = "input-group mb-3 container" >
<
input className = "form-control border-primary font-weight-bold"
style = {
{
height: 60
}
}
placeholder = "Enter Text here"
type = "text"
value = {
input
}
onChange = {
handleInput
}
/> <
div class = "input-group-append" >
<
button className = "input-group-append font-weight-bolder "
style = {
{
fontSize: 20
}
}
onClick = {
lp
} >
{
" "
} <
i class = "fas fa-plus-square fa-2x p-2" > < /i>{" "} <
/button> <
/div> <
/div> {
todos.map((x, index) => ( <
ol style = {
{
listStyle: "outside"
}
}
className = "container" >
<
li className = "font-weight-bolder table-bordered text-capitalize alert-secondary "
style = {
{
fontSize: 30,
textDecoration: line ? "line-through" : "none",
// backgroundColor: ll ? "Chartreuse" : "none",
}
} >
{
x
} <
i class = "fas fa-check-circle float-md-right text-success"
id = "ll"
onClick = {
markdone
} >
< /i>{" "} <
i class = "fas fa-trash-alt text-danger float-md-right"
onClick = {
() => handeldel(index)
} >
< /i> <
/li> <
/ol>
))
}
{ /* for future ref */ } {
/* <div >
{data.map((user) => (
<div className="user">{user.id + " " + user.name
}</div>
))}
</div> */
} <
/div>

I suppose using a Ref should do the trick, as Refs provide a way to access DOM nodes or React elements created in the render method.
Just put it on the element you'd like to style using jQuery and access it with RefName.current

IDs must be unique
You do not need jQuery, just delegation
Plain JS - there are other ways in React
I am assuming .input-group-append is the container
document.querySelector(".input-group-append").addEventListener("click",function(e) {
const tgt = e.target;
if (tgt.classList.contains("text-success")) {
tgt.closest("li").style.backgroundColor = "green";
}
})

Related

How render two different contents of a modal window?

Good afternoon, I have a modal window in which the content is displayed depending on the condition.
I can't to do when the subscription is disabled, the content of the modal changed to "Subscription successful disabled".
And when you click on the "Enable subscription" button, the content of the modal changed to "Enable subscription by clicking on the button"
Now it turns out that "Subscription successful disabled" and "Enable subscription by clicking on the button" are displayed at once.
The enableSub and disableSub functions emulate sending data to the server, and the state emulates receiving data from the server.
const {
useState
} = React;
const state = {
isSubscriptionEnabled: true,
}
const enableSub = () => {
state.isSubscriptionEnabled = true
}
const disableSub = () => {
state.isSubscriptionEnabled = false
}
function App() {
const [isOpen, setIsOpen] = useState(false)
return ( <
div > {
isOpen &&
< div className = "modalWrapper" >
<
div className = "modal" >
<
button onClick = {
() => setIsOpen(false)
} > close < /button> <
div > {
state.isSubscriptionEnabled &&
< div >
Are you sure disable subscription ?
<
button className = "button"
onClick = {
disableSub
} >
Disalbe subscription <
/button> <
/div>
} {
!state.isSubscriptionEnabled &&
< div >
Subscription successful disabled <
button onClick = {
() => setIsOpen(false)
} > Thanks < /button> <
/div>
} {
!state.isSubscriptionEnabled &&
< div >
Enable subscription by clicking on button <
button className = "button"
onClick = {
enableSub
} >
Enable subscription <
/button> <
/div>
} <
/div> <
/div> <
/div>
}
{
state.isSubscriptionEnabled &&
< button className = "button"
onClick = {
() => setIsOpen(true)
} >
Disalbe subscription <
/button>
} {
!state.isSubscriptionEnabled &&
< button className = "button"
onClick = {
() => setIsOpen(true)
} >
Enable subscription <
/button>
} <
/div>
)
}
ReactDOM.render( < App / > , document.getElementById('app'));
.app {
position: relative;
}
.button {
margin: 20px;
}
.modalWrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #ccc;
display: flex;
align-items: center;
justify-content: center;
}
.modal {
width: 300px;
height: 150px;
padding: 30px;
position: absolute;
border: 1px solid teal;
background: #fff;
}
<div id="app"></div>
jsfiddle
import {React,useState} from 'react'
function App() {
const [isOpen, setIsOpen] = useState(false);
const [isSubscriptionEnabled, enableSubscription] = useState(false)
const enableSub = () => {
enableSubscription(true)
}
const disableSub = () => {
enableSubscription(false)
}
return (
<div> {
isOpen &&
<div className = "modalWrapper" >
<div className = "modal" >
<button onClick = {
() => setIsOpen(false)
} > close </button>
<div> {
isSubscriptionEnabled&&
<div>
Are you sure disable subscription ?
<button className = "button"
onClick = {
disableSub
} >
Disable subscription
</button>
</div>
} {
!isSubscriptionEnabled&&
<div>
Subscription successful disabled
<button onClick = {
() => setIsOpen(false)
} > Thanks </button>
</div>
} {
!isSubscriptionEnabled&&
<div>
Enable subscription by clicking on button
<button className = "button"
onClick = {
enableSub
} >
Enable subscription
</button>
</div>
} </div>
</div>
</div>
}
{
isSubscriptionEnabled&&
<button className = "button"
onClick = {
() => setIsOpen(true)
} >
Disable subscription
</button>
} {
!isSubscriptionEnabled&&
<button className = "button"
onClick = {
() => setIsOpen(true)
} >
Enable subscription
</button>
}
</div>
)
}
ReactDOM.render( < App / > , document.getElementById('app'));
React components only render when we change a component using its useState inside that particular component. it will not rerender on your global variable
Please try to format your code at least before posting here,

Count using useState doesnt update state until question 6 even when answered correctly react

im trying to create a quiz app in react using hooks. i want the answers to be clickable and once clicked the user will then move onto the next question. My problem is that, the score state isnt updating until question 6! i am making an API call to get the questions and answers using useEffect. i know that useState is asynchronous and thats why state doesnt update straight away, its just even if i answer the first 6 questions correctly, after question 6 the score is still showing 1. Does anyone have a way around this?
My API call using useEffect:
useEffect(() => {
axios.get("https://my-quiz-server.herokuapp.com/api/newq").then((res) => {
const allQuestions = res.data;
setResult([allQuestions]);
})
.catch((error) => {
console.log(error);
});
}, [setResult]);
My Quiz component:
import React, {
useState,
useContext,
useEffect
} from "react";
import {
QuizContext
} from "../Helpers/context";
const MainQuiz = () => {
const {
score,
setScore,
result
} = useContext(QuizContext);
const [currentQuestion, setCurrentQuestion] = useState(0);
const [optionChosen, setOptionChosen] = useState("");
console.log(optionChosen);
console.log(result);
const nextQuestion = (correctAnswer) => {
if (optionChosen === correctAnswer) {
setScore((score) => score + 1);
}
setCurrentQuestion((currentQuestion) => currentQuestion + 1);
};
useEffect(() => {
console.log("score updated", score);
}, [score]);
return ( <
div className = "quiz" > {
result.map((question, index) => {
if (currentQuestion < question.allQuiz.length) {
return ( <
h3 key = {
index
} > {
question.allQuiz[currentQuestion].q_prompt
} < /h3>
);
} else {
return null;
}
})
} <
div className = "answer__container" > {
result.map((answers, index) => {
if (currentQuestion < answers.allQuiz.length) {
return ( <
div className = "answer__options" > {
" "
} <
button className = "question__choices"
onClick = {
() => {
setOptionChosen("a");
nextQuestion(
result[0].allQuiz[currentQuestion].q_correctAnswer
);
}
} >
{
answers.allQuiz[currentQuestion].a
} <
/button> <
button className = "question__choices"
onClick = {
() => {
setOptionChosen("b");
nextQuestion(
result[0].allQuiz[currentQuestion].q_correctAnswer
);
}
} >
{
answers.allQuiz[currentQuestion].b
} <
/button> <
button className = "question__choices"
onClick = {
() => {
setOptionChosen("c");
nextQuestion(
result[0].allQuiz[currentQuestion].q_correctAnswer
);
}
} >
{
answers.allQuiz[currentQuestion].c
} <
/button> <
button className = "question__choices"
onClick = {
() => {
setOptionChosen("d");
nextQuestion(
result[0].allQuiz[currentQuestion].q_correctAnswer
);
}
} >
{
answers.allQuiz[currentQuestion].d
} <
/button> <
/div>
);
} else {
return null;
}
})
} <
/div> <
span > {
score
} < /span> <
/div>
);
};
export default MainQuiz;

Using Use Effect with hooks

I am trying to create a demo weather fetching app , I need to display weather data of city name as typed , can it be achieved with us effect or there is any other approach for the same
also I need to display results only if data exits currently in my code if data is not available .. default state data is showing kindly suggest to fix both issues
import React, {
useState,
useEffect
} from "react";
import Clock from "react-live-clock";
import "./Weather.css";
import {
ToastContainer,
toast
} from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import {
API_KEY
} from "./Api";
export default function Weather() {
const [city, setcity] = useState("goa");
const [currentweather, setcurrentweather] = useState("");
const [icon, seticon] = useState("");
const [weathertext, setweathertext] = useState("")
const lpsearch = () => {
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`;
if (city) {
fetch(url)
.then((res) => res.json())
.then((data) => {
if (data.cod === "404") {
// console.log("City Not found");
toast.error(`Entered City-Name ${city} Not Found `, {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
setcity("");
} else {
console.log(data);
setcurrentweather(data.main.temp);
setweathertext(data.weather[0].description)
seticon(data.weather[0].icon);
setcity("");
}
// setcity("");
});
}
};
let inputhndl = (event) => {
setcity(event.target.value);
};
return ( <
div >
<
ToastContainer position = "top-center"
autoClose = {
2000
}
hideProgressBar = {
false
}
newestOnTop = {
false
}
closeOnClick rtl = {
false
}
pauseOnFocusLoss draggable pauseOnHover /
> {
" "
} <
div className = "container-fluid" > {
" "
} <
h2 className = "text-center alert-success font-weight-bolder " >
<
Clock format = {
"dddd, DD MMMM , YYYY, h:mm:ss"
}
ticking = {
true
}
/> <
/h2> <
/div> <
div className = "lpcentered " >
<
h3 className = "alert-info text-capitalize text-center" >
Enter City 's <i className="fas fa-city text-secondary"></i> Name <
/h3> <
input onChange = {
inputhndl
}
value = {
city
}
placeholder = "Enter Here"
className = "form-control btn-outline-warning font-weight-bolder mb-3 mt-3" >
< /input> <
button className = "form-control btn-success font-weight-bold "
onClick = {
lpsearch
} >
Search < i className = "fas fa-search " > < /i> <
/button> <
div className = "text-center" >
<
h3 className = "alert-secondary text-capitalize" > {
city
} < /h3>
<
h3 className = "text-capitalize alert-info" > {
city
} < i class = "fas fa-temperature-low" > < /i> - {currentweather} <span>℃</span > < /h3> <
h3 > {
weathertext
} < img src = {
`http://openweathermap.org/img/wn/${icon}#2x.png`
}
alt = "icon"
srcset = "" /
> < /h3>
<
/div> <
/div> <
/div>
);
}

How to access component methods in React?

I am working on React.
I have a method called on_render_cell, where I have created a div and I am inserting image in that div based on some conditions.
This is the approach I am following to insert image in the div.I get the desired images. Now my goal is:
To open a modal when the image is clicked. When I try to assign onClick={this.openModal()}, the modal doesn't pops up. I noticed that this is because this points to the <img>. Can anyone help me how can I call openModal() on click handler of image tag written in result variable of on_render_cell()?
export class ScheduleManager extends SampleBase {
constructor() {
super(...arguments);
this.state = {
visible : false
}
}
openModal() {
this.setState({
visible : true
});
}
closeModal() {
this.setState({
visible : false
});
}
on_render_cell(args) {
let ele = document.createElement('div');
var sum=0;
var cursor=Event.find({Teacher:teacherName});
cursor.forEach(function(event){
if(convert(event.StartTime)===convert(args.date))
sum = sum + parseFloat(event.Duration);
});
let hoursPerDay = sum/60;
let percentHours=(hoursPerDay/maxHoursPerDay)*100;
let result ='';
if(percentHours===0)
{
result='<img id="aaa" ref="abc" className="weather-image" height="25px" width="25px" src="http://www.clker.com/cliparts/h/e/s/t/j/U/grey-circle.svg.thumb.png" onClick={console.log(this)} />';
}
else if(percentHours<=25)
{
result = '<img className="weather-image" src= "http://www.clker.com/cliparts/0/w/P/n/G/3/blue-circle-th.png" />';
}
else if(percentHours>25 && percentHours<=50)
{
result='<img className="weather-image" src= "http://www.clker.com/cliparts/o/b/y/x/Z/c/yellow-dot-th.png" />';
}
else if(percentHours>50 && percentHours<=75)
{
result = '<img className="weather-image" src= "http://www.clker.com/cliparts/1/A/W/q/h/h/orange-circle-th.png" />';
}
else
{
result='<img className="weather-image" src= "http://www.clker.com/cliparts/3/m/Q/u/P/J/red-circle-small-new.svg.thumb.png" />';
}
ele.innerHTML = result;
(args.element).appendChild(ele.firstChild);
}
render(){
return (
<div>
<input type="button" value="Open" onClick={() => this.openModal()} />
<Modal
visible={this.state.visible}
width="400"
height="300"
effect="fadeInUp"
onClickAway={() => this.closeModal()}
>
<div>
<h1>Title</h1>
<p>Some Contents</p>
<a href="javascript:void(0);" onClick={() => this.closeModal()}>Close</a>
</div>
</Modal>
<p>Grey circle denotes no classes for the day</p>
<p>Blue circle denotes less than 25% occupancy for the day</p>
)
}
}
Goal : Open Modal on image click. i.e, access openModal() of component
You can give some var like myRef to your componen as a prop, then in onComponentDidMount of your component assign to prop myRef current instance (this). this.props.myRef = this, then in your parent component you can use methods of myRef. For more you can check this post React.js - access to component methods
sorry but you are not doing it right. when you write:
onClick={() => this.openModal()}
you are creating a new function each time the element renders. instead, I suggest you to bind the method inside the constructor:
this.openModal = this.openModal.bind(this);
and inside the input write:
onClick={this.openModal}
this way you won't create a new function each time the elements renders, and the openModal this will point to the element itself.
If I understand correctly the problem is in this line:
result='<img id="aaa"... onClick={console.log(this)} />';
have you tried pass JSX instead of a string? bind the function openModal in the constructor, and pass to the img the function this.openModal. I think that if you will pass JSX instead of a string it will work
UPDATE
ok so I took the code from Here and edited it a bit:
export class CellTemplate extends SampleBase {
getCellContent(date) {
if (date.getMonth() === 10 && date.getDate() === 23) {
return ( < div > < img src = "src/schedule/images/thanksgiving-day.svg" / > < div className = "caption" > Thanksgiving day < /div></div > );
}
cellTemplate(props) {
if (props.type === "monthCells") {
return ( < div className = "templatewrap" > {
this.getCellContent(props.date)
} > < /div>);
}
return;
}
render() {
return ( < div className = 'schedule-control-section' >
<
div className = 'col-lg-12 control-section' >
<
div className = 'control-wrapper' >
<
ScheduleComponent cssClass = 'cell-template'
width = '100%'
height = '650px'
selectedDate = {
new Date(2017, 11, 15)
}
cellTemplate = {
this.cellTemplate.bind(this)
} >
<
ViewsDirective >
<
ViewDirective option = 'Month' / >
<
/ViewsDirective> <
Inject services = {
[Month, Resize, DragAndDrop]
}
/> <
/ScheduleComponent> <
/div> <
/div> <
/div>);
}
}
in cellTemplate you can see how to call getCellContent correct, and in getCellContent you can see how I would have return JSX.

reactjs setState before render on update

I have a react component and the requirement is to setState before render on update (url hash change). Below is code snippet:
componentConfig: function() {
.....
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
},
I was it working before, I was calling this method from getInitialState and it was working fine. getInitialState fires only once so I was not able to update it on url change. I tried various other inbuilt update methods such as componentWillReceiveProps but they are one step behind. Seems like render happens before this method gets called. I also tried to call it from render but obviously states get confused and it breaks.
As this image demonstrates, componentRillReceiveProps always behind render. I need something that fires before render each time on url update. Hope it makes sense.
or in other words, I would like to fire getInitialState on hash change.
var React = require('react'),
projectsData = require('./../projects'),
ProjectsRow = require('./projects_row'),
itemsInRow = 3,
noOfDefaultRows = 2,
projects = [],
currentProjects = [],
currentPageRows,
currentParamKey;
var Projects = React.createClass({
componentWillMount: function() {
this.componentConfig(this.props);
},
componentWillReceiveProps: function(nextProps){
this.componentConfig(nextProps);
},
componentConfig: function(props) {
var rows = [],
currentParamKey = 'projects',
loadMoreIsVisible = true,
i;
if(props.params.key) {
currentParamKey = props.params.key;
}
projects = projectsData.getByKey(currentParamKey);
projectsData.currentState[currentParamKey] = noOfDefaultRows;
currentProjects = projects.slice(); //Create a copy or array
noOfDefaultRows = projectsData.currentState[currentParamKey] || noOfDefaultRows;
for (i = 0; i < noOfDefaultRows; i++) {
if(currentProjects.length) {
rows.push(currentProjects.splice(0, itemsInRow));
}
}
currentProjects.length ? loadMoreIsVisible = true : loadMoreIsVisible = false;
this.setState({rows: rows});
this.setState({loadMoreBtn: loadMoreIsVisible})
console.log('Finished executing componentConfig and currentParamKey = ' ,currentParamKey);
},
loadMoreProjects: function(e) {
e.preventDefault();
var addRow = this.state.rows;
if(currentProjects.length) {
currentPageRows++;
addRow.push(currentProjects.splice(0, itemsInRow));
this.setState({rows: addRow});
}
if(!currentProjects.length) {
this.setState({loadMoreBtn: false})
}
},
render: function() {
console.log('Now in render and currentParamKey = ' ,currentParamKey);
var projectUrl;
//currentParamKey = this.props.params.key;
if(currentParamKey === 'projects') {
projectUrl = '#/project';
} else {
projectUrl = '#/project/' + currentParamKey
}
return (
< div className="projects">
< div className = "jumbotron" >
< div className = "container" >
< h1 > Projects < /h1>
< /div>
< /div>
< div className = "container" >
{this.state.rows.map(function(row, i) {
return <ProjectsRow url={projectUrl} row={row} key={i} />
}.bind(this))}
< /div>
< div className = "container text-center" >
<a id="loadMore" className= {this.state.loadMoreBtn ? 'linkStyle1' : 'hide'}
onClick = {this.loadMoreProjects}
role="button" > <i className="fa fa-angle-down"></i><span>Load More Projects</span>
</a>
<br />
<br />
<div className="contact-me-link">
<a className="linkStyle1" href="#/contact">
<i className="fa fa-angle-right"></i><span>Contact</span>
</a>
</div>
</div>
< /div>
);
}
});
module.exports = Projects;
The componentWillReceiveProps get new props as a parameter. The old props remain unchanged on this method execution, so you need to initialize your state based on this parameter. Try passing the props as a parameter to your componentConfig method:
componentWillMount: function() {
this.componentConfig(this.props);
},
componentWillReceiveProps: function(nextProps){
this.componentConfig(nextProps);
},
componentConfig: function(data) {
...
}

Categories