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.
Related
ngResource in factory works fine but unfortunately the result able to select JSON index. At the same time it is possible to bind the same $scope.resultItems variable
Console log appear like this 👇
Not working from ngResource http://codepen.io/anon/pen/dMbRXx
Working fine from variable http://codepen.io/anon/pen/ONLgNX
var app = angular.module('app', ['ngResource']);
app.controller('myCtrl', function($scope, categoryFilter) {
$scope.resultItems = categoryFilter.query();
$scope.resultIndex = $scope.resultItems[0];
$scope.resultIndexItem = $scope.resultItems[0].status;
});
app.factory('categoryFilter', function($resource) {
return $resource("https://maps.googleapis.com/maps/api/geocode/json?address=NY", {}, {
query: {
method: "GET"
}
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-resource/1.5.0/angular-resource.min.js"></script>
<div class="container" ng-app="app" ng-controller="myCtrl">
<div class="col-xs-12">
<h3>ngResource result</h3>
<pre>{{resultItems | json }}</pre>
<hr />
<pre>{{resultIndex | json }}</pre>
<hr />
<pre>{{resultIndexItem | json}}</pre>
</div>
</div>
Each resource in fact is a ajax request that means it is asynchronous, So you have to use callbacks to query function. Then your code looks like this
var app = angular.module('app', ['ngResource']);
app.controller('myCtrl', function($scope, categoryFilter) {
categoryFilter.query(function(results){
$scope.resultItems = results;
$scope.resultItems.results[0];
$scope.resultIndexItem = $scope.resultItems.status;
});
});
app.factory('categoryFilter', function($resource) {
return $resource("https://maps.googleapis.com/maps/api/geocode/json?address=NY", {}, {
query: {
method: "GET"
}
});
});
link
Update
Sorry If I miss read you question, All items in json within {} will be an object can be accessed using ., For example in json results and status is object and items represented in [] is an array and they can be accessed using index.
From json
I am trying to set a header value based on the value in my controller. I have the header sending when I am hard coding it as shown below but how can I pass the value from the controller into the ngResource get request,
eg I want the value of anything in the headers to be the value from my controller.
var app = angular.module('app', ['ngResource']);
app.factory('UserService', function ($resource) {
return $resource('http://jsonplaceholder.typicode.com/users/:user',{user: "#user"},{
get: {
method: 'GET',
headers: { 'something': 'anything' }
}
});
});
app.controller('TestCtrl', function($scope, $resource, UserService) {
$scope.test = "text";
UserService.get({
user: 2
}, function(data) {
$scope.id = data.id;
}, function(err) {
console.log(err);
});
});
<!doctype html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<title ng-bind="title" ng-cloak>Restaurant</title>
</head>
<body ng-controller="TestCtrl">
id - {{id}}
<!-- Don't forget to load angularjs AND angular-resource.js -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-resource.js"></script>
<!--Controllers-->
</body>
</html>
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. :)
I have an HTML which looks like -
<div ng-controller="PostsCtrl">
<ul ng-repeat="post in posts" style="list-style: none;">
<li style="padding: 5px; background-color: #f5f5f5;">
<h4>
{{post.postTitle}}
</h4>
<div class="post-details" ng-show="showDetails">
<p>{{post.postContent}}</p>
</div>
</li>
</ul>
</div>
Now the data is being populated from a JSON based REST URL and being displayed. I also have a form that will be adding new post to the database-
<form data-ng-submit="submit()"
data-ng-controller="FormSubmitController">
<h3>Add Post</h3>
<p>
Title: <input type="text" data-ng-model="postTitle">
</p>
<p>
Content: <input type="text" data-ng-model="postContent">
</p>
<p>
Tags: <input name="postTags" data-ng-model="postTags" ng-list
required>
</p>
<input type="submit" id="submit" value="Submit" ng-click="loadPosts()" /><br>
</form>
I basically want to achieve two things -
1. As soon as i add new post it shows up in the list of posts above.
2. As soon as i manually add a new post in the backend, front end automatically updates.
Is it possible to achieve both using angular and if yes how will i be able to do that.
Below is my controller code, which as of now is showing me existing posts as well as letting me add new post to DB.
<script>
var app = angular.module("MyApp", []);
app.controller("PostsCtrl", function($scope, $http) {
$http.get('http://localhost:8080/MyApp/posts')
.success(function(data, status, headers, config) {
$scope.posts = data;
}).error(function(data, status, headers, config) {
console.log("Error in fetching the JSON data.");
});
$scope.$watch('posts', function(newVal, oldVal){
console.log('changed');
alert('hey, myVar has changed!');
}, true);
/*$scope.$watch('posts', function() {
alert('hey, myVar has changed!');
console.log("test log");
$scope.$digest();
});*/
});
app.controller('FormSubmitController', [ '$scope', '$http',
function($scope, $http) {
$scope.loadPosts = function() {
$http.get('http://localhost:8080/MyApp/posts')
.success(function(data, status, headers, config) {
$scope.posts = data;
alert(JSON.stringify(data));
//$scope.posts_updated = data;
}).
error(function(data, status, headers, config) {
console.log("Error in fetching the JSON data.");
});
}
$scope.list = [];
$scope.submit = function() {
var formData = {
"postTitle" : $scope.postTitle,
"postContent" : $scope.postContent,
"postTags" : $scope.postTags,
"postedBy" : "admin"
};
var response = $http.post('addPost', formData);
response.success(function(data, status, headers, config) {
console.log("na");
});
response.error(function(data, status, headers, config) {
alert("Exception details: " + JSON.stringify({
data : data
}));
});
//Empty list data after process
$scope.list = [];
};
} ]);
</script>
Any help on this will be really appreciable.
1: on your success of post, you can just push the added object into your posts list. This will trigger the two-way-binding, and the object will "automatically" appear in your ng-repeater.
$scope.posts.push(element);
2: This one is a bit tricky, since angular is a client-side application, it doesn't recognize what happens on the server-side. What you have to do to make this work is to look at websockets (like SignalR or similar) that can make a push to your client whenever something gets added. This also depends on that your "manual" insert is done using a programatically method. Doing it directly from database-changes is going to be alot more painfull
Initialize $scope.posts before invoking $http request
$scope.posts = [];
Since you are using $http service, it should automatically repaint ng-repeat when new data found. So you don't need be to worried about it
Very important thing is that you don't need to call $digest when you use $http service. Using $digest blindly is a very bad practice and is major performance issue. In the end of $http service angular automatically call $digest so you don't need to call again
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>
...