React update component state from another component - reactjs

I have one component as follow:
var SingleEditableModule = React.createClass({
getInitialState: function() {
return {
selected: false
};
},
show_overlay: function() {
$('.overlay').fadeIn();
},
render: function() {
var show_overlay = this.show_overlay;
return (
<div className="large-4 small-12 columns">
<h3 className="title">{this.props.data.title}</h3>
<div className="month">
<p>
{this.props.data.month}
</p>
</div>
<div className="img-holder">
<div
id={this.props.data.id}
onClick={show_overlay}
className="action_wrapper">
<span className="swap_trigger"></span>
<span className="action">
{this.props.data.action}
</span>
</div>
</div>
<h4>{this.props.data.title_description}</h4>
<p>{this.props.data.description}</p>
</div>
);
}
});
I want to assign a CSS class to this component based on "className" gained from "get_campus_id":
var Overlay = React.createClass({
close_overlay: function() {
$('.overlay').fadeOut();
},
get_campus_id: function(className) {
console.log(className);
},
render: function() {
var options = [],
get_campus_id = this.get_campus_id;
this.props.data.map(function(el, i){
options.push(<li
className={el.className}
onClick={get_campus_id.bind(null, el.className)}
key={i}>{el.location}</li>);
});
return (
<div className="overlay">
<div className="overlay-content">
<header className="clearfix">
<h3 className="float-left">Select your campus rotation</h3>
<div onClick={this.close_overlay} className="float-right close">
<span className="cancel">Cancel</span>
<span className="x">x</span>
</div>
</header>
<ul>
{options}
</ul>
<footer>
</footer>
</div>
</div>
)
}
});
"SingleEditableModule" represents an empty module which can be populated based on the value returned from "get-campus_id".
Full github url: https://github.com/WebTerminator/Hult

You cannot change the state of one component from another component. The best you can do is have both of them being children of a parent component, and then pass parameters as a prop. You can then use componentWillReceiveProps(nextProps) to intercept new props coming in (if you want to then modify a state based on that).

Related

State is null in React

