Dynamically add new component - javascript

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.

Related

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

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.

React.js state confusion

I am still trying to understand the state concept in react.js. Can anyone please help with the below jsfiddle? I am trying to filter the records based on the category selected.
var App = React.createClass({
render: function() {
return (
<div>
<Instructions />
<h1>Requests</h1>
</div>
);
}
});
From what I've found with react, communicating changes between components that don't have a parent-child relationship kind of requires the state to be managed in a top-level component that is a parent to both the components that are trying to communicate. In your example, App is your top-level component that contains MySelect and DisplayRecords as children. If you want the status of MySelect to affect the rows shown in DisplayRecords, you'll have to manage that in the state of App.
In the example, I moved the select box' selection to the state of App, and passed props to the different components accordingly. I tried my best to explain the notable changes with comments, but if you have questions about any changes, definitely leave a comment!
var DisplayRecords = React.createClass({
render: function(){
var _this = this; // avoid conflicting this keyword
return (
<div>
<table><tbody> // include tbody to avoid errors (weird react thing)
{_this.props.records.map(function(record){ // loop through each record
// if all records is selected, or the record status matches the selection
if(_this.props.filter=="All Requests" || record.status == _this.props.filter){
// return the record as a table row
return (
<tr key={record.id} >
<td>{record.title}</td>
<td>{record.status}</td>
<td>{record.updated_at}</td>
<td>{record.created_at}</td>
<td>Delete</td>
</tr>
)
}
})}
</tbody></table>
</div>
)
}
});
var MySelect = React.createClass({
callParentFunction: function(e) {
// call parent's getFilter function with the selected option's text as argument
this.props.changeHandler(e.target.options[e.target.selectedIndex].text);
},
render: function() {
// note removed specified value of select box
return (
React.createElement("select", { onChange: this.callParentFunction},
React.createElement("option", { value: 1 }, "All Requests"),
React.createElement("option", { value: 2 }, "Approved"),
React.createElement("option", { value: 3 }, "Denied"),
React.createElement("option", { value: 4 }, "Pending")
)
)
}
});
var App = React.createClass({
getInitialState: function(){
// set initial selection
return {
selected: "All Requests"
}
},
getFilter:function(newFilter){
// set new selection on change of select box
this.setState({selected: newFilter})
},
render: function() {
// pass selected state to both MySelect and DisplayRecords
// pass getFilter to MySelect so it can be called onChange
return (
<div>
<MySelect selection={this.state.selected} changeHandler={this.getFilter} />
<h1>Requests</h1>
<DisplayRecords records={this.props.data} filter={this.state.selected} />
</div>
);
}
});
React.render(<App data={requests}/>, document.getElementById('container'));

React: Unable to access child props in parent's event handler

I'm using React to create a UI and I have a parent component and a child component, something along these lines:
// Child component
var ListItem = React.createClass({
render: function() {
var link_details = (
<div>
Start Date: {this.props.my_data.start_date}<br/>
End Date: {this.props.my_data.end_date}<br/>
</div>
);
return (
<li>
<a onClick={this.props.clickHandler}>
{ this.props.my_data.name }
</a>
{link_details}
</li>
)
}
});
// Parent component
var Sidebar = React.createClass({
getInitialState: function() {
return {
my_data: [],
};
},
handleListItemClick: function(e){
console.log(e.target);
console.log(e.target.props);
},
render: function() {
var myLinks = this.state.my_data.map(function(mylink) {
return (
<ListItem key={mylink.id} my_data={mylink} clickHandler={this.handleListItemClick} />
);
}.bind(this));
return (
<div>
<ul className="nav nav-sidebar">
{ myLinks }
</ul>
</div>)
}
});
I want the click event on the child to trigger the parent's handler so that the parent can update its state based on what was clicked in the child. While the code I have above works, and the parent's handler is called, I am unable to access any of the child component's props. I'm not sure if that's by design and I should pass data from the child to the parent in a different way, or if I'm doing something wrong. I'm still very new to React, so any advice is appreciated. Thanks!
You can not do that but you can pass data from child to parent via callback
<li>
<a onClick={this.props.clickHandler.bind(null,this.props.my_data.name)}>
{ this.props.my_data.name }
</a>
{link_details}
</li>
or using arrow function if you are using es6
<li>
<a onClick={() => this.props.clickHandler(this.props.my_data.name)}>
{ this.props.my_data.name }
</a>
{link_details}
</li>
Edit
Why passing null?
Things to remember:
Automatic binding methods to 'this' happens when your component mounts.
There are two conditions
1.Calling a callback passed from parent component to a child component
When we directly pass functions (e.g. this.clickHandler) to a child component without worrying about the value of 'this' when the function is actually called.
React then the replaces the standard Function.prototype.bind method with its own function to help stop you from doing anything silly (like trying to change the already-bound value of 'this'), so you instead have to pass 'null' to say "I understand this will only alter the arguments".
2.Calling a function defined within same component
React does not do this for function calls within the same component
Rules for binding
If you want to set the first argument by calling .bind on a function...
passed in via props, pass null as the first argument e.g.
this.props.funcName.bind(null, "args")
taken from 'this', pass 'this' as the first argument e.g.
this.funcName.bind(this, "args")
You can do so:
var ListItem = React.createClass({
clickItem: function (e) {
this.props.clickHandler(e, this.props.my_data); // now you can pass any data to parent
},
render: function() {
var link_details = (
<div>
Start Date: {this.props.my_data.start_date}<br/>
End Date: {this.props.my_data.end_date}<br/>
</div>
);
return (
<li>
<a onClick={this.clickItem}>
{ this.props.my_data.name }
</a>
{link_details}
</li>
)
}
});
I took a look at the answer on Pass props to parent component in React.js and came up with the following:
// Parent component
var Sidebar = React.createClass({
getInitialState: function() {
return {
my_data: [],
};
},
handleListItemClick: function(data_passed, e){
console.log(data_passed);
},
render: function() {
var myLinks = this.state.my_data.map(function(mylink) {
return (
<ListItem key={mylink.id} my_data={mylink} clickHandler={this.handleListItemClick.bind(null, mylink.id)} />
);
}.bind(this));
return (
<div>
<ul className="nav nav-sidebar">
{ myLinks }
</ul>
</div>)
}
});
This does seem to work- I'd be interested in seeing other solutions and which one is the "best" and why.

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.

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