globally access data across all pages in REACT js - reactjs

In header react component class have defined function Search
Search: function()
{
var author=$('#author').val();
var bookname=$('#title').val();
var isbn=$('#isbn').val();
var keywords=$('#keywords').val();
var publisher=$('#publisher').val();
var url=VDOMAIN+"/aodrbooks.php?action=srch&author="+author+"&isbn="+isbn+"&publisher="+publisher+"&name="+bookname+"&price=''";
$.ajax({url:url,
success: function(result){
resp = JSON.parse(result); //this data is an array
if(resp['count']==1){
location.href=VDOMAIN+"odrbooks?pagename=bkd&bid="+resp['results'][0]['bookid']+"&bkname="+resp['results'][0]['name'];
}
else{
location.href=VDOMAIN+"odrbooks?pagename=cat&type=&author="+author+"&bkname="+bookname;
}
}
});
},
here how do i make my resp data globally such thAT I can access it in any page in any component?
I tried using this.state.data=resp ,this.props.data=resp and this.setState({data:resp})

Use state container for that purpose. The most popular one right now is https://github.com/reactjs/react-redux
You can dispatch an action and store successful response in Your reducer which represents Your application state.
Then connect that reducer to the component that needs resp data and use it through props.

Related

Angular v1 Component to Component data transfer

I'm struggling with a problem within Angular v1.6.1 where I am trying to transfer some data from a component to another component.
I have a component called navbar which resides in app\common\navbar has a controller that fetches data from a service. The following files make up navbar component
navbar.component.js
import controller from './navbar.controller';
import template from './navbar.html';
export default navbarComponent = {
restrict: 'E',
bindings: {},
template,
controller
};
navbar.controller.js
class NavbarController {
constructor(httpService) {
const dataUrl = "/assets/data/header.json";
this.name = 'Navbar';
this.headerData = {};
console.log("In "+this.name);
httpService.getData(dataUrl)
.then((response) => {
angular.extend(this.headerData,response.data);
},(error) => { throw error; });
}
}
export default NavbarController;
navbar.html
<section>
<top-header top-data="$ctrl.headerData"></top-header>
<section>
and my httpService resides in app\services folder. It fetches content using axios http library and looks something like this
httpService.js
import axios from 'axios';
export class HttpService {
constructor() {
this.name = "HttpService";
}
getData(api_url){
return axios.get(api_url)
.then((response) => response, (error) => error);
}
}
The component which uses my navbar component's headerData is top-header and resides in app\common\top-header. This is what it contains
top-header.component.js
import template from './top-header.html';
import controller from './top-header.controller';
export default topHeaderComponent = {
restrict: 'E',
template,
bindings: {
topData: '<'
},
controller,
};
top-header.controller.js
class TopHeaderController {
constructor() {
this.name = 'TopHeader';
this.topHeaderData = {};
this.$onInit = function() {
this.topHeaderData = this.topData;
console.log(this.topHeaderData);
console.log(this.topHeaderData.telephoneNumber);
console.log(this.topHeaderData);
}
}
}
export default TopHeaderController;
top-header.html
{{$ctrl.topHeaderData.telephoneNumber}}
and finally my static files resides in assets\data and the JSON I'm trying to fetch header.json contains
header.json
{
"telephoneNumber": 12345678
}
So the problem now I see is that the data does show up in my top-header component but I'm not sure what's happening but the data disappears (comes up undefined) once I try to access the object property.
What I'm saying is that in top-header.controller.js
when I console.log(this.topHeaderData); it shows the object but when I try to console.log(this.topHeaderData.telephoneNumber); it comes up undefined
I think the problem exists because of the execution priority of the Directives. I even set navbar component priority to 5 and it didn't help as the data is undefined.
top-header.controller.js
this.$onInit = function() {
this.topHeaderData = this.topData;
console.log(this.topHeaderData); // shows topData
console.log(this.topHeaderData.telephoneNumber); // undefined
console.log(this.topHeaderData); // shows topData
}
This data this.topHeaderData.telephoneNumber is essential as I use this in my template.
How can I resolve this issue? Any help would be greatly appreciated.
The problem may be in top-header.controller.js: you're assigning binded topData to this.topheaderData in $onInit hook but when component is initialized the data hasn't been fetched yet. Instead of $onInit you should use $onChange hook method which is called by Angular when binded property is updated (in your case when data is fetched from server)
Angular component docs:
$onChanges(changesObj) - Called whenever one-way bindings are updated.
The changesObj is a hash whose keys are the names of the bound
properties that have changed, and the values are an object of the form
{ currentValue, previousValue, isFirstChange() }. Use this hook to
trigger updates within a component such as cloning the bound value to
prevent accidental mutation of the outer value.

