I have a Service which uses $http to 'get' some JSON data from a REST API. The Controller uses the Service to get this data and initialise it in the $scope. How can I make it so that every time the JSON API changes that change is updated in the $scope, and thus the view?
Controller:
app.controller('MainController', function ($scope, BuildService) {
init();
function init() {
BuildService.getBuilds().then(function() {
$scope.builds = BuildService.data();
});
}
});
Service:
app.service('BuildService', function ($http, $q) {
var BuildService = {};
var deffered = $q.defer();
var data = [];
BuildService.getBuilds = function () {
//return builds;
$http.get('/api').
success(function(d, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
data = d;
deffered.resolve();
}).
error(function(d, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
deffered.reject();
});
return deffered.promise;
};
BuildService.data = function() { return data; };
return BuildService;
});
This question is not AngularJS-specific. What you want to achieve is a real-time app.
Method 1: polling
Use $interval to check JSON API every 30 seconds or so.
Method 2: WebSocket-based notification
If you have control over the JSON API, you can create another WebSocket-based notification API. Whenever JSON API changes, notify client to fetch JSON API again.
I'd say you really have too much unneccessary logic. Keep it simple and just go like that. If you want to reuse the GET you can do it in a getBuilds controller method.
app.controller('MainController', function ($scope, $http, BuildService) {
init();
function init() {
$http.get('/api').
success(function(data) {
$scope.builds = data;
});
}
});
Related
I have an angular controller which makes an HTTP GET request and on the promise return, calls either a success of error function. My code right now will sometimes execute the success function after the GET request returns and sometime execute before it. Is there something I'm messing up in my promise handling? Something to note, sometimes the http GET doesn't even get called (or at least its breakpoint) and the success function happens regardless. Here is my code:
.controller('CheckOutCtrl', ['$scope', '$http', function($scope, $http) {
//Controller for checkout feature
$scope.owner = "Unclaimed"; //Default owner
$scope.endDate = "";
$scope.unclaimed = true;
$scope.showpopup = false; //Should we show the popup that checkout is successful or returned
$scope.currentOwner = false; //Show return date
$scope.popuptext = "";
$scope.checkOut = function(){ //Extends or creates a check out
$http.get("/checkout/extend/code/" + code + "/username/" + userName).then(
function success(response, status, headers, config) {
console.log("Checked out or extended");
$scope.showpopup = true;
$scope.currentOwner = true;
$scope.popuptext = response.data; //Show airport checked out until or error
console.log($scope.popuptext);
init(); //Update current owner
},
function error(response, status, headers, config) {
$scope.error = response;
console.error("Check out error:", response);
}
);
};
}
I discovered this was happening because Angular caches GET requests for some time and the cached version of my request was being used.
I am trying to sort out the best way to do the following:
At the request of our backend developer we want to have a json file that contains a master list of the api urls that are used in requests by my frontend. This way the end user's browser only makes one request for the object and we can then pass them this into other services. so for example...
the dataUrl JSON contains the following
{
"emails":"json/emails.json",
"mapping":"json/mapping.json",
"profile":"json/profile.json"
}
and I would need to store that as a variable that could be used in all of my api calls like such:
app.factory('Emails', ['$http', function($http, Urls) {
var url = ""; //something here to get the dataUrl object for "emails"
var query = {};
query.getItems = function () {
return $http.get(url.emails); //from var emails above?
};
return query;
}]);
What is going to be my best approach to this?
This is what I tried so far and it didn't work...
app.factory('Urls', ['$http', function($http) {
var query = {};
query.getItems = function () {
return $http.get('json/dataUrls.json');
};
return query;
}]);
app.factory('Emails', ['$http', function($http, Urls) {
Urls.getItems().then(function(response) {
var url = response.data.emails;
console.log(url);
})
var query = {};
query.getItems = function () {
return $http.get('json/emails.json');
};
return query;
}]);
This results in a console error TypeError: Cannot read property 'getItems' of undefined
You are injecting dependency in wrong way
First inject it then create it's instance
Try this
Replace
app.factory('Emails', ['$http', function($http, Urls) {
to
app.factory('Emails', ['$http', 'Urls', function($http, Urls) {
Trying to get JSON data from an API and show the result in a view using AngularJS. I'm able to get the data correctly but unable to show it in the view.
When i try to access the object's data the result is always undefined.
Here's what i'm doing...
API Service:
myApp.service('apiService', ['$http', function($http)
{
var api = "http://domain.xpto/api/";
var self = this;
this.result;
var apiService =
{
getSection: function(id)
{
var url = api + "section/" + id;
return $http.get(url);
}
}
return apiService;
}]);
Controller:
myApp.controller('mainController', ['$scope', '$routeParams', 'apiService', function($scope, $routeParams, apiService)
{
apiService.getSection(1).then(function(response)
{
$scope.$applyAsync(function ()
{
var data = response.data; //json data as expected
var section = data.section; //undefined?!
var images = data.images; //undefined!?
$scope.title = section.title; //undefined!?
});
});
}]);
JSON Result:
UPDATE: Simplified my apiService based on #Salih's and #elclanrs's suggestion.
Why am i unable to access the inner objects of the json (f.e, data.section.title)?
UPDATE #2: I'm finally able to access the data. It seems i needed an extra data level to get access to the section object of my json array (response.data.data.section). Honesty i don't understand why. I've accessed the API using jquery and it was strait forward...
Edit: I made this plunker to help you!
http://embed.plnkr.co/Yiz9TvVR4Wcf3dLKz0H9/
If I were you, I would use the service function to update the own service value. You already created this.result, you can just update its value.
Your Service:
myApp.service('apiService', ['$http', function($http)
{
var api = "http://domain.xpto/api/";
var self = this;
this.result = {};
this.getSection = function(id){
var url = api + "section/" + id;
$http.get(url).then(function(res){
self.result = res;
});
}
}]);
I wouldn't use a Promise for this case. You can access the Service's var into your Controller and View.
Your controller:
myApp.controller('mainController', ['$scope', '$routeParams', 'apiService',
function($scope, $routeParams, apiService)
{
$scope.apiSer = apiService;
$scope.apiSer.getSection(1);
}]);
In your View:
<pre>{{ apiSer.result }}</pre>
And now you'll see your parameter get updated in real time.
In your getSection function just write and return the following
return $http.get(url);
You might need to use angular.forEach method to parse your inner values of the JSON . Take a look at this example Accesing nested JSON with AngularJS
I use an http get request in angular for extract data in a object with the users connected at the moment in my app.
But that info need to be refreshed every time for bind to the scope.
So I made this for refresh every 3 seconds the data of the array in get request ->
index.jade
a(ng-repeat="item in room.connected")
img(src="/images/{{item.avatar}}")
controller.js
ngApp.controller('controller', function(){
var vm = this; vm.connected;
$interval(function(){
//The Get request returns an array like->[{"username":"cesarodriguez4","avatar":"icon-user-man-1.png"}]
$http.get('http://localhost:3000/get-classroom-viewers/user')
.then(function(response){
vm.connected = response.data;
},function(error){
console.log(error);
});
}, 3000);
//Every 3 seconds executes the GET request.
});
That works, but i think its not the correct,
because the terminal shows every time the get request and I think that's a bad practice
Does an method for refresh the info only when the server changes the data?
I try Using $scope.$watch but does not work.
You should use websockets, so that if anything changes in the server side you can push to sockets, from socket you can read and update the scope variable. Looping or making server request on every 3 sec is bad practice as it increases server load.
SockJS Angular Client
angular.module('myApp')
.service('PushNotificationService', ['$q', '$timeout', function($q, $timeout) {
var service = {}, listener = $q.defer(), socket = {
client: null,
stomp: null
};
service.RECONNECT_TIMEOUT = 30000;
service.SOCKET_URL = 'your socket Url'; // like '/chat'
service.CHAT_TOPIC = 'topic url'; // like '/getMessage/chat'
service.receive = function() {
return listener.promise;
};
var reconnect = function() {
$timeout(function() {
initialize();
}, this.RECONNECT_TIMEOUT);
};
var startListener = function() {
socket.stomp.subscribe(service.CHAT_TOPIC, function(data) {
var jsonObj = JSON.parse(data.body);
listener.notify(jsonObj);
});
};
var initialize = function() {
socket.client = new SockJS(service.SOCKET_URL);
socket.stomp = Stomp.over(socket.client);
socket.stomp.connect({}, startListener);
socket.stomp.onclose = reconnect;
};
initialize();
return service;
}]);
In your controller
angular.module('myApp').controller('myCtrl', function($scope, PushNotificationService) {
PushNotificationService.receive().then(null, null, function(message) {
//message contains data you pushed to socket from server
//assign data to $scope variable
$scope.data = message;
});
})
Include below scripts in your html
sockjs.js
stomp.js
More Info
Websocket using Spring AngularJS SockJS
I have a problem, I'm using a JSON coming from an external server, but when I do "Pull to refresh" or when I open the application, displays the same information I downloaded the first time the application is opened. It may be that the JSON is being stored in the cache and therefore not update? For if when I go to on-refresh = "doRefresh ()" and called another JSON, (the first time I do), update, but re-enter the application I load the information from the first JSON and if I want update, showing me the information I also downloaded the first time. This will fix manually deleting the application data, but it is not the best way ...
This is my services.js
angular.module('starter.services', ['ngResource'])
.factory('NotasService', ['$http',
function ($http) {
var items_nota = [];
var items_nota_array;
return {
all: function () {
return $http.get('http://192.168.1.0:8100/wp-json/posts?filter[post_status]=publish&filter[posts_per_page]=30')
.success(function(data, status, headers, config){
console.log("**** SUCCESS ****");
console.log(status);
})
.error(function(data, status, headers, config){
console.log("**** ERROR ****");
console.log(status);
})
.then(function(response){
console.log("**** THEN ****");
items_nota = response;
return items_nota;
}
)
},
get: function (notaId) {
// Simple index lookup
var pepe = parseInt(notaId);
var ESTO = 0;
var addToArray = true;
for (var i = 0; i < items_nota.length; i++) {
if (items_nota[i].id == pepe) {
addToArray = false;
ESTO = i;
}
}
return items_nota[ESTO];
}
}
}])
This is my controller.js..
.controller('ActulidadCtrl', function ($q, $scope, NotasService, $timeout) {
var items_nota;
NotasService.all().then(function (data) {
$scope.items_nota = data;
})
//Pull tu refresh
$scope.doRefresh = function () {
console.log('Actualizando!');
$timeout(function () {
//NotasService.loadData().then(function (data) {
NotasService.all().then(function (data) {
$scope.items_nota = data;
})
//Stop the ion-refresher from spinning
$scope.$broadcast('scroll.refreshComplete');
});
};
})
Thanks! And Happy New Year!
UPDATE: solved the problem was in the server side cache
I think your problem is with GET query:
http://192.168.1.0:8100/wp-json/posts?filter[post_status]=publish&filter[posts_per_page]=30
Please check if this query is returning same posts event if you add new data.You can make sample http query using tools like Postman.
post_status and posts_per_page are constant.
Please check. Good luck!!