how to control child elements by onClick from parent in reactjs? - javascript

crafting basic app in react as following:
parent container receive state by ajax and contains four columns, left column - all messages items, second column message body (should be shown when message element is clicked as well as controls), next - message controls (next, prev) and action type:
how to to properly attach a controls to children elements for instance for onClick to message element? here is the snippet of a parent:
var ModerationContainer = React.createClass({
getInitialState: function () {
return {data: []};
},
componentDidMount: function () {
...
},
LoadMessagesFromApi: function () {
jQuery.ajax({
... // loads messages from json api into state
});
},
testor: function () {
alert();
},
render: function () {
var allMessageItems = this.state.data.map(function (message) {
return (
<MessageItem id={message.id} key={message.id} onClick={this.testor}/>
);
}, this);
return (
<div>
<div className="col-md-2 messageColumn">
{allMessageItems}
</div>
<MessageBodyColumn/>
<ControlsColumn />
<BlockColumn />
</div>
);
}
});
No onclick event is executed after i click message block althrought I attached this to map while rendering messages block, what did i wrong ?
Also, how it is possible to auto select first message item if none of them clicked ?
Any hints or links on tutorials from experienced with react people much appreciated

I would right the MessageItem on the parent like
<MessageItem key={message.id} onClick={this.testor.bind(this, message.id) }/>
Then inside your MessageItem component you can take the onClick handler from the pros, lets say MessageItem is a div your render function could be like
render()
{
const onClick = this.props.onClick;
const label = `Message${this.props.key}`;
return( <div onClick={ onClick }> { label }</div>)
}
and if you write your testor like
testor: function ( id ) {
alert( id );
}
You can see the id of the clicked message.

Related

React. How to pass an arg to a function called by an onClick without autotriggering it

I have this piece of code.
Where the problem I am facing is that is missing a prop which I want to be an id, obtained inside the map function.
Since I am unable to find a way to send the id to the component outside map, I figured I would do this:
This is my render function
render() {
var users = this.state.userList;
const Table = Reactable.Table,
Td = Reactable.Td,
Tr = Reactable.Tr;
if (users.length === 0) {
return <p>loading</p>
}
return (
<div class="maincontainer">
<div className="content-landing">
<Table
className="table"
filterable={['Email']}
itemsPerPage={8}
currentPage={0}
sortable={true}
>
{users.map((row) => {
return (
<Tr className={row.className}>
<Td column="Email">{row.email}</Td>
<Td column="Edit" ><FontAwesomeIcon className="editIcon" onClick={this.showModal(row.id)} icon={faEdit} /></Td> //----THIS.SHOWMODAL IS BEING AUTOEXECUTED WITHOUT ACCOUNTING FOR THE CLICKING
</Tr>
)
})}
</Table>
<EditUserModal show={this.state.showModal} close={this.closeModal} row={this.state.rowId}/> //---I WANT THIS TO RECEIVE A row.id FROM THE ABOVE MAP
</div>
</div>
)
}
I have written a couple comments in the parts where I want to make the changes.
I also thought about putting <EditUserModal> , inside the <Td> , but since its an external npm module it crashes, it only admits text.
So my solution was, to pass the row.id to the showModal function, and try to set is a state from there.
showModal(rowId) {
// console.log("showmodal state before any click")
// console.log(this.state.showModal)
console.log("triggered show modal")
console.log(rowId)
this.setState({
showModal: true,
rowId: rowId
}, () => {
// console.log("clicked show modal")
// console.log(this.state.showModal)
});
}
I think it should work, but since the function has a () , it auto executes without waiting for any click, making my app to crash.
In your code you are executing the function directly: this.showModal(row.id).
You have to use a callBack function to pass row.id something like:
onClick={()=> this.showModal(row.id)}
This should solve your problem.
You can use a callBack function in the onClick like this:
onClick={()=> this.showModal(row.id)}
Or you can define the showModal function like this:
showModal = (rowId) => () => {
...
}
and onClick={this.showModal(row.id)}
For people who does not understand arrow functions, the above solution is similar to this:
function showModal(rowId) {
return function () {
...
}
}
The showModal function returns another function that will be triggered in the onClick event.

Understanding synthetic events in ReactJS

