State is null in React - reactjs

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

Related

JSX not rendering after .map in React

I am fetching a JSON file and trying to render the data from it. Everything shows up great when I console.log it but the JSX is not being rendered to the page. I was using forEach and read that it should be map instead but that doesn't fix my problem. Here's my code:
getPromoDetails(data) {
data = this.state.data;
Object.keys(data || {}).map(function(key) {
console.log("Promo ID: ",data[key].cm_ID)
console.log("Title: ",data[key].cm_title)
console.log("State: ",data[key].state)
console.log("Status: ",data[key].status)
console.log("Last Modified on: ",data[key].cm_lastmodified)
return
<div className="col-xs-12">
<div className="col-xs-3">
<img src={`https://link.com/thumbnail_${data[key].cm_ID}.jpg`}/>
</div>
<div className="col-xs-9">
<span className="col-xs-12"> {data[key].cm_title}</span>
<span>On: {data[key].cm_on}</span>
<span>State: {data[key].state}</span>
<span>Status: {data[key].status}</span>
<span>Last Modified: {data[key].cm_lastmodified}</span>
</div>
</div>
});
}
Any advice??
You are not returning the array that is the result of the map. You also have to make sure the JSX is on the same line as the return statement, or undefined will be returned.
getPromoDetails() {
const { data } = this.state;
return Object.keys(data || {}).map(function(key) {
return (
<div className="col-xs-12" key={key}>
<div className="col-xs-3">
<img src={`https://link.com/thumbnail_${data[key].cm_ID}.jpg`} />
</div>
<div className="col-xs-9">
<span className="col-xs-12"> {data[key].cm_title}</span>
<span>On: {data[key].cm_on}</span>
<span>State: {data[key].state}</span>
<span>Status: {data[key].status}</span>
<span>Last Modified: {data[key].cm_lastmodified}</span>
</div>
</div>
);
});
}

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.

How to popup chat window using node.js

