I am trying to consume rest api in ReactJS. But it's showing undefined.
Here is my code..
ReactJS code:
<script type="text/jsx">
var JavaEEWSTest = React.createClass({
getInitialState: function () {
return {text: ''};
},
componentDidMount: function(){
$.ajax({
url: "http://localhost:8080/hi"
}).then(function(data) {
this.setState({text: data.text});
alert(data.text);
}.bind(this))
},
render: function() {
return <div>Response - {this.state.text}</div>;
}
});
React.render(<JavaEEWSTest />, document.getElementById('component'));
</script>
Here is my Spring boot code:
#RestController
#CrossOrigin(origins = "http://localhost:3000")
public class HelloController {
#RequestMapping(value="/hi",method=RequestMethod.GET)
public String sayHello()
{
return "hello";
}
}
While making AJAX calls, we can use axios-react, the quick link: https://www.npmjs.com/package/axios
And instead of the function keyword in your code, you may use the ES6 version's =>.
Below is an example of getting the response from the rest API.
constructor() {
super();
this.state = {
data : []
}
}
componentDidMount() {
axios.get(URL)
.then((res) => {
this.setState({data:res.data});
console.log(this.state.data);
})
.catch((error) => {
console.log(error);
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Related
I am learning React and I am trying to display a list of users from and ajax call. I am getting an unexpected token error from CodePen when I add the line
export default Users;
When I remove the line there are no more errors but the list of users is not being displayed.
My code:
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
function UserList(users) {
const userItems = users.map((user) =>
<ul>
<li>
{ user.name }
</li>
<li>
{ user.email }
</li>
<li>
{ user.phone}
</li>
</ul>
);
return (userItems);
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
if (document.getElementById('root')) {
ReactDOM.render(<Users />, document.getElementById('root'));
}
Here is my code.
Thank you for any and all help!
Problem 1 in AJAX call
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
console.log(data);
callback(null, data);
},
error: function (error) {
console.log(data);
callback(error, {});
}
});
}
$.ajax is asynchronous call, that means it doesn't returns directly any value (how it could if it is fetching the results from the internet) it Just creates another function which will call success and error when completed.
That's why we need to wrap it with callbacks
function GetUsers(project, resolve = () => {}, reject = () => {}) {
}
Problem 2 in mount
componentDidMount() {
GetUsers(null, function (err, data) {
if (err)
{
console.log(err);
}// do something
this.setState({ users: data })
}.bind(this))
}
This code is completely wrong, it has even syntax error so not worth to discuss it in details.
We need to call our new function and pass success callback for mutating the state
GetUsers(null, users => {
this.setState({ users });
});
In this way we will call GetUsers wait for it's results and only after that we will mutate the state with new result
3 problem in component creation
React component's don't have state by default, you need to infer the state from constructor so we need to change initialization to
constructor(props) {
super(props);
this.state = {
users: false
};
}
otherwise you will get Cannot call setState of undefined as state is not automatically created for performance purposes and all components are Pure by default.
I have created a working sandbox here
in
function GetUsers(project){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
return data;
},
error: function (error) {
console.log(error);
return {};
}
});
}
--
success: function (data) {
return data;
}
doesn't do what you think it does. return data isn't really returning the data... anywhere.
You need to have a callback.
function GetUsers(project, callback){
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
success: function (data) {
callback(null, data)
},
error: function (error) {
callback(error, {})
}
});
}
class Users extends Component {
componentDidMount() {
GetUsers(null, function (err, data) {
if (err) // do something
this.setState({ users: data })
}.bind(this))
}
render() {
return(
<UserList user = {this.state.users} />
);
}
}
you can also Promise-ify things to simplify the logic
I'm doing a basic React app with data coming from my api. But the state is not updated when I do this.setState({}) after AJAX success. The state.events is empty in the render method.
What am I doing wrong?
import React, {PropTypes, Component} from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
events: []
};
}
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
})
.catch(function (error) {
console.warn(error);
});
}
render() {
// this.state.events keeps being an empty array []
return (
<div className="home">
{
this.state.events.map((month) => {
console.log(month)
})
}
</div>
);
}
}
export default App;
The way you are using should throw the error, check the console. You need to bind the context to use this keyword inside callback method that you are using in .then, Use this:
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then( response => {
console.log('data', response.data);
this.setState({events: response.data});
})
.catch(function (error) {
console.warn(error);
});
}
or use .bind(this) to bind the context, like this:
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
}.bind(this))
.catch(function (error) {
console.warn(error);
});
}
You need to bind axios success function to the correct context to make use of setState. USe this
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
},bind(this))
.catch(function (error) {
console.warn(error);
});
}
this
inside callback doesn't refer to your component context for that you need to bind your callback function of axios with your react component to update state of that component
import React, {PropTypes, Component} from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
events: []
};
}
componentDidMount() {
axios.get('http://localhost:4000/api/v1/events')
.then(function (response) {
this.setState({events: response.data});
}.bind(this)) // binding of callback to component
.catch(function (error) {
console.warn(error);
});
}
render() {
// this.state.events keeps being an empty array []
return (
<div className="home">
{
this.state.events.map((month) => {
console.log(month)
})
}
</div>
);
}
}
I have a function in controller:
function get(request) {
return UserService.get({
id: request.id,
transformResponse: function(data) {
return angular.fromJson(data);
}
});
};
And test like this:
var $scope;
var controller;
var UserService;
beforeEach(function() {
angular.mock.module(function($provide) {
UserService = jasmine.createSpyObj('UserService', ['get']);
$provide.value('UserService', UserService);
});
});
beforeEach(inject(function($rootScope, $controller, UserService) {
$scope = $rootScope.$new();
controller = $controller('...' {
$scope: $scope,
UserService: UserService
});
$scope.$digest();
}));
it('should call user service get function when getting user', function() {
var request = { id: 5 };
controller.get(request);
expect(UserService.get).toHaveBeenCalledWith(request);
});
Test passed, but karma coverage display that function transformResponse not covered by the test.
How I must correctly mock this function? Thanks!
I would like to send a post request to my API. It works with jQuery :
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
$.ajax({
type: "POST",
url: "api.php?option=inscription",
data: {lol : "mess"}
});
</script>
But it doesn't with AngularJS :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> </script>
{{1+1}}
<script>
$http.post('api.php?option=inscription', {lol : "mess2"})
.success(function(){alert('cool');});
</script>
If someone can help me. Thank you !
UPDATE :
Thank for your answers, I wanted to simplify but it wasn't clear anymore. So with your help, this is my new code, and the problem is the same. The data in the backend is empty ;
frontend :
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> </script>
<div ng-controller="MainCtrl"></div>
{{data}}
<script>
var app = angular.module('myApp', []);
app.service('SomeService', function($http) {
this.readData = function(dataUrl, dataTobePosted) {
var back = $http.post(dataUrl, dataTobePosted);
back.success(function(data){
console.log(data);
return data;
}).error(function(data, status, headers, config) {
return status;
});
}
});
app.controller('MainCtrl', function($scope, $http, SomeService){
$scope.readData = function(url) {
var dataTobePosted = {"lol": "mess"};
$scope.data = SomeService.readData(url, dataTobePosted);
}
$scope.readData('api.php?option=inscription');
});
</script>
</html>
For clarity, I am suggesting a simple implementation. However, further reading may needed in order to understand the behaviour precisely.
angular.module('myApp').service('SomeService', function($http) {
this.readData = function(dataUrl, dataTobePosted) {
// read data;
return $http.post(dataUrl, dataTobePosted)
.then(function(res) {
return res.data;
}, function(res) {
return res;
}
}
return this;
});
angular.module('myApp').controller('MyController', function($scope, SomeService) {
$scope.readData = function(url) {
var dataTobePosted = {"lol": "mess"};
SomeService.readData(url, dataTobePosted)
.then(function(res) {
$scope.data = res;
}, function(res) {
// Display error
}
}
$scope.readData('api.php?option=inscription');
}
Usage in the HTML page
<div ng-controller="MyController">
{{data}}
</div>
You're using AngularJS as if it's jQuery. It's not. AngularJS works with dependency injection, so you need to wrap your $http call inside a controller.
You should probably read up on AngularJS. A few useful links:
https://docs.angularjs.org/guide/introduction
https://docs.angularjs.org/guide/controller
https://docs.angularjs.org/guide/di
"Thinking in AngularJS" if I have a jQuery background?
My bad, my problem came from my backend in the php I just get my data with :
$data = json_decode(file_get_contents("php://input"));
and not with $_POST
I'm using jasmine+karma to run the following code...
and get the following error:
Expected { then : Function, catch : Function, finally : Function } to equal 123.
Can someone help me understand why I don't get a resolved value for my promise. thanks
'use strict';
angular
.module('example', ['ui.router'])
.config(function($stateProvider) {
$stateProvider
.state('stateOne', {
url: '/stateOne',
resolve: {cb: function($q) {
var deferred = $q.defer();
deferred.resolve(123);
return deferred.promise;
}},
controller: function($scope, cb) {console.log(' * in controller', cb);},
templateUrl: 'stateOne.html'
});
})
.run(function($templateCache) {
$templateCache.put('stateOne.html', 'This is the content of the template');
});
describe('main tests', function() {
beforeEach(function() {module('example');});
describe('basic test', function($rootScope) {
it('stateOne', inject(function($rootScope, $state, $injector, $compile) {
var config = $state.get('stateOne');
expect(config.url).toEqual('/stateOne');
$compile('<div ui-view/>')($rootScope);
$rootScope.$digest();
expect($injector.invoke(config.resolve.cb)).toEqual(123);
}));
});
});
Ok, Figured it out with some help (via email) from Nikas, whose blog I found at:
http://nikas.praninskas.com/angular/2014/09/27/unit-testing-ui-router-configuration/.
Here is a succinct example that demonstrates how to test the resolve values in ui.router, where the values involve $http.
angular
.module('example', ['ui.router'])
.factory('Clipboard', function($http) {
return {
get: function(args) {
return $http.get('/db/clipboard');
}
};
})
.config(function($stateProvider) {
$stateProvider
.state('stateOne', {
resolve: {cb: function(Clipboard) {
return Clipboard.get();
}}
});
});
describe('main tests', function() {
beforeEach(function() {module('example');});
it('stateOne', inject(function($state, $injector, $httpBackend) {
$httpBackend.whenGET('/db/clipboard').respond({a:1});
$injector.invoke($state.get('stateOne').resolve['cb'])
.then(function(res) {console.log(' *res ', res.data);})
.catch(function(err) {console.log(' *err ', err);});
$httpBackend.flush();
}));
afterEach(inject(function($httpBackend) {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
}));
});