Firebase search with param?

so i just started with Firebase and AngularFire.
I've got this data structure:
friends
-JzKr-mrv-O7rlxrMi3_
creator: "111181498675628551375"
description: "dsa"
name: "das"
--JzKrahnTf47MXp8nAZx
creator: "111181498675628551320"
description: "ddasdassa"
name: "dasdadsadas"
Now i want to query with param creator = "111181498675628551320".
How can i do this ? I've tried this way:
.service('Friends', function ($firebase, store, $state) {
var friendsRef = new Firebase("url/friends");
friendsRef.authWithCustomToken(store.get('firebaseToken'), function (error, auth) {
if (error) {
// There was an error logging in, redirect the user to login page
$state.go('login');
}
});
var friendsSync = $firebase(friendsRef);
var friends = friendsSync.$asArray();
this.all = function () {
return friends;
};
this.getCreator = function(creator){
return friends.$getRecord(creator);
};
});
Anyone got maybe some dev reference how i should work with it?
Maybe i should make other call then url/friends?
AngularFire is a wrapper around the Firebase JavaScript SDK, which simplifies binding Firebase data to AngularJS views. When something is not obvious from the AngularFire documentation, refer to the Firebase JavaScript documentation.
You can read all about Firebase queries in the documentation. In that case what you'll need to do, is build the necessary query using Firebase's regular JavaScript SDK:
var ref = new Firebase('https://yours.firebaseio.com/friends');
var query = ref.orderByChild('creator').equalTo('111181498675628551320');
Then you can bind the resulting items to your view by using an AngularFire $firebaseArray():
$scope.friends = $firebaseArray(query);

SetState fails in callback (via ComponentWillMount), on server only

