How do I access in React, a method of one component in other components, that are not in a direct parent-child relation? For example:
var QuestionsBox = React.createClass({
**editQuestion**: function(questionId){
// do something
// this.refs.mainForm.loadQuestionFromServer.bind(this, questionId);
},
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="questionsBox">
<h4>Questions</h4>
<QuestionsList data={this.state.data}/>
</div>
);
}
});
var QuestionsList = React.createClass({
render: function() {
var reactObject = this;
var questionsList = this.props.data.map(function (question) {
return (
<Question id={question.id}>
{question.question_name}
</Question>
);
});
return (
<div>
{questionsList}
</div>
);
}
});
var Question = React.createClass({
render: function() {
return(
<div className="question">
{this.props.children}
<a onClick={**access here editQuestion method of QuestionsBox component, with parameters**}>edit</a>
</div>
);
}
});
or other similar structures, that do not have a direct parent-child relation..
You need to pass it down as a prop
var QuestionsBox = React.createClass({
**editQuestion**: function(questionId){
// do something
// this.refs.mainForm.loadQuestionFromServer.bind(this, questionId);
},
getInitialState: function() {
return {data: []};
},
render: function() {
return (
<div className="questionsBox">
<h4>Questions</h4>
<QuestionsList
data={this.state.data}
editQuestion={this.editQuestion}
/>
</div>
);
}
});
var QuestionsList = React.createClass({
render: function() {
var reactObject = this;
var questionsList = this.props.data.map(function (question) {
return (
<Question>
id={question.id}
editQuestion={this.props.editQuestion}
{question.question_name}
</Question>
);
});
return (
<div>
{questionsList}
</div>
);
}
});
var Question = React.createClass({
render: function() {
return(
<div className="question">
{this.props.children}
<a id={this.props.id} onClick={this.editQuestion}>edit</a>
</div>
);
},
editQuestion: function(e) {
this.props.editQuestion(e.target.id);
}
});
Create a separate storage class. Embed the instance of that class in each place that has access to editing the data it contains. You see this in Flux, Facebook's architecture library. Instead of passing down handlers, have the events be emitted from the Storage class, and have each component subscribe to that instance of the storage class.
It's hard to describe, but that link has a video which will make it very clear. This way, any time data changes the store will trigger events which will trigger re-renders of your react views.
Related
Hello I have a function to send to two sockets values
getMatchConfigurationFor = players => {
console.log(sessionMap.all())
if(players){
const match = new Match(players);
const result = {
idMatch: match.id,
playerOne: match.players[0],
playerTwo:match.players[1]
}
return result;
}
}
configurePlayersForNewMatch = (matchedPlayers) => {
matchedPlayers.forEach(player =>
sessionMap.get(player.socketId)
.broadcast.to(player.socketId)
.emit('match',
this.getMatchConfigurationFor(matchedPlayers)));
}
I tested all of it and it's working perfectly, but I tried to listen to the socket on the front end sme success I don't know why
my front end:
import React, { Component } from 'react';
import io from 'socket.io-client';
import Loading from './Loading'
import Players from './Players'
class Home extends Component {
constructor(props, context) {
super(props, context);
this.socket = null;
this.state = {
queue: [],
loading: true,
players: [],
};
}
componentDidMount() {
// io() not io.connect()
this.socket = io('http://localhost:9000');
const player = JSON.parse(localStorage.getItem('user'));
this.socket.emit('addPlayer-Queue', player);
this.socket.on('match', (result) => {
console.log('a')
console.log(result);
});
this.socket.open();
}
componentWillUnmount() {
this.socket.close();
}
render() {
const { queue } = this.state;
const { loading } = this.state;
const { players } = this.state
const visibility = loading ? 'hidden' : 'visible';
return (
<div className="container">
<div className="result">
</div>
<div className="ctnFlex">
<div className="playerOne">{players.map(pls => <p>{pls.name}</p>)}</div>
<Loading loading={loading} message='in queue.' />
<div className="playerTwo" style={{ visibility }}>
<Players players={players}/>
</div>
</div>
</div>
)
}
}
export default Home;
I have a session map of all sockets that come into my server:
var SessionMap = {};
module.exports = {
set: function(key,value){
SessionMap[key] = value;
},
get: function(key){
return SessionMap[key]
},
delete: function(key){
delete SessionMap[key]
},
all: function(){
return SessionMap
}
}
I debugged all my code and without any kind of error
A console. log of one of the sockets being sent the emit
https://pastebin.com/XHDXH9ih
I am able to fetch the data from the db and it is displaying on the inspect element also but it is not displaying on the browser i mean UI.
//storing the data into the posts
this.state = {
displayMenu: false,
posts: [ ]
};
//click function for the drop down and handling the axios.get
Click = event => {
event.preventDefault();
let currentComponent = this;
axios.get(`http://localhost:4000/api/AMS`)
.then(function (response) {
console.log(response);
currentComponent.setState({posts: response.data})
})
.catch(function (error) {
console.log(error);
});
}
//Render method
render() {
// var back = {backgroundSize : 'cover'};
var textStyle = {
position: 'absolute',
top: '50%',
left: '50%'
};
//From here the checking of data is happening, if the data is found inside the posts it will show it on the browser otherwise it will show no posts.
const { posts } = this.state;
const postList = posts.length ? (
posts.map(post => {
// console.log('hi');
return (
<div className="post card" key={post.ID}>
<div className="card-content">
</div>
</div>
)
})
) : ( <div className="center">No posts yet</div>)
//RETURN method
return (
<div>
{/* <Image
style={back} responsive
src={logo}>
</Image> */}
<div style={textStyle} className="dropdown" style = {{background:"red",width:"200px"}} >
<div className="button" onClick={this.showDropdownMenu}> Regions </div>
{ this.state.displayMenu ? (
<ul>
<li><a className="active" href="/AMS" onClick={this.Click}>AMS</a></li>
<li>EMEA</li>
<li>APJ</li>
</ul>
):(null)
}
</div>
//Here i am calling the postList variable
{postList}
{/* {this.state.posts}<br/>
{this.state.pictures} */}
</div>
);
}
}
Click = event => {
event.preventDefault();
let currentComponent = this;
axios.get(`http://localhost:4000/api/AMS`)
.then(function (response) {
console.log(response);
currentComponent.setState({posts: response.data})
})
.catch(function (error) {
console.log(error);
});
}
render() {
// var back = {backgroundSize : 'cover'};
var textStyle = {
position: 'absolute',
top: '50%',
left: '50%'
};
const { posts } = this.state;
const postList = posts.length ? (
posts.map(post => {
// console.log('hi');
return (
<div className="post card" key={post.ID}>
<div className="card-content">
</div>
</div>
)
})
) : ( <div className="center">No posts yet</div>)
The results that i am getting in the inspect element console is like below:
ID: 229, EMAIL: "anuraguk3#gmail.com", ROLE: "BASE", PASSWORD:"$2b$10$ShTWYAtF8M5JLhEm68JqTuMx7P8x6dtOIkNsGz4wE21LY92xGoDCO"
DOM is rendered before getting server response.So, you need to use async-await in this scenario. For your program:-
Click = async(event) => {
event.preventDefault();
let currentComponent = this;
await axios.get(`http://localhost:4000/api/AMS`)
.then(function (response) {
console.log(response);
currentComponent.setState({posts: response.data})
})
.catch(function (error) {
console.log(error);
});
}
I have created a chat app using nodejs/express, mongodb, reactjs. When I type in the chat box and on clicking send button the data get's stored inside mongodb but how can I display it on client side. In code below I am not able to display it on client side. In server.js I am not able to emit the messages. What I am doing wrong in server.js ? The data is not reaching frontend from backend/database.
Code:
server.js:
const express = require('express');
const mongoose = require('mongoose');
const socket = require('socket.io');
const message = require('./model/message')
const app = express();
const mongoURI = require('./config/keys').mongoURI;
mongoose.connect(mongoURI, {useNewUrlParser: true})
.then()
.catch( err => console.log(err));
let db = mongoose.connection;
const port = 5000;
let server = app.listen(5000, function(){
console.log('server is running on port 5000')
});
let io = socket(server);
io.on("connection", function(socket){
console.log("Socket Connection Established with ID :"+ socket.id)
socket.on('disconnect', function(){
console.log('User Disconnected');
});
let chat = db.collection('chat');
socket.on('SEND_MESSAGE', function(data){
let message = data.message;
let date = data.date;
// Check for name and message
if(message !== '' || date !== ''){
// Insert message
chat.insert({message: message, date:date}, function(){
socket.emit('output', [data]);
});
}
});
//Code below this is not working:
chat.find().limit(100).sort({_id:1}).toArray(function(err, res){
if(err){
throw err;
}
// Emit the messages
socket.emit('RECEIVE_MESSAGE', res);
});
})
chat.js:
import React, { Component } from 'react'
import './chat.css'
import io from "socket.io-client";
export default class Chat extends Component {
constructor(props){
super(props);
this.state = {
message: '',
date: '',
messages: []
};
const socket = io('localhost:5000');
this.sendMessage = event => {
event.preventDefault();
if(this.state.message !== ''){
socket.emit('SEND_MESSAGE', {
message: this.state.message,
date: Date.now()
});
this.setState({ message: '', date: '' });
}
};
socket.emit('RECEIVE_MESSAGE', data => {
addMessage(data);
});
const addMessage = data => {
console.log(data);
this.setState({
messages: [...this.state.messages, data],
});
console.log(this.state.message);
console.log(this.state.messages);
};
}
render() {
return (
<div>
<div id="status"></div>
<div id="chat">
<div className="card">
<div id="messages" className="card-block">
{this.state.messages.map((message, index) => {
return (
<div key={index} className="msgBox"><p className="msgText">{message.message}</p></div>
)
})}
</div>
</div>
<div className="row">
<div className="column">
<input id="inputmsg" type="text" placeholder="Enter Message...."
value={this.state.message} onChange={ev => this.setState({message: ev.target.value})}/>
</div>
<div className="column2">
<button id="send" className="button" onClick={this.sendMessage}>Send</button>
</div>
</div>
</div>
</div>
)
}
}
Screenshot of mongo shell:
Mongoose documentation specifies the correct usage of .find() method . You can find it here.
To cut the chase you need to give the method an object model that you are looking for. So for example if you were looking for objects with specific date field you could use:
chat.find({ "date": <some-date> }, function(err, objects) { ... });
If you want to fetch all object from the collection you can use:
chat.find({}, function(err, objects) { ... });
My problem is, that it isn't displayed in html form. How can I solve this ?
The query is well, and I get the result on URL, but can't display it on component.html.
( It works and I see if I call the URL /api/mainstorage so it display me the JSON content.)
Index.js
var express = require('express');
var router = express.Router();
// http://localhost:3000/
router.get('/', function(req, res, next) {
res.status(200)
.json({
status: 'success',
message: 'Live long and prosper!'
});
});
var db = require('./queries');
router.get('/api/mainstorage', db.getAllDocuments);
module.exports = router;
Queries.js
var promise = require('bluebird');
var options = {
// Initialization Options
promiseLib: promise
};
var pgp = require('pg-promise')(options);
var connectionString ='postgres://dbuser:Storage#localhost/mainstorage'
var db = pgp(connectionString);
const axios = require('axios');
const API = 'http://localhost:3000';
function getAllDocuments(req, res, next) {
axios.get(`${API}/main`)
db.any('SELECT * FROM files')
.then(function (data) {
res.status(200)
.json({
status: 'success',
data: data,
message: 'Retrieved all files'
});
})
.then(documents => {
res.send(200).json();
})
.catch(function (err) {
return next(err);
});
}
module.exports = {
getAllDocuments: getAllDocuments
};
documents.component.ts
export class DocumentsComponent implements OnInit {
title = 'app works!';
mainstorage;
documents: any [];
constructor(private documentsService: DocumentsService) { }
ngOnInit() {
// Retrieve documents from the API
this.documentsService.getAllDocuments().subscribe(documents => {
this.documents = documents;
});
}
}
documents.service.ts
#Injectable()
export class DocumentsService {
constructor(private http: Http) {}
getAllDocuments(){
return this.http.get('/api/mainstorage')
.map(res => res.json());
}
}
documents.component.html
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>
You are not able to see anything in the html because service data is asynchronous and you are trying to display it before the service returns it back.
You can solve this by wrapping your variables in *ngIf
<div *ngIf='documnets'>
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>
</div>
</div>
</div>
*ngIf will check if there are documents and once data from service is received it will be displayed.
I created a simple app to search video using youtube-api, but when I use npm start it was not give me any errors but give me the warning Warning: Unknown proponItemSearchedon <searchItem> tag. Remove this prop from the element.
in searchItem (created by listItem)
in div (created by listItem)
in listItem
Here is my code:
var React = require('react');
var Item = require('./item.jsx');
var searchItem = React.createClass({
getInitialState : function() {
return {
'queryString' : ''
};
},
handleSearchClicked : function() {
this.props.onItemSearched(this.state);
this.setState({
'queryString' : ''
});
},
handleChangedNameItem : function(e) {
e.preventDefault();
this.setState({
'queryString' : e.target.value
});
},
render : function () {
return (
<div>
<label>
<input id="query" type="text" onChange={this.handleChangedNameItem} value={this.state.queryString} placeholder="Search videos..." />
<button id="search-button" onClick={this.handleSearchClicked}>Search</button>
</label>
</div>
);
}
});
And this is listItem what i show my results
var listItem = React.createClass({
getInitialState : function() {
return {
'results' : []
};
},
handleQuerySearch : function(query) {
var req = gapi.client.youtube.search.list({
'part': 'snippet',
'type': 'video',
'q' : encodeURIComponent(query).replace(/%20/g, "+"),
'order' : 'viewCount',
});
//execute request
req.execute((res) => {
var results = res.result;
this.setState({
'results' : results.items
});
});
},
render : function() {
var listItem = this.state.results.map( item => {
return(
<Item title={item.snippet.title} videoid={item.id.videoId} />
);
});
return (
<div>
<searchItem onItemSearched={this.handleQuerySearch} />
<div className="list-item">
{listItem}
</div>
</div>
);
}
});
module.exports = listItem;
React wants all components to be written in class format. Meaning the names need to be capitalized.
searchItem needs to be SearchItem
You can also define the props that will be received on search item
var SearchItem = React.createClass({
propTypes: {
onItemSearched: React.PropTypes.func
},
....
});