I am working on node.js and began to create a chat application I have built it successfully but the problem is that I want the chat window should be open when the client click on the name of the sender(who sent the message to the client).
I will show you the example what I have done till now.
Here you can see that the chat box is already open but I want it should open when a user is selected from "List of users" and the content of chat box should be replaced whenever a new user is selected and previous content should be removed.
Here is my index.html code :
<div class="col-md-4 user-list">
<h2>List of Users</h2>
<ul class="list-group">
<li class="list-group-item"
ng-repeat="user in userList"
ng-class="{ 'active' : user.id == selectedUser.uid}"
ng-click = seletedUser(user.id,user.userName);
ng-style="{
'cursor': user.id === socketId ? 'not-allowed' :'pointer'
}"
>
<span id='{{user.id}}' >{{ user.id === socketId ? 'You': user.userName }}</span>
<span id='{{user.id + "notify"}}' style="color:black; opacity:0.5; font:2px; padding:5px; visibility:hidden;"> {{'typing...'}}</span>
</li>
</ul>
</div>
</div>
<div class="container" id="messages">
<div class="row">
<div class="col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> {{'Chat -' + selectedUser.uname}}
</div>
<div class="panel-body">
<ul class="chat col-md-7"
ng-repeat = "message in messages"
ng-style ="{'float':message.fromid == socketId ? 'left' : 'right'}">
<li>
<div class="clearfix">
<div class="direct-chat-text"
ng-style = "{'background-color': message.fromid == socketId ? '#d9edf7' : '#62f3bc'}"
>
{{message.msg}}
</div>
</div>
</li>
</ul>
<br></br>
</div>
<div class="panel-footer">
<div class="input-group">
<textarea elastic type="text" class="form-control custom-control" ng-model='message' ng-keyup="keyup()" ng-keydown="keydown()" ng-change="change()" placeholder="Type your message here..."></textarea>
<span class="input-group-addon btn btn-primary" ng-click="sendMsg()"><i class="glyphicon glyphicon-send"></i></span>
</div>
</div>
</div>
</div>
</div>
</div>
If you would require any other information related to code please comment.
As I am newbie to node.js so help me to solve my problem.
UPDATE
My script.js code which have sufficient details:
app.controller('app', ($scope,$timeout,socket) => {
$scope.socketId = null;
$scope.selectedUser ={ uid: null, uname: null};
$scope.messages = [];
$scope.msgData = null;
$scope.userList = [];
var TypeTimer;
var TypingInterval = 1000;
$scope.username = window.prompt('Enter Your Name');
if ($scope.username === '') {
window.location.reload();
}
$scope.seletedUser = (id,name) => {
if(id === $scope.socketId)
{
alert("Can't message to yourself.")
}
else
{
$scope.selectedUser =
{
uid: id,
uname: name
}
}
};
$scope.sendMsg = () => {
// const keyCode = $event.which || $event.keyCode;
if ($scope.message !== null && $scope.message !== '' && $scope.selectedUser.uid !== null) {
socket.emit('getMsg',{
toid : $scope.selectedUser.uid,
fromid: $scope.socketId,
msg : $scope.message,
name : $scope.username
});
$timeout.cancel(TypeTimer);
TypeTimer=$timeout( function(){
socket.emit('getTypingNotify',{
toid : $scope.selectedUser.uid,
fromid: $scope.socketId,
msg:"hidden"
});
});
$scope.message = null;
console.log($scope.selectedUser.uid);
}
else
{
alert("enter a message or select a User to send message");
}
};
socket.emit('username',$scope.username);
socket.on('userList', (userList,socketId) => {
if($scope.socketId === null){
$scope.socketId = socketId;
}
$scope.userList = userList;
});
socket.on('exit', (userList) => {
$scope.userList = userList;
});
socket.on('setMsg',(data) => {
document.getElementById(data.fromid+'notify').style.visibility= data.msg;
});
socket.on('sendMsg', (data) => {
//console.log('send');
$scope.messages.push(data);
});
my understanding is u want to show a pop up on click of a button or some text box u can use angular bootstarp model as shown here
"https://plnkr.co/edit/?p=preview"
and control the close and open in angularjs contoller and send the chat details too server side
After searching some tutorials and questions(on StackOverflow) I found a way and going to share with you all.
I created a directory name "open" and an attribute visible of this "open" directive to show and hide the dialog.
app.directive('open',function() {
return {
restrict: 'E',
template: `<div class="container">
<div class="row">
<div class="col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span>{{"Chat -" + selectedUser.uname}}
</div>
<div class="panel-body">
<div ppp-chat></div>
<br></br>
</div>
<div class="panel-footer">
<div class="input-group">
<textarea msd-elastic type="text" class="form-control custom-control" ng-model="message" ng-keyup="keyup()" ng-keydown="keydown()" ng-change="change()" placeholder="Type your message here..."></textarea>
<span class="input-group-addon btn btn-primary" ng-click="sendMsg()"><i class="glyphicon glyphicon-send"></i></span>
</div>
</div>
</div>
</div>
</div>
</div>`,
replace:true,
scope:false,
link: function postLink(scope,element,attrs) {
scope.$watch(attrs.visible,function(value){
if(value == true)
{
$(element).show();
}
else
$(element).hide();
});
$(element).on('show.bs.open',function() {
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.open',function() {
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
And a method in controller to toggle the chat window(hide or show)
$scope.toggleChat = () => {
$scope.showChat = false;
$scope.showChat = !$scope.showChat;
};
this toggleChat is used to change the value of showChat scope variable that is used to turn on(off) the visibility of chat box by alterating the showChat value as true or false.
In html I have replaced my id="messages" element( with its child and subchild) with
<open visible="showChat">
</open>

I don't get out of the function Angularjs

I have a simple Angular code to show and hide a poppin, but every time I use it I am blocked in the function.
In my controller I have this to show the poppin :
$scope.showHidden = function() {
console.log('in')
$scope.showIt = true;
};
And this to hide it :
$scope.hideIt = function() {
console.log('out')
$scope.showIt = false;
};
And in my HTML :
<li class="beer_list_item beer_item" ng-repeat="beer in beers | filter : myFilter" ng-click="showHidden()">
<img ng-src="{{beer.img}} " alt="{{beer.alt}}" />
<div class="beer_list_item_desc" ng-show="showIt">
<h2 class="title1">{{beer.name}}</h2>
<img src="{{beer.img}}" alt="{{beer.alt}}"/>
<p>{{beer.desc}}</p>
<button class="btn" ng-click="hideIt()">Close</button>
</div>
</li>
If I click on the item the poppin appears, and when I click on the close btn, I see 'out' and 'in' in my logs, and the poppin never disappear.
I'm sure it's a stupid mistake, but I don't see it. If anyone have an idea.. thanks by advance !
You need to prevent the event propagation when click on hideIt:
<button class="btn" ng-click="hideIt();$event.stopPropagation();">Close</button>
This could be a refactoring:
function BeersCtrl($scope, beers) {
$scope.beers = beers;
$scope.showBeerList = true;
$scope.toggleBeerList = function(event) {
$scope.showBeerList = !$scope.showBeerList;
};
}
angular
.module('test', [])
.controller('BeersCtrl', BeersCtrl)
.value('beers', [
{ name: 'Peroni' },
{ name: 'Guinnes' }
])
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="test">
<article ng-controller="BeersCtrl">
<div>
<button
ng-click="toggleBeerList($event)"
type="button">Toggle Beer List</beer>
</div>
<ul ng-show="showBeerList">
<li
ng-repeat="beer in beers">
<span ng-bind="beer.name"></span>
</li>
</ul>
</article>
</section>

React update component state from another component

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).

Resources