I have a very simple Spring Rest backend that returns JSON data. The restful URL is working in my browser like this:
http://localhost:8080/abc/runlist
It returns data like so:
[
{"stock_num":"KOH19","damage":"Toronto (Oshawa)"},
{"stock_num":"AZ235","damage":"Toronto (Oshawa)"},
...
]
I have an independent html page that is not part of my web app. I just want to test to see if my angular code is getting the data and then looping through it.
<!DOCTYPE html>
<html>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="customersCtrl">
<ul>
<li ng-repeat="x in names">
{{ x }}
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://localhost:8080/abc/runlist")
.success(function (response) {$scope.names = response.records;});
});
</script>
yo yo
</body>
</html>
Why is it not working? I came across something in Spring where you need to implement something called CORS. I did that like so but still nothing returned:
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain
chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS,
DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
Try something like:
js:
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://localhost:8080/abc/runlist")
.success(function (response){
$scope.names = records;
});
});
html:
<ul>
<li ng-repeat="x in records">
{{x}}
</li>
</ul>
more params html:
<ul>
<li ng-repeat="x in records">
{{x.myName}}
{{x.myNumber}}
</li>
</ul>
Hope I've been helpfull.
Try putting return in front of your $http.get
<script>
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
return $http.get("http://localhost:8080/abc/runlist").success(function (response) {
$scope.names = response;
});
});
</script>
then in your view use the dot notation to refer to the properties you want to display e.g.
{{x.stock_num}}
Got it! There were 2 fixes:
Firstly I had to implement the CORS filter and class in order not get this error:
org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:339)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:418)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:406)
Secondly, a warning for example copiers! I had copied the simple example above from W3Schools, a great tutorial site as such:
$http.get("http://localhost:8080/abc/runlist")
.success(function (response) {$scope.names = response.records;});
Note the .records at the end of response. This was not needed. When I took it off, it worked.
More than likely it's being caused by your use of the file:// scheme. See the middle bullet on the linked question here for reasoning. Basically your origin is going to be null for file:// requests, which causes XmlHttpRequest to fail, which $http relies on.
try this:
$http.get("http://localhost:8080/abc/runlist")
.success(function (response, data, headers, status, config) {
$scope.names = response.names;
});
hope it will work. :)
Related
I'm having trouble getting responses from certain sites using http.get. Every get I do from Firebase seems to work, but many other sites do not, although the requests work fine from my browser or curl. I have two URL's that provide the exact same data, one from Firebase and another from a Cloud9 project. The Firebase one works and the c9 one doesn't.
When it doesn't work I get the following response:
{"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"http://dl-celeb-dp-x2jroy.c9users.io:8081/getScoreboard","headers":{"Accept":"application/json, text/plain, */*"}},"statusText":""}
I've tried HTTP as well as HTTPS for the one that isn't working but I get the same response either way.
I have a fiddle to demonstrate:
https://jsfiddle.net/9d7mysns/
HTML:
<h1>{{result}}</h1>
<p>{{content}}</p>
</div>
Javascript:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$http.get("https://blazing-torch-1276.firebaseio.com/getScoreboard.json") //Working
//$http.get("https://dl-celeb-dp-x2jroy.c9users.io:8081/getScoreboard") //Not Working
.then(function(response) {
$scope.result = "Success";
$scope.content = response;
}, function(response) {
$scope.result = "Error";
$scope.content = response;
});
});
Please help,
Thanks!
I think the second one is not allowing Cross-Domain request. This is what I see in the Chrome console for your fiddle.
XMLHttpRequest cannot load https://dl-celeb-dp-x2jroy.c9users.io:8081/getScoreboard. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.
Try this:
var app = angular.module('myApp', []);
app.controller('myCtrl',['$scope', '$http', function($scope, $http) {
//$http.get("https://blazing-torch-1276.firebaseio.com/getScoreboard.json") //Working
$http.get('https://dl-celeb-dp-x2jroy.c9users.io:8081/getScoreboard',{
header : {'Content-Type' : 'application/json; charset=UTF-8'}
}) //Now Working
.success(function(response) {
$scope.result = "Success";
$scope.content = response;
}).error(function(response) {
$scope.result = "Error";
$scope.content = response;
});
}]);
I'am trying to make simple web application using TMDB api but I'm having trouble with some request.
I'am successfully connecting to its api and getting all needed data and displaying it nicely. Problem is when i load my Homepage which has poster_path of movie, i get all posters nicely and displayed but in chrome dev tools I can see there is one more extra request sent (not sent by me... at least not on purpose) and its failing and wracking my app.
Chrome displays following for bad request:
GET file:///C:/Users/Ivan/Documents/testProject/fmdb-fjume-movie-database/app/%7B%7BimageBaseUrl%7D%7D/%7B%7Bmovie.poster_path%7D%7D net::ERR_FILE_NOT_FOUND
Status: failed
Initiator: other
Here's my code for getting information and html:
Home view
<div class="well main-frame">
<h1>MY MOVIE DATABASE</h1>
<div class="row row-centered">
<div class="col-sm-2 col-centered" style="text-align:center;" ng-repeat="movie in movies | limitTo:2">
<img id="homeThumbnailImg" src="{{imageBaseUrl}}/{{movie.poster_path}}"></img>
{{movie.original_title}}
</div>
</div>
</div>
Home controller
'use strict';
angular.module('home', ['services'])
.controller('homeCtrl', ['$scope', '$q', 'api', 'globals', function($scope, $q, api, globals) {
$scope.imageBaseUrl = globals.getImageBaseUrl();
$scope.getData = function() {
$q.all([
api.discover('movie')
]).then(
function(data) {
$scope.movies = data[0].data.results;
//console.log(data[0].data.results);
},
function(reason) {
console.log(reason);
});
}
$scope.getData();
}]);
API
'use strict';
angular.module('services', [])
.constant('baseUrl', 'http://api.themoviedb.org/3/')
.constant('apiKey', 'myKey...')
.factory('api', function($http, apiKey, baseUrl) {
return {
discover: function(category) {
var url = baseUrl + 'discover/' + category + '?certification_country=US&certification.lte=G&sort_by=popularity.desc&api_key=' + apiKey;
return $http.get(url).success(function(data) {
return data;
});
},
search: function() {
},
...
Thank you all for your time!
You should change your img tag to look like this:
<img id="homeThumbnailImg" ng-src="{{imageBaseUrl}}/{{movie.poster_path}}"></img>
Note the ng-src attribute that replaces the src attribute. This will prevent the browser from trying to fetch the literal string {{imageBaseUrl}}/{{movie.poster_path}} before angular has a chance to eval that expression.
Here's the code: http://jsbin.com/rucatemujape/1/edit?html,js,console,output
My question is how do I manually call method changeUser from JavaScript so the output HTML changes?
I can do this by executing (relies on jQuery)
angular.element('body').scope().changeUser({fullName: 'John Doe'});
angular.element('body').scope().$apply()
But I want to know is there any better way?
For example, in knockout.js I can execute viewModel.someFunction() any time and knockout correctly handles this.
Why do I want to do this: because I want be able to change model from browser's console when debugging a code.
Edit: Another reason why I need this it's getting information from Restful Services and updating a model. Yes I can trigger that event by clicking a button with "ng-click" attribute but how to deal with events which are not initiated by user? For example, repeating ations from setInterval or something
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function($scope, $timeout) {
$scope.user = {};
$scope.count = 0;
$scope.changeUser = function(user) {
$scope.user = "MyName";
$scope.count++;
// call function after 1 sec.
$timeout($scope.changeUser, 1000);
};
// initiate function
$scope.changeUser();
});
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
</head>
<body ng-controller="MyController"
<span>Hello, {{user}}</span>
<span>count, {{count}}</span>
</body>
</html>
Use ng-click="changeUser()" to call the fucntion
http://jsbin.com/rucatemujape/2/edit
Controllers do not really expose "APIs" outside their own 'scope' (and below). So either you do the Ajax call within the controller or you expose the "user data" to display.
For example: Kostia Mololkin's answer's (in main comments) uses a global variable to share the data.
Angular Way
Here I present a more "angular way": the user is being handled by a "Service". Not clear which direction you wanted exactly. Anyway, this cannot hurt.
Angular works best when you use "data" to "communicate state" instead of "events". So the idea again is to arrange things so your data instance (i.e. "user") is the same between "{{user.fullname}}" and where the Ajax call is taking place. There are many ways to skin a cat and it highly depends on the needs of your application. For example, if you build a singleton service for the ajax call, you can also have the data own by it AND exposed to the controller in some form or another (again, many ways of doing this).
NOTE: If you use angular's system to perform ajax calls (i.e. $http or $resource for instance) then you should never need to manually call "$apply()". Btw, you should "wrap" calls with $apply() instead of calling it "afterwards" reason being to properly handle "throws".
Plunker example with Ajax/Rest call:
http://plnkr.co/edit/SCF2XZCK5KQWkb4hZfOO?p=preview
var myApp = angular.module('myApp', []);
myApp.factory('UserService', ['$http',function($http){
// Extra parent object to keep as a shared object to 'simplify'
// updating a child object
var userData = {};
userData.user = { fullName:'none' };
function loadUserData(userid) {
$http.get('restapi_getuserdata_'+userid+'.json').
success(function(data, status, headers, config) {
// update model
userData.user = data;
}).
error(function(data, status, headers, config) {
console.log("error: ", status);
});
}
return {
userData: userData,
loadUserData: loadUserData
};
}]);
myApp.controller('MyController', ['$scope', 'UserService', '$timeout',
function($scope, UserService, $timeout) {
// shared object from the Service stored in the scope
// there are many other ways, like using an accessor method that is
// "called" within the HTML
$scope.userData = UserService.userData;
}]);
myApp.controller('SomeOtherController', ['UserService', '$timeout',
function(UserService, $timeout) {
// $timeout is only to simulate a transition within an app
// without relying on a "button".
$timeout(function(){
UserService.loadUserData(55);
}, 1500);
}]);
HTML:
<html ng-app="myApp">
...
<body ng-controller="MyController">
<span>Hello, {{userData.user.fullName}}</span>
<!-- simulating another active piece of code within the App -->
<div ng-controller="SomeOtherController"></div>
...
A variant using a getter method instead of data:
http://plnkr.co/edit/0Y8gJolCAFYNBTGkbE5e?p=preview
var myApp = angular.module('myApp', []);
myApp.factory('UserService', ['$http',function($http){
var user;
function loadUserData(userid) {
$http.get('restapi_getuserdata_'+userid+'.json').
success(function(data, status, headers, config) {
console.log("loaded: ", data);
// update model
user = data;
}).
error(function(data, status, headers, config) {
console.log("error: ", status);
user = undefined;
});
}
return {
getCurrentUser: function() {
return user || { fullName:"<none>" };
},
userLoggedIn: function() { return !!user; },
loadUserData: loadUserData
};
}]);
myApp.controller('MyController', ['$scope', 'UserService', '$timeout',
function($scope, UserService, $timeout) {
// getter method shared
$scope.getCurrentUser = UserService.getCurrentUser;
}]);
myApp.controller('SomeOtherController', ['UserService', '$timeout',
function(UserService, $timeout) {
// $timeout is only to simulate a transition within an app
// without relying on a "button".
$timeout(function(){
UserService.loadUserData(55);
}, 1500);
}]);
HTML:
<html ng-app="myApp">
...
<body ng-controller="MyController">
<span>Hello, {{ getCurrentUser().fullName }}</span>
<!-- simulating another active piece of code within the App -->
<div ng-controller="SomeOtherController"></div>
...
Please advice,
I am creating rest client with json output using angular js , although rest data has received, but it never populated correctly into view html.
is there any wrong $scope data defined at angular controller?
Below is the json rest output data.
{
"Job": [
{
"id": "1",
"prize": "car"
}
]
}
and
the javascript controller with name "some.js"
var app = angular.module("MyApp", []);
app.controller("PostsCtrl", function($scope, $http) {
$http.get('jsonURL').
success(function(data, status, headers, config) {
$scope.posts = data.Job;
}).
error(function(data, status, headers, config) {
});
});
and
html view
<!doctype html>
<html ng-app="MyApp">
<head>
<title>Test AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="some.js"></script>
</head>
<body>
<div ng-controller="PostsCtrl">
<ul ng-repeat="post in posts">
<p>The ID is {{post.id}}</p>
<p>The prize is {{post.prize}}</p>
</ul>
</div>
</body>
</html>
It looks ok to me. One thing you might need to check is that the http response has a content-type header of application/json, otherwise angular will not parse the data correctly.
Try this as a work-around:
var jsonResponse = eval('('+data+')');
$scope.posts = jsonResponse.Job;
Or just make sure your header is set correctly and you shouldn't have to do this.
I'm just getting started with Angular.js and I'm not sure how to "link" two "models" together. I have the following code in my index.php file
<div ng-controller="AccountCtrl">
<h2>Accounts</h2>
<ul>
<li ng-repeat="account in accounts">
<span>{{account.id}} {{account.ownedBy}}</span>
</li>
</ul>
</div>
<div ng-controller="TransactionCtrl">
<h2>Transactions</h2>
<ul>
<li ng-repeat="transaction in transactions">
<span>{{transaction.id}} {{transaction.timestamp}} {{transaction.amount}} {{transaction.description}} {{transaction.account}}</span>
</li>
</ul>
</div>
and the following js
function AccountCtrl($scope, $http) {
// initialize Data
$http({
method:'GET',
url:'http://api.mydomain.ca/accounts'
}).success(function(data, status, headers, config) {
$scope.accounts = data;
}).error(function(data, status, headers, config) {
alert('Error getting accounts. HTTP Response status code: '+status);
});
}
function TransactionCtrl($scope, $http) {
// initialize Data
$http({
method:'GET',
url:'http://api.mydomain.ca/transactions'
}).success(function(data, status, headers, config) {
$scope.transactions = data;
}).error(function(data, status, headers, config) {
alert('Error getting transactions. HTTP Response status code: '+status);
});
}
So in my example each account will have many transactions and I want to add a function to my account controller to calculate the balance of the account based on the transactions but I'm not sure how to do that because they are in different $scopes.
Is there a way to do this in Angular or do I have to return the "linked" transaction information in my JSON response from the server when I get the accounts?
I guess account holds transactions, right?
Then I guess, you can create an service to manage account / transaction data.
Inject this service into both controllers.
module = angular.module('app', []);
module.factory('accountService', function($http) {
var obj = {
// handles http communication to/from server.
// also has methods/getters/setters for data manipulation, etc.
};
return obj;
});
module.controller('AccountCtrl', function($scope, accountService) {
// access accountService for the view-databind.
});
module.controller('TransactionCtrl', function($scope, accountService) {
// access accountService for the view-databind.
});
Since you are making both http requests at the same time, I would change my service to return the transactions as a property of the account object. Then it would be one server call, less overhead, and you data would be in the format that you need it in. I think you have the right idea with your last question.
And good choice using Angular. If you haven't found them yet, John Lindquest released a great set of videos at egghead.io.