I have the following reactJS/JSX code :
var LikeCon = React.createClass({
handleClick: function(like) {
return;
},
render(){
return this.renderLikeButton(this.props.like, this.props.likeCount)
},
renderLikeButton(like, likeCount){
return (
content = <div className={like==true ? "likeButConAct" : "likeButCon"}>
<div className="likeB" onClick={this.handleClick(!like)} > </div>
{ likeCount > 0 ? <div className="likeCount">{likeCount}</div>: null}
</div>
);
}
});
The problem is that handleClick will never be triggered even when I click the likeB div? Why?
Edit :
This is the code that uses the LikeCon component :
var TopicComments = React.createClass({
render: function() {
var comment = this.props.data.map(function(com, i) {
return (
<article>
<div className="comment">
<div className="tUImgLnk">
<a title={com.UserName} target="_blank" href={com.UserInfoUrl}>
<img className="tUImg" src={com.UserPicSrc} />
</a>
</div>
{com.UserName}
<div className="content">
{com.Message}
</div>
<div className="status">
<div className="dateCreated dimText">
{com.DateCreated}
</div>
<LikeCon like={com.Like} likeCount={com.LikeCount} />
<article></article>
</div>
</div>
</article>);
}.bind(this));
return(
<div className="comments">
{comment}
</div>
);
}
});
I suspect the problem is that the LikeCon is generating a markup for the TopicComment so the handleClick is not really there when triggered from the TopicComment. Is there a simple way to fix this?
You should be passing handle click event like so:
<div className="likeB" onClick={this.handleClick.bind(this,!like)} > </div>
With your current version you are passing result of executing this.handleClick(!like) to onClick handler which is undefined.
With above version you are passing a function which takes !like as its first parameter when executed.
Update:
Also since your div only contains a single space character, it is difficult to find the space character and click on it. If you add a text and click on that text, you will see the handle function is being executed:
working fiddle : http://jsfiddle.net/an8wvLqh/
Related
I have this piece of code, I want to show replies after the click event but it doesn't seem to fire or render.
// function for rendering comment's replies
const renderReplies = (comment) =>{
if(comment.data.replies){
return (
<div className="reply">
{comment.data.replies.data.children.map(reply => {
if(reply.data.body){
return (
<div className="comment-card">
<span className="comment-author">{reply.data.author}</span>
<ReactMarkdown>{reply.data.body}</ReactMarkdown>
<div className="upvotes">
<ImArrowUp id="comment-arrow-icon" />
{reply.data.score}
</div>
{showMoreReplies(reply)}
</div>
)
}
})}
</div>
)}}
const showMoreReplies = (reply) => {
if(reply.data.replies){
return (
<span className="show-all-replies" onClick={() => renderReplies(reply)} >Show more replies <HiArrowNarrowRight className="show-more-replies-arrow" /> </span>
)
}
}
If I execute renderReplies() within itself like this:
</div>
{renderReplies(reply)}
</div>
then the replies show up properly. The only issue is that I want them to show up after click event. I could use display: none but since I have a lot of comments with their own replies it will be a bit complicated
I don't succeed by defining a function
and call this function below by just changing className for each element ..
Here is the code:
const ProgressBar = (props)=>{
return(
<div className={props.styleName}>
<div className={classes.ProgressBarGradient}>
<div className={classes.GradientHider}/>
</div>
</div>
)
}
const GridContent = (props)=>{
return (
<div className={classes.Container}>
<h3 className={classes.Title1}>progress vs target</h3>
<h3 className={classes.Title2}>weekly goal</h3>
<h3 className={classes.Title3}>monthly goal</h3>
<ProgressBar styleName="ProgressBar1"></ProgressBar>
</div>
);
}
What I want is to change only the className of the first div when I call the function below.
Thank you so much :)
PS: I use css modules so when I call my class I usually do className={classes.className}
In your ProgressBar use this :
<div className={classes[props.styleName]}>
I'm trying to create a select2 style component in React.
I have got 90% functionality down, the one bit I just can't fathom is hiding the result box when the user clicks away
The render method is:
render() {
let resultBlock;
if (this.state.showSearch) {
resultBlock = (
<div className="search-input-container" onBlur={this.onBlur}>
<div className="search-input-results">
<input
type="text"
name={this.props.name}
placeholder={this.props.placeholder}
className="form-control"
onChange={this.inputKeyUp}
autoComplete="false" />
<ul>
{this.state.items.map((item, i) => <li key={i} data-value={item.id} onClick={this.itemSelected} className={item.isSelected ? 'selected' : ''}>{item.text}</li>)}
</ul>
</div>
</div>
);
}
let displayBlock;
if (this.props.value.text) {
displayBlock = this.props.value.text;
} else {
displayBlock = <span className="placeholder">{this.props.placeholder}</span>;
}
return (
<div className="form-group">
<label htmlFor={this.props.name}>{this.props.label}:</label>
<div className="form-input">
<div className="searchable-dropdown" onClick={this.revealSearch}>
{displayBlock}
<div className="arrow"><i className="fa fa-chevron-down" aria-hidden="true" /></div>
</div>
{resultBlock}
</div>
</div>
);
}
I've tried moving onBlur={this.onBlur} around, but it only fires if the <input... had focus before one clicked away.
It can't be that complicated, the only approach I thought of, is attaching a global click handler to the page, and diff'ing clicks to understand if a user hasn't clicked on my component. But this seems over engineered.
How can this be achieved?
I achieved this functionality by:
Putting this in the constructor:
this.windowClick = this.windowClick.bind(this);
(From what dfsq said) Put this in componentDidMount:
if (window) {
window.addEventListener('click', this.windowClick, false);
}
This event handler:
windowClick(event) {
event.preventDefault();
if (event.target.classList.contains('searchable-marker')) {
return;
} else {
this.setState({
showSearch: false
});
}
}
Where searchable-marker is just a class I put on all the div's, ul's, li's and inputs to make sure that if I clicked one of these, it wouldn't close the the box.
Adding the unmount:
componentWillUnmount() {
window.removeEventListener('click', this.windowClick, false);
}
what you can try doing is onBlur you could change the value of this.state.showSearch = false and when this condition is satisfied add a className="hide" (hide{display: none}) by creating a custom function which returns a classname as a string.
I have this piece of code:
Drupal.behaviors.articleQuiz = (function(){
var _attach = function(context){
$('.question-container', context)
// .once()
.each(function(i, section){
new ArticleQuiz($(section));
});
};
return {
attach: _attach
};
})();
function ArticleQuiz($el){
this.$el = $el;
this.answer = this.$el.data('answer');
console.log('this.answer', this.answer);
this.quizLogic();
return this;
}
ArticleQuiz.prototype.quizLogic = function(){
var THIS = this;
$('.quiz-cols a').click(function(e) {
e.preventDefault();
// exit if choice already made: users can't change their pick
if ($(this).parents('.quiz-cols').parent().find('.white-font').length) {
return;
}
// set class according to data-answer:
$(this).addClass('background-' + (THIS.answer === true ? 'green' : 'red')).addClass('white-font');
console.log('answer', THIS.answer)
});
return THIS;
};
Drupal.behaviors.articleQuiz.attach($body);
In the function ArticleQuiz() you may see a console.log('this.answer', this.answer); which prints this and it's totally correct:
And then almost at the you may see this other console.log('answer', THIS.answer) which is within the click function and prints only true. Which means that is ignoring the other 2 falses that you might see in the picture I put above.
This is the html:
<div data-answer="true" class="question-container">
<div>
<h2>1. First question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
<div data-answer="false" class="question-container">
<div>
<h2>2. Second question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
<div data-answer="false" class="question-container">
<div>
<h2>3. Third question.</h2>
</div>
<div class="quiz-cols">
<div class="true-placeholder">...</div>
</div>
<div class="quiz-cols">
<div class="false-placeholder">...</div>
</div>
</div>
And just for you to know, the this.$el = $el; is pointing to div.question-container
As you see in that html there are 3 divs with class and data attribute data-answer="true" class="question-container", one of them is with data-answer=true and the other 2 are with data-answer=false.
So my question. Why in the first console.log I can see the 3 data-answer attributes coming up as they are: 1 true and 2 false. And in the click function it doesn't matter the container I click on, it only returns 3 true and ignores the false?
EDIT
The reference is working properly out of the click function.
You're creating a click handler for all the questions every time this.quizLogic() is called, instead of only for the current question. You can fix that by adding context to the selector before attaching the handler:
$('.quiz-cols a', this.$el).click(function(e) {
...
I am making a simple React.js project. The project can be found here.
The HTML is as follows:
<header>
<div class="container-center">
<h1 class="text-center">Markdown Previewer</h1>
</div>
</header>
<div class="container-center" id="main-container">
</div>
<footer>
<div class="container-center">
<p class="text-center">Copyright © Sergey Kosterin, 2016. All rights reserved.</p>
</div>
</footer>
The Javascript code is as follows:
var RawTextContainer = React.createClass({
render: function(){
return (
<h1>Raw Text</h1>
);
}
});
var MarkdownContainer = React.createClass({
render: function(){
return (
<h1>Markdown Text</h1>
);
}
});
var MainAppContainer = React.createClass({
render: function(){
return (
<div class="row">
<div class="col-md-6">
<RawTextContainer />
</div>
<div class="col-md-6">
<MarkdownContainer />
</div>
</div>
);
}
});
ReactDOM.render(<MainAppContainer />, document.getElementById('main-container'));
I want the app to show me two columns containing some text. But I don't see anything. What am I doing wrong?
React doesnt use class keyword. Instead of that it should be className. Here is a useful link about class & className keywords.
var MainAppContainer = React.createClass({
render: function(){
return (
<div className="row"> // className instead of class
<div className="col-md-6"> // className instead of class
<RawTextContainer />
</div>
<div className="col-md-6"> // className instead of class
<MarkdownContainer />
</div>
</div>
);
}
});
If it isn't the answer, then you have to provide a bit more information about your problem e.g. stack trace, errors etc. It's quite difficult to guess where is your problem.
Update
Worked example -> Pen Example i don't know why, but Pen doesnt recognise ReactDOM or you didn't include it. You can try to render your component through React.
React.render(<MainAppContainer/>, document...)
Also if you open browser console, you will get more information about some errors, or required statements (in your case jQuery isn't included file).
Thanks.