I'm trying to create a basic webpage that shows data retrieved by http://rest-service.guides.spring.io/greeting.
The json output is:
{"id":2273,"content":"Hello, World!"}
I'm using the following html page:
<body ng-app="hello">
<div class="container">
<h1>Greeting</h1>
<div ng-controller="home" ng-cloak class="ng-cloak">
<p>The Id is: {{greeting.id}}</p>
<p>The content is: {{greeting.content}}</p>
</div>
</div>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>
<script src="js/hello.js"></script>
</body>
And the hello.js:
var myApp = angular.module('hello', []);
myApp.controller('home', ['$scope', function($scope) {
$scope.greeting = {};
$http.get('http://rest-service.guides.spring.io/greeting')
.success(function(data, status, headers, config) {
$scope.greeting = data;
});
}]);
Result: the placeholders greeting.id/content are not resolved. What might be wrong here?
You didn't inject $http service.
myApp.controller('home', ['$scope, $http', function($scope, $http) {...}]);
EDIT
It is also worth to metnion what cverb said in his answer. In Angular 1.4 you should replace .success() with .then(), because .success is deprecated.
Now usage should be:
$http.get(url).then(
function(data){
//success callback
},
function(){
//error callback
});
);
change your $http call to following. You have also not injected $http in your controller.
$http.get('http://rest-service.guides.spring.io/greeting')
.success(function(data, status, headers, config) {
$scope.greeting = data.data;
});
Change your .success() with .then(), the .success() method is deprecated and does not work in the same way as a normal promise.
If you wish to keep using it, you can just use it like this.
$http.get('http://rest-service.guides.spring.io/greeting')
.success(function(data) {
$scope.greeting = data;
});
Also see the documentation of $http.
Related
Ok so I am experimenting with Angular but I have run into a problem and maybe it is because I haven't adopted the Angular way of thinking yet, but this is basically what I ran into.
I get some data with a JSON request and show this data in a list using ng-repeat. So far so good. No errors in the console, but it does not attach the eventlistener to the ng-repeat elements. The code is fine, because with non ng-repeat elements it works like a charm. Someone else ran into this problem and how did you solve it? Thanks in advance.
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
JS
angular.module("app", ['ngRoute'])
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.factory('producteffecten', function() {
var effecten = {};
effecten.showdescription = $('ul').hover(function (){
$(this).append("<p>Test</p>");
});
return effecten;
})
The simple answer is: you can use $('ul').on("hover",function(){}). But this is not the angular way of thinking. The first improvement you could make is this:
add ng-mouseover="muisOverEffectje()" to the ul in the html
add $scope.muisOverEffectje=function(){ your event code} to the angular page
The next step to avoid adding the code with jquery to make it even more angular could be something like this:
add a parameter which gives the selected item to your event : muisOverEffectje(item)
add ng-show="showDescription" to the the ul
put show-description to true in the event handler
The last step could be: Make a directive for you . Like a product component for example.
Setting a timeout works, but it is hacky I guess. I will try to rewrite in a more angular way.
.factory('producteffecten', function() {
var effecten = {};
//SETTING TIMEOUT WORKS SOMEHOW
effecten.showdescription = setTimeout(function() {
$('ul').hover(function (){
$(this).append("<p>Test</p>");
});
}, 10);
return effecten;
})
You could also write an directive. Which is the nicest way in angular to do this kind of stuff:
Html:
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten" hover-text="item.effect">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
js:
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.directive("hoverText",function(){
return {link:function(scope,elem,attr){
var insertElem=$("<div class='hovertext'>"+scope.hoverText+"</div>")
elem .mouseenter(function() {
insertElem.appendTo(elem);
})
.mouseleave(function() {
insertElem.remove();
});
},
scope:{"hoverText":"="}
};
});
I'm trying to get which data has been changed in array. my use case is First time all data fetch from ajax and show within row and fetch new data using $http every 5 second. I need to know that if the new data is same as old one. If yes then which value has changed so I've to update that background to some color..
What I've already tried
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
}, 5000);
});
app.controller('RentalDateController', function($scope, $log){
console.log($scope.listings);
$scope.$watch('listings.Third_Column', function (Third_Column, oldvalue) {
//$log.info(Third_Column, $scope.listings.First_Column);
console.log('being watched oldValue:', oldvalue, 'newValue:', Third_Column);
}, true);
});
My html is
<body ng-app="app">
<div ng-controller="listingController">
<table>
<tr>
<th>Testing</th>
<th>Pripse</th>
</tr>
<tr ng-repeat="row in listings" ng-controller="RentalDateController">
<input type="text" ng-model="row.Third_Column">
<input type="text" ng-model="row.First_Column">
<th>{{row.Third_Column}}</th>
<th>{{row.First_Column}}</th>
</tr>
</table>
</div>
</body>
I think I need to use $watch but it's not working.
You have the angular two-way data binding so it should automatically update your ng-repeat when the model changes.
I suggest the following
1) Remove RentalDate controller first.
2) Use $timeout, and on success of http use this
$scope.$apply(function(){
$scope.listing = data;
});
If that doesn't still automatically update, put the array in an object.
$scope.data = {}
$scope.data.listings = putArrayHere();
This will work because of this. Read up. :D
https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance
Try doing this:
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
var previousListing = [];
var newData;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
if( previousListing.length == $scope.listings.length )
{
console.log('No new data available.');
}
else
{
// length of the arrays are different, hence new data must be available
console.log('New data available!');
newData = $scope.listings.splice( 0, ($scope.listings.length - previousListing.length) ); // returns new data in the form of an array
console.log(newData);
previousListing = $scope.listings; // reset previous data variable
}
}, 5000);
});
am try to develop an application using angular js in which i take take data from database and populate li using that data
for that i write a WebMethod as fallow
[WebMethod]
public static string getname()
{
SqlHelper sql = new SqlHelper();
DataTable dt = sql.ExecuteSelectCommand("select cust_F_name,Cust_L_Name from customer");
Dictionary<string, object> dict = new Dictionary<string, object>();
object[] arr = new object[dt.Rows.Count];
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
arr[i] = dt.Rows[i].ItemArray;
}
dict.Add(dt.TableName, arr);
JavaScriptSerializer json = new JavaScriptSerializer();
return json.Serialize(dict);
}
which return data in json form
am use the fallowing js to bind
var DemoApp = angular.module('DemoApp', []);
DemoApp.factory('SimpleFactory', function () {
var factory = {};
var customer;
$.ajax({
type: "POST",
url: "Home.aspx/getname",
data: JSON.stringify({ name: "" }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data, status) {
customer = $.parseJSON(data.d);
},
failure: function (data) {
alert(data.d);
},
error: function (data) {
alert(data.d);
}
});
factory.getCustomer = function () {
return customer;
};
return factory;
});
DemoApp.controller('SimpleController', function ($scope, SimpleFactory) {
$scope.Customer = SimpleFactory.getCustomer();
});
and my view is as fallow
<html xmlns="http://www.w3.org/1999/xhtml" data-ng-app="DemoApp">
<head runat="server">
<title></title>
</head>
<body data-ng-controller="SimpleController">
<form id="form1" runat="server">
<div>
Name<input type="text" data-ng-model="Name" />{{ Name }}
<ul>
<li data-ng-repeat="customer in Customer | filter:Name">{{ customer.cust_F_name }} -
{{ customer.cust_L_name }}</li>
</ul>
</div>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="Script/Home.js" type="text/javascript"></script>
</body>
</html>
but it not working it will work fine if i hard code the data in factory but when i bring data using ajax call it will not work am unable to understand why it so.
Why it's not working?
you cannot just attach a variable to the scope when it's value is waiting for on asynchronous call.
when you use 3rd-party libraries that changes the scope you must call $scope.$apply() explicitly
prefer $http over $.ajax and use promises!
DemoApp.factory('SimpleFactory', function ($http) {
return {
getCustomer: function(){
return $http.post('Home.aspx/getname',{ name: "" });
})
}
}
DemoApp.controller('SimpleController', function ($scope, SimpleFactory) {
SimpleFactory.getCustomer().then(function(customer){
$scope.Customer = customer;
},function(error){
// error handling
});
});
If you still want to use $.ajax
you must explicitly call $scope.$apply() after the response
you must use promises or callbacks to bind to scope variables.
If you want to first fetch data from the server and than load the view
#Misko Hevery has a great answer: Delaying AngularJS route change until model loaded to prevent flicker
It's not related to your problem but load jquery before you load angular.js
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
Your problem is the js (the function "SimpleFactory.getCustomer()") is returning before AJAX call returning..
Also, you should use $http in Angular instead of jquery's ajax, because:
$http returns a "promise" similar to other areas in angular, which means .success, .done are consistent with angular.
$http set the content type to 'application/json' for you on POST requests.
$http success and error callbacks will execute inside of angular context so you don't need to manually trigger a digest cycle - if you use jQuery, then it might be necessary to call $apply..
Like this:
var DemoApp = angular.module('DemoApp', []);
DemoApp.factory('SimpleFactory', ['$http', function ($http) {
var factory = {};
factory.getCustomer = function () {
var promise = $http.post('Home.aspx/getname', {name: ''});
promise.catch(function(error) {
alert(error);
});
return promise;
};
return factory;
}]);
DemoApp.controller('SimpleController', ['$scope', 'SimpleFactory', function ($scope, SimpleFactory) {
SimpleFactory.getCustomer().then(function(customer) {
$scope.Customer = customer;
});
}]);
Factories in AngularJS are singletons. So the way you've written the code will execute the ajax call when the factory is injected into the controller. You don't see the customer data because the server response will be handled after you assign the json data to the scope variable.
A quick (and dirty) fix which will probably work is wrapping the customer object:
DemoApp.factory('SimpleFactory', function ($rootScope) {
// ...
var customer = {};
// ...
$.ajax({
// ...
success: function(data) {
$rootScope.$apply(function() {
customer.data = data;
});
}
// ...
});
});
// In view
<li data-ng-repeat="customer in Customer.data"> <!-- ... --> </li>
A better approach would be to use either to use the builtin $http or the $resource angular service. The last one requires you to make use of RESTful services (recommended). If for any reason you still want to make use of jQuery ajax calls you need some form of telling Angular that the ajax call has been completed: have a look at the $q promise service.
I have a REST service that I made which returns a json string which is simply a set of strings (I used Gson to generate this string (Gson.toJson(mySetOfStrings))
So I have added to my index.html:
<div ng-controller="ListOptionsCtrl">
<form novalidate>
<button ng-click="refreshList()">refresh</button>
<select name="option" ng-model="form.option" ng-options="o.n for o in optionsList></select>
</form>
</div>
and in my script:
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.optionsList = angular.fromJson(data);
});
};
}
Unfortunately all this produces in my select box is an empty list. When I see what the response to the GET request is it returns a json string with content in it so I do not see why nothing is being added to this element. What am I doing wrong here? thanks
It is because Angular does not know about your changes yet. Because Angular allow any value to be used as a binding target. Then at the end of any JavaScript code turn, check to see if the value has changed.
You need to use $apply
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
});
};
}
Try this.
More about how it works and why it is needed at Jim Hoskins's post
You should check for $digest error by doing if(!$scope.$$phase) { ... } before doing $apply.
success(function(data) {
if(!$scope.$$phase) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
}
});
I am trying to write a simple app that does the following:
1. User inputs 2 parameters & clicks a button
2. Angular calls an external JAVA Servlet that returns JSON
3. App outputs the json string to the screen
I have a problem however, as when i click the button nothing happens. I believe (due to testing) that the reason this happens is that since the call is async, the variable that is returned is null.
Pertinent code:
controllers.js
function myAppController($scope,kdbService) {
$scope.buttonClick = function(){
var dat = kdbService.get($scope.tName,$scope.nRows);
$scope.data = dat;
}
}
services.js
angular.module('myApp.services', []).factory('kdbService',function ($rootScope,$http){
var server="http://localhost:8080/KdbRouterServlet";
return {
get: function(tname,n){
var dat;
$http.jsonp(server+"?query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
console.log("1");
console.log(data);
dat=data;
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
console.log("2");
console.log(dat);
return dat;
}
}
});
index.html
<!-- Boilerplate-->
<h1>Table Viewer</h1>
<div class="menu" >
<form>
<label for="tName">Table Name</label>
<input id="tName" ng-model="tName"><br>
<label for="nRows">Row Limit</label>
<input id="nRows" ng-model="nRows"><br>
<input type="submit" value="Submit" ng-click="buttonClick()">
</form>
</div>
{{data}}
<!-- Boilerplate-->
When i execute the code and push the button, nothing happens. However, if i look in my log, i see this:
2
undefined
1
Object {x: Array[2], x1: Array[2]}
Clearly, what is happening is that the success function returns after the get function has returned. Therefore the object put into $scope.data is undefined, but the object returned from the jsonp call is left behind.
Is there a correct way to be doing this? Most of the tutorials I see assign the data to the $scope variable inside the success function, thereby skipping this problem. I want my service to be detached if possible.
Any help would be appreciated.
i would do something like that :
controller
function myAppController($scope,kdbService) {
$scope.kdbService = kdbService;
$scope.buttonClick = function(){
$scope.kdbService.get($scope.tName,$scope.nRows);
}
}
service
angular.module('myApp.services', []).factory('kdbService',function ($rootScope,$http){
var server="http://localhost:8080/KdbRouterServlet";
return {
data:{},
get: function(tname,n){
var self = this;
$http.jsonp(server+"?
query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
console.log("1");
console.log(data);
self.data = data;
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
}
}
});
html
{{kdbService.data}}
OR
use continuation in the get method :
controller
function myAppController($scope,kdbService) {
$scope.buttonClick = function(){
kdbService.get($scope.tName,$scope.nRows,function success(data){
$scope.data = data;
});
}
}
service
get: function(tname,n,successCallback){
$http.jsonp(server+"?query=krisFunc[`"+tname+";"+n+"]&callback=JSON_CALLBACK").
success(function(data, status, headers, config) {
successCallback(data,status,headers,config);
}).
error(function(data, status, headers, config) {
alert("ERROR: Could not get data.");
});
}
OR use the $resource service
http://docs.angularjs.org/api/ngResource.$resource ( you'll need the angular-resource module
code not tested.
I want my service to be detached if possible.
then put the "data object" in a "data service" calling a "data provider service". You'll have to call the "data provider service" somewhere anyway. There is no skipping this problem in my opinion, since that's how javascript work.
also use angular.controller("name",["$scope,"service",function($s,s){}]);
so you will not need to care how parameters are called , as long as they are defined and injected properly.