Why doesn't a calculated amount update when the factory updates? - angularjs

I have a simple factory like this
angular.module('posBitcoinApp')
.factory('invoiceData', function ($http, $interval) {
var blockchainInfoExchangeRates = {};
var getLatestExchangeRates = function() {
$http.get('https://api.bitcoinaverage.com/ticker/global/IDR/')
.success(function(response) {
blockchainInfoExchangeRates.IDR = response.last;
});
};
$interval(getLatestExchangeRates, 60000);
getLatestExchangeRates();
return {
exchangeRates: blockchainInfoExchangeRates
};
});
Then in one of my controllers I have...
angular.module('posBitcoinApp')
.controller('InvoiceCtrl', function ($scope, $http, $interval, $location, invoiceData) {
$scope.invoiceData = invoiceData;
$scope.invoiceData.btcAmount = parseFloat($scope.invoiceData.idrAmount / $scope.invoiceData.exchangeRates.IDR).toFixed(8);
So every minute the exchange rates get updated. However, the calculated the BTC value ($scope.invoiceData.btcAmount) does not auto update. What am I missing? Something need to be watched? $scope.apply() somewhere?
Thanks.

Even though you refresh data on factory it would not reflect as you are returning the data. Instead of that You have to refresh scope.invoiceData.btcAmount for every one minute interval.
Var updateBTC = function(){
//call to factory if you want to avoid having an interval inside factory to update data and use the result in the below statement.
$scope.invoiceData.btcAmount = parseFloat($scope.invoiceData.idrAmount / $scope.invoiceData.exchangeRates.IDR).toFixed(8);
};
$interval(updateBTC, 60000);

Related

Why after adding $interval other call to funtions stop working?

I'm working on an app developed by other people, I don't have any documentation or any way to contact them, and I have this problem:
It's an angular application that need to be refreshed every minute, In other sections of the app, they are using $interval, but in this page if I try to use it, the calls to my WebAPI stop working and I recive this error:
WebApiFactory.getNoStatusOrders is not a function
I need your help to know why is this happening, here is my code:
angular.module('AssemblyLive').controller('overviewCarsWithoutStatus', [
'$scope', '$rootScope', '$location', 'WebApiFactory', "$interval", 'StatusPointMonitorFactory',
function ($scope, $rootScope, $location, $interval, WebApiFactory, StatusPointMonitorFactory) {
...
var areas = {
bodyShop1:"B000,B001,B020,B031,B200,B211,B220,B231,B300,B311,B320,B331,B370,B371,B375,B376,B380,B381,B383,B386,B390,B400,B401,B410,B420,B421,B425,B426,B430",
bodyShop2: "B431,B435,B436,B440,B451,B500,B521,B540,B551,B553,B600,B750,B760,B770,B781,B783,B790,B791,B800,B811,B813,B900",
paintShop1: "D000,D011,D012,D051,D100,D130,D131,D132,D151,D152,D230,D251,D252,D300,D351,D352,D360,D381,D390,D400,D451,D452,D470",
paintShop2: "D471,D472,D481,D482,D500,D501,D531,D532,D540,D561,D562,D600,D620,D650,D670,D691,D692,D700,D731,D741,D750,D800,D812,D821,D822,D841,D842",
assembly: "F000,F100,F150,F200,F250,F300,F350,F400,F450,F500,F550,F600,F650,F700,F750,F800,F850,F900"
};
...
//Start the creation of the overview.
function initializeOverview() {
$scope.counters = [];
//Iterates over the configuration.
//Get all the status to call the query.
var status = $scope.headers.map(function(a) {return a.status.toString();});
//Call to create the knrs b y area.
getKNRWithoutStatus(status.toString());
for(var status in areas){
getCarsWithNoStatus(areas[status]);
}
getNoStatusCounters("B000,C000,D000,E000,E500,F000,F100,F950,G000,G900");
}
// Funtion to set the counters in the table headers
function getNoStatusCounters(status) {
WebApiFactory.getNoStatusOrdersCounter(status).then(function (resultData) {
Object.getOwnPropertyNames(resultData.NoStatusOrders).forEach(function(name) {
...
function getCarsWithNoStatus(status) {
// Fetch all the counters from the WebAPI
WebApiFactory.getNoStatusOrdersCounter(status).then(function (resultData) {
...
function getKNRWithoutStatus(status) {
var orders = [];
//Query the status monitor.
WebApiFactory.getNoStatusOrders(status).then(function(statusMonData) {
...
/** To refresh data when the clock in the footer refresh. */
$rootScope.$on('carsWithoutStatusOverview', function(){
initializeOverview();
$interval(initializeOverview, Config.dataRefreshInterval * 1000)
});
Note: My page works perfectly without adding $interval
Review your dependency injection. You put WebApiFactory and $interval in different positions in the $inject list and in the parameters. (So the $interval variable points to your WebApiFactory service and vice versa.)

Firebase loading $scope view enter doesn't load

I have a loading problem in Firebase. I want to display a list of images when I open the view but nothing happens till i go back ( there is a flash and i can see my photo list). It's working but not displaying in the opening.
What am i missing please ?
There is the beginning of my Controller view:
'Use Strict';
angular.module('App').controller('valider_photosController', function($scope, $state, $localStorage, Popup, Firebase, $firebaseObject, $ionicHistory, $ionicPopup, $ionicModal, $cordovaCamera) {
$scope.imagestab = [];
var ref_logements = firebase.database().ref('logements');
var ref_images = firebase.database().ref('images');
ref_logements.child(id_logement).child('images').on('child_added', added);
function added(idxSnap, prevId){
ref_images.child(idxSnap.key).once('value', function(datasnap){
var bidule = datasnap.val();
bidule['key'] = datasnap.key;
$scope.imagestab.push(bidule);
console.log('La valeur'+datasnap.key+'donne '+datasnap.val());
});
};
});
Since firebase works with asynchronous calls, by the time firebase responds with your data the angular cycle had already finished and you won't have your scope updated. You can force it by using $scope.$apply();.
ref_images.child(idxSnap.key).once('value', function(datasnap){
var bidule = datasnap.val();
bidule['key'] = datasnap.key;
$scope.imagestab.push(bidule);
$scope.$apply();
});
There is a tool that integrates angular and firebase in a way that you won't have to be concerned with things such as applying the scope. Its called angularfire. I totally recommend you to start using it in your application.
With angularfire you can get your data simply using
$scope.bidule = $firebaseObject(ref_images.child(idxSnap.key));
or
$scope.images = $firebaseArray(firebase.database().ref('images'));
I created a Factory
.factory('Firebase', function ($firebaseArray, $firebaseObject) {
var ref = firebase.database().ref();
return {
all: function (section) {
var data = $firebaseArray(ref.child(section));
return data;
},
getById: function (section, id) {
var data = $firebaseObject(ref.child(section).child(id));
return data;
},
get: function (section, field, value) {
var data = $firebaseArray(ref.child(section).orderByChild(field).equalTo(value));
return data;
}
};
})
And then in my controller, i replaced like you said :
var ref_logements = firebase.database().ref('logements');
var ref_images = firebase.database().ref('images');
ref_logements.child(index2).child('images').on('child_added', added);
function added(idxSnap, prevId) {
var monimage = Firebase.getById('images', idxSnap.key);
$scope.imagestab.push(monimage);
};
And it Works like a charm ! Thank you again :)

Proper way to structure my controller, service, and factory in angularjs application...service or factory?

I have been working with wrapping my head around the "angularjs" way of thinking (Angular 1) and I have a relatively ok grasp as I work my way through a small personal project. I am at a bit of a roadblock, not because I cannot get it to work, but I would like to know what the proper way to set up the data in my application.
The basic situation is this:
I have 3 json files:
categories.json
products.json
vendors.json
These hold the data (which I will fetch from a database later but am simplifying for now).
I basically need to load the data from all three of these files so that I can form a variable holding all "Products" (which is a JS class I declared separately).
I started off by storing the data inside one controller (relevant code below):
myApp.controller('productListController', ['$scope', '$http', '$q', function ($scope, $http, $q) {
var promises = [];
promises.push(getCategories($http));
promises.push(getVendors($http));
promises.push(getProducts($http));
$q.all(promises).then(function (response) {
//categories = response[0];
//vendors = response[1];
//products = response[2];
$scope.products = createProductList(response);
$scope.vendors = response[1].data;
$scope.vendorChecked = getCheckedVendors($scope.vendors);
})
This worked fine but I realized that I need this data in other views, which led me to try to move this code into a service.
The problem I had when doing this is that I do not know of a way for the controller to know that the service is done fetching the data so that I can then save it in the ProductListController $scope.
I would need to have a way to for example:
myApp.service('ProductService', ['$http', '$q', function ($http, $q) {
self = this;
var promises = [];
promises.push(getCategories($http));
promises.push(getVendors($http));
promises.push(getProducts($http));
$q.all(promises).then(function (response) {
//These three I would like to update in ProductListController
//when it is done.
self.products = createProductList(response);
self.vendors = response[1].data;
self.vendorChecked = getCheckedVendors(self.vendors);
})
Is this the correct approach to take? If so, how can I let the controller know that the service is done fetching the data and save for example:
$scope.products = ProductService.products;
$scope.vendors = ProductService.vendors;
$scope.categories = ProductService.categories;
Is this even the correct approach? Another approach I thought of was to use a factory instead of a service. Then I had another problem because I had for example:
return {
getProducts: function() {
//http get request code in here
return promise
},
getVendors: function() {
//http get request code in here
return promise
},
getCategories: function() {
//http get request code in here
return promise
},
getAllData: function () {
//in here I want to use the three promises in the 3 functions above
//but I am not able to call them from here. If I was able to do that
//then I could call this method from ProductListController and get the
//data that way.
}
I am sorry if this is long but I wanted to describe the different things I tried. I know I can make it work but I want to learn the right way, or a couple of right ways.
It is better to always return promise:
var promises = [];
promises.push(getCategories($http));
promises.push(getVendors($http));
promises.push(getProducts($http));
return $q.all(promises)
If you also not satisfied that in each controller you should call createProductList,getCheckedVendors - consider putting this tranforms to $http transformResponce https://docs.angularjs.org/api/ng/service/$http.
Or you can create your own promise. (Using $q.defer https://docs.angularjs.org/api/ng/service/$q).
Using servie or factory actually doesnt matter. This is factory:
var factory = {};
factory.getProducts: function() {
return promise
}
factory.getCategories: function() {
return promise
}
factory.getVendors: function() {
return promise
}
factory.getAllData: function () {
var promises = [];
promises.push(factory.getProducts());
promises.push(factory.getCategories());
promises.push(factory.getVendors());
return $q.all(promises)
}
return factory;
And in controler you just have:
MyFactory.getAllData().then(...)

Angular service, how to have simultaneous calls wait

I have two controllers that want the same data around the same time, but I don't want the data binded.
So I have a service to go get user data that has this method:
var getUserData: function() {
if (!angular.isDefined(this.userData)) {
return new RESTUtil.getData('userData').then(function(data) {
this.userData = data;
return this.userData
})
} else {
return this.userData
}
}
Then I have two controllers that pull in the data for different purposes:
controller('ControllerA', ['$scope', '$rootScope', 'DataService'], function($scope, $rootScope, DataService) {
var ctrlA = this;
DataService.getUserData().then(function(data) {
ctrlA.userData = data;
});
});
controller('ControllerB', ['$scope', '$rootScope', 'DataService'], function($scope, $rootScope, DataService) {
var ctrlB = this;
DataService.getUserData().then(function(data) {
ctrlB.userData = data;
});
});
So the problem with what I currently have written is both ControllerA and ControllerB hit the getUserData service before the RESTUtil call returns, so i end up getting two data calls to the service.
I thought that i'd use a $scope.$on in Controller B to listen to a broadcast from ControllerA, but that binds the data.
Basically if ctrlA.userData = this and I change ctrlB.userData = that, i don't want the two userData objects to bind, they should be instantiated.
Any suggestions on how I can either a.) write my service logic where any calls to getUserData while a REST Call is happening will wait and use the same data call, or B.) have a broadcast that doesn't bind?
I saw a similar question posted here: Have multiple calls wait on the same promise in Angular
But i'm not sure how to leverage the $http since my actual webservice call is abstracted inside the RESTUtil.getData();
You're almost there. But your service has a flaw. The first time it's called, it returns a promise. But the second time it's called (if the promise has been resolved), it doesn't return a promise anymore, but the resolved data instead.
The service should simply always return a promise, and it should initialize the promise the first time it's called:
var getUserData: function() {
if (!angular.isDefined(this.userData)) {
this.userData = RESTUtil.getData('userData');
}
return this.userData;
}
If you want to avoid each caller to receive the same object from the promise, then return a new promise each time, that is resolved with a copy of the original data:
var getUserData: function() {
if (!angular.isDefined(this.userData)) {
this.userData = RESTUtil.getData('userData');
}
return $q.when(this.userData).then(angular.copy);
}

How can I fetch a list over and over?

I want to have a list in sync, so I'm (right now) polling it every seconds. But I seem to have a problem - it does not work:
app.controller("MainController", function ($scope, $http, $timeout) {
$scope.responsePromise = $http.get("http://localhost:52219/API/GetList");
$scope.responsePromise.success(function (data, status, headers, config) {
$scope.model.list = JSON.parse(data);
$timeout(function ()
{
console.log("reload");
$scope.responsePromise = $http.get("http://localhost:52219/API/GetList");
}, 1000);
});
My goal is retrieving a list every X sec from the server that talks to the database. Anyone know why does does not spam "reload"? I only get it once
You are looking for $interval, and not $timeout.
from $interval docs:
Angular's wrapper for window.setInterval. The fn function is executed every delay milliseconds.
and also:
Note: Intervals created by this service must be explicitly destroyed when you are finished with them. In particular they are not automatically destroyed when a controller's scope or a directive's element are destroyed. You should take this into consideration and make sure to always cancel the interval at the appropriate moment.
As said by #Nitsan Baleli, you should use the service "$interval" and not "$timeout".
The question was asked here, please see the answer : Angular JS $timeout vs $interval
My goal is retrieving a list every X sec from the server that talks to the database.
I rewrote your code so that it matches your goal, it becomes:
app.controller("MainController", function ($scope, $http, $timeout) {
var $scope.model = {
list:[]
};
var getData = function(){
$http.get("http://localhost:52219/API/GetList").success(function(data){
$scope.model.list = JSON.parse(data);
});
};
getData(); // for the first call
$interval(function (){
getData();
}, 1000);
});
See the plunkr demo here: http://plnkr.co/edit/xCbGGyKPTeJtg7TeKKyE?p=preview

Resources