I need some help with understanding the so-called synthetic events in ReactJS. I wrote the following toy program that has a Video component and a VideoList component. When a video in the rendered list of videos is clicked, I would print out what video gets clicked in the console.
I don't understand how the event onVideoSelected() gets defined. Is it replaced by the onClick() event in the rendered Video component?
Thanks!
var Video = React.createClass({
handleClick: function() {
this.props.onVideoSelected(this.props.title);
},
render: function() {
return <li><div onClick={this.handleClick} className="bg-success">{this.props.title}</div></li>;
}
});
var VideoList = React.createClass({
propTypes: {
data: React.PropTypes.array.isRequired
},
handleVideoSelected: function(title) {
console.log('selected Video title is: ' + title);
},
render: function() {
return (
<div className="panel panel-default"><div className="panel-heading">List of Videos</div><ul>
{data.map(function (v) {
return <Video onVideoSelected={this.handleVideoSelected} key={v.title} title={v.title} />;
},this)}
</ul></div>
);
}
});
var data = [
{title: 'video title 1', link: 'http://www.youtube.com/1'},
{title: 'video title 2', link: 'http://www.youtube.com/2'},
{title: 'video title 3', link: 'http://www.youtube.com/3'}
];
React.render(<VideoList data={data} />, document.getElementById('videolist'));
There's actually no magic going on here, just passing functions around. onVideoSelected is a function reference that you passed into the Video component via a property; said another way, the flow goes like this:
What happens when you click the div? Call this.handleClick.
What happens when you call handleClick? Call this.props.onVideoSelected.
How is onVideoSelected defined? It got passed into the component, just like any other property.
What was passed in to the onVideoSelected property? A reference to the VideoList's handleVideoSelected function.
It may help to compare it to some sorta-similar, simplified jQuery code:
function handleVideoSelected(title) {
console.log('selected Video title is: ' + title);
}
function createVideoDiv(onVideoSelected, title) {
var div = $("<div className="bg-success"></div>").text(title).appendTo(...);
div.on("click", function() {
// call the function that was passed to us
onVideoSelected(title);
});
}
$.each(videos, function(idx, video) {
createVideoDiv(handleVideoSelected, video.title);
});
In the jQuery version, you pass handleVideoSelected into createVideoDiv; similarly, in the React version, you pass handleVideoSelected into Video via props.
After your onClick handler is called in the Video component you are no longer dealing with events; these are plain old function calls.
To keep a reference to the video title, pass a curried version of handleVideoSelected with the title as the first arg by using Function.prototype.bind:
{this.props.data.map(function (v) {
return <Video onVideoSelected={this.handleVideoSelected.bind(this, v.title)} key={v.title} title={v.title} />;
}, this)}
(I also prepended this.props to data. Looks like a typo in your code.)
This is how individual Todos are identified in the "Expose Component Functions" doc.

anchor tag (a tag) onclick event handler not working

Though i have included the onclick handler for the a tag in the html returned by the render method of the reactjs component(component with the name renderLocationLink) , though the rendering takes place correctly the onclick handler attribute doesnt appear in the rendered html on the webpage .I want the Not able to figure whats the issue , here is the code
var feedApp = React.createClass({
getInitialState: function(){
return {
data : [
{display_name:"Rao",content:"this is Rao post",links:['link1','link2','link3']},
{display_name:"Sultan",content:"this is Sultans",links:['link4','link5','link6']},
{display_name:"John",content:"this is John post",links:['link7','link8','link9']}
]
}
},
fetchFeedsFromUrl: function(){
console.log('Onclick triggered');
},
render: function(){
return (<Feeds data={this.state.data} onClick={this.fetchFeedsFromUrl} />)
}
})
var Feeds = React.createClass({
render: function(){
var onClickfunc = this.props.onClick;
var feeds = this.props.data.map(function(feed){
return (
<oneFeed name={feed.display_name} onClick={this.onClickfunc} content={feed.content} links={feed.links} />
)
});
return(
<div> {feeds} </div>
)
}
})
var oneFeed = React.createClass({
render: function() {
return (
<div>
<h3>{this.props.name}</h3>
<renderLocationLink onClick={this.props.onClick} linkArray={this.props.links} />
<p>{this.props.content} </p>
</div>
)
}
});
var renderLocationLink = React.createClass({
render: function(){
var onClick = this.props.onClick;
var locationLinks = this.props.linkArray.map(function(link,index){
return (<a onClick={this.onClick} href={link}>{link} </a>)
})
return ( <div >{locationLinks}</div> )
}
})
React.renderComponent(feedApp(null),document.body);
You do not need to reference "this" in your map functions to access your local variable. Remove "this" when you try to access the onClick variable.
var renderLocationLink = React.createClass({
render: function(){
var onClick = this.props.onClick;
var locationLinks = this.props.linkArray.map(function(link,index){
return (<a onClick={onClick} href={link}>{link} </a>)
})
return ( <div >{locationLinks}</div> )
}
})
Your rendered markup will not contain an onClick attribute. What you write in your JSX markup is not a direct HTML markup.
What will happen instead is that React will give your markup a data-reactid attribute, and will make sure its own event handlers fire something when a specific data-reactid gets clicked.
Ok, so I have found out where it goes wrong:
In many components you were using this incorrectly. You were using this within the render function. So instead of using
{this.onClick} you should have been using {onClick} instead.
Look at this example, how we use {onClick} (and not {this.onClick}) in the returned render.
var Feeds = React.createClass({
render: function(){
var onClickfunc = this.props.onClick;
var feeds = this.props.data.map(function(feed){
return (
<oneFeed name={feed.display_name} onClick={onClickfunc} content={feed.content} links={feed.links} />
)
});
return(
<div> {feeds} </div>
)
}
})
Here's a working JSFiddle: http://jsfiddle.net/kb3gN/6771/
PS: This is exactly as Butters suggested.