I need to render React components on the server for SEO. My component fetches data in ComponentWillMount, based on the query parameters - but on the server (Node 4.0.0), SetState fails in the request's callback. The error can be reproduced with a simpler setTimeout too, as in the code example below.
I have found numerous discussion on the web relating to complications between React and server-side rendering. I'm working on two work-around approaches:
removing all ajax requests from the server, instead rendering the result of the request directly into a global variable embedded in the first-serve HTML
moving the ajax request prior to initialization of the React components, on the server only (the request would still have to live in ComponentWillMount (or ComponentDidMount) for the client version.
Please let me know if there is an alternative or recommended approach instead.
var React = require('react');
// Reproduced in React 0.13.3 and 0.14.0-beta1
var ReactDOMServer = require("react-dom/server");
var A = React.createClass({
componentWillMount: function() {
var _this = this;
// for example an ajax call to fetch data based on request parameters:
setTimeout(function(err, res) {
// state is set based on results
_this.setState({ a: 1 });
}, 100);
},
render: function() {
return React.createElement('div', null);
}
});
ReactDOMServer.renderToString(React.createElement(A, null));
Error:
$ node index.js
/app/node_modules/react/lib/getActiveElement.js:25
return document.body;
^
ReferenceError: document is not defined
at getActiveElement (/app/node_modules/react/lib/getActiveElement.js:25:12)
at ReactReconcileTransaction.ReactInputSelection.getSelectionInformation (/app/node_modules/react/lib/ReactInputSelection.js:38:23)
at ReactReconcileTransaction.Mixin.initializeAll (/app/node_modules/react/lib/Transaction.js:168:75)
at ReactReconcileTransaction.Mixin.perform (/app/node_modules/react/lib/Transaction.js:135:12)
at ReactUpdatesFlushTransaction.Mixin.perform (/app/node_modules/react/lib/Transaction.js:136:20)
at ReactUpdatesFlushTransaction.assign.perform (/app/node_modules/react/lib/ReactUpdates.js:86:38)
at Object.flushBatchedUpdates (/app/node_modules/react/lib/ReactUpdates.js:147:19)
at Object.wrapper [as flushBatchedUpdates] (/app/node_modules/react/lib/ReactPerf.js:66:21)
at ReactDefaultBatchingStrategyTransaction.Mixin.closeAll (/app/node_modules/react/lib/Transaction.js:202:25)
at ReactDefaultBatchingStrategyTransaction.Mixin.perform (/app/node_modules/react/lib/Transaction.js:149:16)
Issue opened at https://github.com/facebook/react/issues/4873
Try moving the setState function in another method:
var React = require('react');
// Reproduced in React 0.13.3 and 0.14.0-beta1
var ReactDOMServer = require("react-dom/server");
var A = React.createClass({
stateChange: function( obj ){
setTimeout( this.setState( obj ), 100 );
},
componentWillMount: function() {
this.stateChange( {a: 1} );
},
render: function() {
console.log( this.state.a )
return React.createElement('div', null);
}
});
ReactDOMServer.renderToString(React.createElement(A, null));

ReactJS + flux - how to handle session-like parameters (pseudoauthorization)

Here's the usecase:
I have 2 components in my reactjs application. Both components are fed with data from remote server - via websockets. I don't want my components nor stores to be aware of data source - all websocket logic resides in ActionCrators and something I call SocketListeners.
Here's the example of such a listener:
var listen = function (socket) {
socket
.on(Messages.LIGHTS_CHANGED, function (newConfiguration) {
AppDispatcher.dispatch({
type: LightActionTypes.SUBSTITUTE_LIGHT_CONFIGURATION,
payload: newConfiguration
});
})
};
module.exports = {
listen: listen
};
Since it is a websocket, I need to know the remote url.
I'd like to ask my user to provide this url on my home page - and before that, my components (actually - routes) should not be available and user should be redirected to the page where he is able to specify this URL.
So I need something which looks like a login flow - but instead of login and password, remote url is crucial property here.
How would you manage this session-like state?
I tried something like this:
In my form-like home view I have a function:
handleConnectionConfirmed: function(event) {
event.preventDefault();
ActionCreator.saveRemoteUrl(
this.state.remoteUrl
);
},
which causes to update my ConfigurationStore:
var _lightsUrl = '';
var _temperatureUrl = '';
var ConfigurationStore = {
lightsSocketEndpoint: function () {
return _lightsUrl;
},
temperatureSocketEndpoint: function () {
return _temperatureUrl;
}
};
And then both my components have:
componentWillMount: function () {
ActionCreator.init();
},
Init function:
init: function () {
_socket = WebSocketFactory.lightsWebSocket();
SocketListener.listen(_socket);
},
One last snippet:
lightsWebSocket: function () {
return io.connect(
ConfigurationStore.lightsSocketEndpoint()
)
},
The problem is: as soon as I refresh any page, of course my ConfigurationStore is cleared.
How can I make it somehow persistent without using an external storage?
Also, do you know how can I configure react-router so that it could redirect me to 'login' page when no remote url is specified and user tries to open site where one of those components resides?
Use LocalStorage or SessionStorage. For example:
In your store's constructor do:
_lightsUrl = localStorage.getItem('lightsUrl') || '';
And in the dispatch handler of the store:
_lightsUrl = newLightsUrl;
localStorage.setItem('newLightsUrl');
Here's a nice tutorial which does authentication this way (don't mind the 'Rails' part): http://fancypixel.github.io/blog/2015/01/29/react-plus-flux-backed-by-rails-api-part-2/

How to redirect after success from ajax call using React-router-component?

I am building a application using Facebook flux architecture of React JS. I have build the basic part of app where I have a login form. I am fetching the the result from node server to validate user at the store, I am getting the result from server, Now I got stuck that how can I redirect the user to home page after success.
I have read about the react router component and I am able to redirect at the client side but not able to redirect at the time of fetching result from ajax in Store. Please help me.
You need to use the transitionTo function from the Navigation mixin: http://git.io/NmYH. It would be something like this:
// I don't know implementation details of the store,
// but let's assume it has `login` function that fetches
// user id from backend and then calls a callback with
// this received id
var Store = require('my_store');
var Router = require('react-router');
var MyComponent = React.createClass({
mixins: [Router.Navigation],
onClick: function() {
var self = this;
Store.login(function(userId){
self.transitionTo('dashboard', {id: userId});
});
},
render: function() {
return: <button onClick={this.onClick}>Get user id</button>;
}
});
It worked for me when I added to the react element properties a require for the router and used the router like this:
// this is the redirect
this.context.router.push('/search');
// this should appear outside the element
LoginPage.contextTypes = {
router: React.PropTypes.object.isRequired
};
module.exports = LoginPage;
This should work
var Store = require('Store');
var Navigatable = require('react-router-component').NavigatableMixin
var LoginComponent = React.createClass({
mixins: [ Navigatable ],
onClick: function() {
Store.login(function(userId){
this.navigate('/user/' + userId)
}.bind(this));
},
render: function() {
return <button onClick={this.onClick}>Login</button>;
}
});

Resources