I receive this error:
TypeError: this.state is null
Have code like this, but it does not work .... Any idea why?
I want to change the text of a label (reanalyzeButton)
Read several docs and tutorials and it seem it should work. No idea why it behaves like this.
This is inherited code I work with using React 0.13
var ProjectHeader = React.createClass({
displayName: 'ProjectHeader',
intervalId: null,
state: {
projectjson: [],
label: '',
},
componentDidMount() {
// Now we need to make it run at a specified interval
this.intervalId = setInterval(this.refresh, 1000);
this.setState({ label: '<span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>'});
},
refresh : function(){
if (this.state.projectjson.analysis_status == 'succeeded') {
clearInterval(this.intervalId);
this.setState({label: '<A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>'});
}
render : function(){
if (props.project.analysis_status == 'in_progress') {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request a re-analysis of the project"><i className="fa fa-refresh fa-spin" /> Analysis in progress</A>
reanalyzeButton = this.state.label
} else if ((!props.project.analyze) || props.project.analysis_priority == 0) {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>
reanalyzeButton = this.state.label
} else {
//reanalyzeButton = <span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>
reanalyzeButton = this.state.label
}
return <div className="project-header" itemScope itemType="http://schema.org/Code">
<div className="row">
<div className="col-xs-12 col-sm-9">
<div className="clearfix">
{projectHeader}
</div>
</div>
<div className="col-xs-12 col-sm-3">
<span className="qc-badge">
{badge}
</span>
</div>
</div>
<div className="row">
<div className="col-xs-12">
<ul className="meta">
{fetchStatus}{projectInfo} <li>{reanalyzeButton}</li>
</ul>
<ul className="tags hidden-xs">
{tagList}
</ul>
</div>
</div>
You need to specify a getInitialState method in order to set the initial state. See here: https://reactjs.org/docs/react-without-es6.html#setting-the-initial-state

Controller doesn't get parent data

I'm doing a tutorial over angular 1.5 and I've gotten far into it and one of the sections seems broken concerning matching a current user to the author username. The class injects the User service and I think assumes I can inherit from a parent controller for the author but it comes up undefined. I tried injecting $scope then setting a variable to $scope.$parent.article (article is the object that has the author name in it) but this was still undefined. I checked the parent controller doing a console log on article and it does have the data that I am trying to get. Here is a link to my project if you want to look at the entire thing but I'll try to post just the relevant code below. https://github.com/RawleJuglal/flow_news_app/tree/front_end/src/js
Parent Controller (article.controller.js)
import marked from 'marked';
class ArticleCtrl {
constructor(article, $sce, $rootScope) {
'ngInject';
this.article = article;
console.log(this.article);
//THIS IS CONSOLE LOG
//{title: "Juglal For StackOverflow",
slug: "juglal-for-stackoverflow-ba400n",
body: "<p> Need the goods</p>",
createdAt: "2017-04-25T14:51:42.131Z",
updatedAt: "2017-04-25T14:51:42.131Z",
author:{
bio:"I'm a MEAN stack developer. But if I don't find a job in Oklahoma soon, I'll be learning C++/Sharp."
following:false
image:"https://media.licdn.com/mpr/mpr/shrinknp_200_200/p/6/000/1e9/0e2/3cd7175.jpg"
username:"RawleJuglal",....
}
// Update the title of this page
$rootScope.setPageTitle(this.article.title);
this.article.body = $sce.trustAsHtml(marked(this.article.body, { sanitize: true }));
}
}
export default ArticleCtrl;
Child Controller (article-actions.components.js)
class ArticleActionsCtrl {
constructor(Articles, User, $state) {
'ngInject';
this._Articles = Articles;
this._$state = $state;
//Code that causes the error because this.article.author.username is undefined
if (User.current) {
this.canModify = (User.current.username === this.article.author.username);
} else {
this.canModify = false;
}
}
}
let ArticleActions = {
bindings: {
article: '='
},
controller: ArticleActionsCtrl,
templateUrl: 'article/article-actions.html'
};
export default ArticleActions;
HTML(article.html) //Just in case this the problem
<div class="article-page">
<div class="banner">
<div class="container">
<h1 ng-bind="::$ctrl.article.title"></h1>
<article-actions article="$ctrl.article"></article-actions>
</div>
</div>
<div class="container page">
<div class="row article-content">
<div class="col-xs-12">
<div>
<div ng-bind-html="::$ctrl.article.body"></div>
</div>
<ul class="tag-list">
<li class="tag-default tag-pill tag-outline"
ng-repeat="tag in ::$ctrl.article.tagList">
{{ tag }}
</li>
</ul>
</div>
</div>
<hr />
<div class="article-actions">
<article-actions article="$ctrl.article"></article-actions>
</div>
<div class="row">
<div class="col-xs-12 col-md-8 offset-md-2">
<div>
<form class="card comment-form">
<div class="card-block">
<textarea class="form-control"
placeholder="Write a comment..."
rows="3"></textarea>
</div>
<div class="card-footer">
<img class="comment-author-img" />
<button class="btn btn-sm btn-primary" type="submit">
Post Comment
</button>
</div>
</form>
</div>
<div class="card">
<div class="card-block">
<p class="card-text">This is an example comment.</p>
</div>
<div class="card-footer">
<a class="comment-author" href="">
<img class="comment-author-img" />
</a>
<a class="comment-author" href="">
BradGreen
</a>
<span class="date-posted">
Jan 20, 2016
</span>
</div>
</div>
</div>
</div>
</div>
</div>
In fact, your example will work with angular 1.5 but not >1.6.
here is the reason :
Starting with angular 1.6, bindings are not yet set in the constructor. If you need them, move your code to the $onInit function.
Here is your new ArticleActionsCtrl :
class ArticleActionsCtrl {
constructor(Articles, User, $state) {
'ngInject';
this._Articles = Articles;
this._$state = $state;
this.User = User;
}
$onInit() {
if (this.User.current) {
this.canModify = (this.User.current.username === this.article.author.username);
} else {
this.canModify = false;
}
}
}
let ArticleActions = {
bindings: {
article: '='
},
controller: ArticleActionsCtrl,
templateUrl: 'article/article-actions.html'
};
export default ArticleActions;
I did not test it, do not hesitate to tell me if you have any problem with it.

Html tags renders but does't function in reactjs

I have a div which renders on a boolean condition triggered by a button.
I have multiple select options in the new div. The problem is just the first works and others dont.
Code Snippet:
var Results = React.createClass({
getInitialState: function(){
return {
partname:[],
moveOptions: false,
fromLocation:'',
toLocation:'',
moveQuantity:0
}
},
componentWillMount:function(){
var partInfo = [];
var count = 0;
//ajax calls to get partInfo
this.setState({
partInfo:partInfo
});
},
showMoveOptions: function(){
this.setState({moveOptions:!this.state.moveOptions});
},
movePart: function(){
//ajax call
},
handleQuantityChange: function(e){
this.setState({
moveQuantity:e.target.value
});
},
handleFromChange: function(e){
this.setState({
fromLocation:e.target.value
});
},
handleToChange: function(e){
this.setState({
toLocation:e.target.value
});
},
render: function() {
var partInfo = this.state.partInfo;
return(
<div>
<div id="results">
<br/>
<div className="col-sm-6">
<h3>Part Name :{this.props.partname}</h3>
<div className="container">
{
partInfo.map(function(l){
return([
<div>
<h3>Building: {l.building}</h3>
<h3>Location: {l.location}</h3>
<h3>Quantity: {l.qty}</h3>
</div>
]);
}.bind(this))
}
</div>
</div>
<div className="col-sm-6">
<button type="button" onClick={() => this.showMoveOptions()}>Move</button>
</div>
</div>
{ this.state.moveOptions ?
<div>
<div>
<h3>From: </h3>
<select onChange={this.handleFromChange.bind(this)}>
partInfo.map(function(from){
return(
<option value={from.location}>{from.location}</option>
)
}
</select><br/>
<h3>To: </h3>
<select onChange={this.handleToChange.bind(this)} >
partInfo.map(function(to){
return(
<option value={to.location}>{to.location}</option>
)
}
</select><br/>
<h3>Quantity:</h3>
<input type="text" name="quantity" value={this.state.moveQuantity} onChange={this.handleQuantityChange.bind(this)}/>
</div>
<div>
<button type="button" onClick={() => this.movePart()}>Submit</button>
</div>
</div> : null
}
</div>
);
}
});
As shown in the code the first select tag works. After that all tags are rendered but i neither can select the drop down menu nor i can change text in input tag.
You should handle onChange event to update controlled input.
Check the documentation here
A controlled <input> has a value prop. Rendering a controlled <input> will reflect the value of the value prop.
and
User input will have no effect on the rendered element
I've made a fiddle with your code. You have lost some brackets in your snippet, and you should not bind handlers to this when using React.createClass syntax. But the rest is working just fine.

React modify state with extern component

I'm beginner with react and i got a problem,
I want to update state to a component by one another component .
There is my html :
<div id="leftmenu"></div>
<div id="systeme"></div>
I actually hide component in my LeftMenu component with :
var LeftMenu = React.createClass({
getInitialState: function() {
return {modif: false};
},
render: function() {
return(
<div className="col s2">
<ul id="slide-out" className="side-nav fixed">
<li><a className={this.state.modif ? 'validate' : ' validate hidden'}><i className="material-icons right">done</i>CONFIRMER ET REBOOT</a></li>
<li><a className={this.state.modif ? 'cancel' : 'cancel hidden'}><i className="material-icons right">stop</i>TOUT ANNULER</a></li>
</ul>
</div>
)
}
});
I want modify modif state when my Systeme component fire an action,
It is possible ?
Thank's ;)

Looping in Render() function of ReactJS

I have an array of objects that I need to loop output on but am getting stuck. I tried using jQuery's .each() without success.
render: function() {
return (
$.each(events, function(k, e) {
<div className="event-item-wrap">
<div className="event-item" style="backgroundImage:e.Image">
<div className="event-item-date">e.Date</div>
<div className="event-item-title">e.Title</div>
<div className="event-item-price">e.Price</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
});
);
}
My array contains simple Javascript objects with keys and values. How can I render them in React?
Here is a example of how looping is usually done in Reactjs
var List = React.createClass({
render: function() {
return (
{ this.props.data.map(function(e) {
var eventStyle = {
backgroundImage:e.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{eventStyle}">
<div className="event-item-date">{e.Date}</div>
<div className="event-item-title">{e.Title}</div>
<div className="event-item-price">{e.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
)
})
}
);
}
});
React.render(<List data={ (Array goes here) } />, document.body);
I totally agree with Dominic Tobias answer about, forgetting about jQuery, since we won't be manipulating the dom nor do we need to. For all other helpers use native functions or _. or give (es6 a shot) but in addition to the answer given by eugene safronov. I would like to recommend not to create the loop within the return itself, for readability and also for flexibility purposes. See example and the example below.
var List = React.createClass({
render: function () {
var eventItems = this.props.data.map(function (item) {
var itemStyle = {
backgroundImage:item.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{itemStyle }">
<div className="event-item-date">{item.Date}</div>
<div className="event-item-title">{item.Title}</div>
<div className="event-item-price">{item.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
);
});
return (
<div className="app">
{ eventItems }
</div>
);
}
});
React.render(<List data={ (itemsArray) } />, document.body);
-- example with no data --
var List = React.createClass({
render: function () {
var eventItems;
if(_.isEmpty(this.props.data)) { // i used lodash/underscore _. for this example)
eventItems = (
<span>No items to display</span>
);
} else {
eventItems = this.props.data.map(function (item) {
var itemStyle = {
backgroundImage:item.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{itemStyle }">
<div className="event-item-date">{item.Date}</div>
<div className="event-item-title">{item.Title}</div>
<div className="event-item-price">{item.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
);
});
}
return (
<div className="app">
{ eventItems }
</div>
);
}
});
React.render(<List data={ (itemsArray) } />, document.body);
it adds some extra flexibility, and readibility. I hope this helps u a bit, success with ReactJs!
(update: btw, now i used _. to check if data was empty, but u could also have checked if map returned nothing, and then show the different content, saves 1 extra function :D)

Resources