Dynamically add new component

I've been playing with ReactJS and have two components like:
/** #jsx React.DOM */
var MyDiv = React.createClass({
render: function () {
return (
<div>
Hello World
</div>
)
}
});
var MyClickableDiv = React.createClass({
addDiv: function () {
alert("Hello World"); //For testing
}
render: function () {
return (
<div>
<MyDiv />
<a href='#' onClick={this.addDiv}>Add new MyDiv</a>
</div>
)
}
});
What I'm trying to do is: upon clicking "Add new MyDiv", I want to add a new MyDiv component under the first MyDiv that I already have.
I think a more react-minded approach would be to make the state of whether the second div is present or not explicit and put all the rendering inside the render function instead of splitting it, half in render and the other half in addDiv.
var MyClickableDiv = React.createClass({
getInitialState: function(){
return {showDiv: false};
},
addDiv: function () {
this.setState({showDiv: true});
},
render: function () {
return (
<div>
<MyDiv />
{this.state.showDiv ? <MyDiv /> : null}
<a href='#' onClick={this.addDiv}>Add new MyDiv</a>
</div>
)
}
});
If you want addDiv to keep adding divs when you click it again, change the state so that instead of a boolean flag you keep a list of the extra divs that should be rendered.

ReactJS Cortex Object updated by render not invoked?

I am trying to implement Emberjs's Todo app as a practice exercise for Cortex by mquan on github. I am currently implementing the "All", "Active", "Completed" filter where clicking an anchor will result in the anchor being highlighted (class added).
I created the following:
var filtercortex = new cortex([
{title:'all', selected:true, key:1},
{title:'completed', selected:false, key:2},
{title:'active', selected:false, key:3}
]);
With the following render function (in the parent):
render: function() {
var filters = filterCortex.map(function(filter) {
return (
<li>
<FilterAnchor cortex={filterCortex} filter={filter} />
</li>
)
});
...
return ...
<ul id='filters'>
{filters}
</ul>
And FilterAnchor's definition:
var FilterAnchor = React.createClass({
handleClick: function() {
var that = this;
this.props.cortex.forEach(function(filter) {
if (filter.key.getValue() == that.props.filter.key.getValue()) {
console.log(filter.title.getValue(), true);
filter.selected.set(true);
} else {
console.log(filter.title.getValue(), false);
filter.selected.set(false);
}
});
return false;
},
render: function() {
var className = (this.props.filter.selected.getValue()) ? 'selected' : '';
return (
<a className={className} href="#" onClick={this.handleClick}>
{this.props.filter.title.getValue()}
</a>
)
}
});
right now, I do not see the class 'selected' being applied to the anchor links when I am clicking.
However, upon investigation I notice this:
Clicking "All":
All true
Completed false
Active false
Clicking "Completed":
All true
Completed false
Active false
So I am certain that the objects inside filtercortex has been updated properly (you can open up firebug to check). However, FilterAnchor.render is not being triggered.
Is this a bug?
Source code: https://github.com/vicngtor/ReactTodo/blob/cortex/script.jsx
The sample at the top of the Cortex readme has this at the bottom:
orderCortex.on("update", function(updatedOrder) {
orderComponent.setProps({order: updatedOrder});
});
Is there an equivalent section in your code? If not, then the problem is that the update event for the cortex data store isn't set to trigger an update of the view, which is made through a call to setProps on the top level React component in this example.

Categories