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

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.)

Related

AngularJS Amplitude Service Not Acting as Singleton

I have recently posted a similar question, but this is not a duplicate.
Apologies for the code heavy post but I wanted to provide as much context as possible. I am having an issue with defining the analytics tool, 'Amplitude' as a service in my Angular.js application. Services are supposed to act as singletons throughout an application (source), so I am confused to be getting the following behavior.
In my app.js file, I call AmplitudeService.logEvent('EVENT_NAME') in a .run function which successfully logs the event to Amplitude. Note: Console.log(AmplitudeService) returns an object with all the correct functions here.
However, when I call AmplitudeService.logEvent('EVENT_NAME') within any other controller, such as header.js I do not ever see any data in my Amplitude dashboard. Note: Console.log(AmplitudeService) returns an identical object within header.js to the one returned from app.js
Would appreciate any and all insight!
P.S. The official AmplitudeJS SDK is here. I am trying to implement it through this wrapper.
AmplitudeService.js (source)
Note: If you check the author's syntax, he returns an object at the end of his service. In my research, I've read to use the "this" keyword when defining Service functions (source), and that you don't need to return an object as you would with a Factory, so I have updated it accordingly.
angular.module('AmplitudeService', [])
.service('AmplitudeService',
['$amplitude', '$rootScope', 'amplitudeApiKey', '$location',
function ($amplitude, $rootScope, amplitudeApiKey, $location) {
this.init = function() {
$amplitude.init(amplitudeApiKey, null);
}
this.identifyUser = function(userId, userProperties) {
$amplitude.setUserId(userId);
$amplitude.setUserProperties(userProperties);
}
this.logEvent = function(eventName, params) {
$amplitude.logEvent(eventName, params);
}
}]);
angular-amplitude.js (source)
This allows access to "$amplitude" throughout the application
(function(){
var module = angular.module('angular-amplitude', ['ng']);
module.provider('$amplitude', [function $amplitudeProvider() {
this.$get = ['$window', function($window) {
(function(e,t){
var r = e.amplitude || {};
var n = t.createElement("script");
n.type = "text/javascript";
n.async = true;
n.src = "https://d24n15hnbwhuhn.buttfront.net/libs/amplitude-2.2.0-min.gz.js";
var s = t.getElementsByTagName("script")[0];
s.parentNode.insertBefore(n,s);
r._q = [];
function a(e){
r[e] = function(){
r._q.push([e].concat(Array.prototype.slice.call(arguments,0)));
}
}
var i = ["init","logEvent","logRevenue","setUserId","setUserProperties","setOptOut","setVersionName","setDomain","setDeviceId","setGlobalUserProperties"];
for(var o = 0; o < i.length; o++){
a(i[o])
}
e.amplitude = r
}
)(window,document);
return $window.amplitude;
}];
}]);
return module;
}());
App.js
angular.module('app', [
'ngRoute',
'angular-amplitude',
'AmplitudeService',
])
.run(['AmplitudeService', function(AmplitudeService){
console.log(AmplitudeService); // Outputs 'Object {}'
AmplitudeService.init();
*AmplitudeService.logEvent('LAUNCHED_SITE'); // This logs the event*
console.log(AmplitudeService); // Outputs 'Object {}'
}])
Header.js
angular.module('app.common.header', [])
.controller('HeaderCtrl', [ '$rootScope', '$scope', '$location','$route', '$window', 'AmplitudeService', function($rootScope, $scope, $location, $route, $window, AmplitudeService){
$scope.goToSearch = function(term) {
$location.path('/search/' + term);
console.log(AmplitudeService); // Outputs 'Object {}'
*AmplitudeService.logEvent('SEARCHED');* // This does not log the event
};
}]);
Update: I have tried switching the Service to a Factory and that did not generate any new results.
Found the solution and hope this is helpful to anyone that comes across this. My solution was to initialize the SDK by calling AmplitudeService.init() within a .run() function within app.js, which initialized an amplitude object within my window. From there forward, I included $window as a service in each of my controllers and called $window.amplitude.logEvent('event_name_here');
Feel free to contact if you have questions. Thanks.
We had similar issues on a large project and we created a wrapper providing a directive to init Amplitude and a service to provide the logEvent and sendUserId.

Issues injecting Angular factories and services

I don't know what it is about injecting factories, but I am having the most difficult time.
I've simulated what I'm attempting to do via this sample plunk http://plnkr.co/edit/I6MJRx?p=preview, which creates a kendo treelist - it works fine.
I have an onChange event in script.js which just writes to the console. That's also working.
My plunk loads the following:
1) Inits the app module, and creates the main controller myCtrl (script.js)
2) Injects widgetLinkingFactory int myCtrl
3) Injects MyService into widgetLinkingFactory
The order in which I load the files in index.html appears to be VERY important.
Again, the above plunk is NOT the real application. It demonstrates how I'm injecting factories and services.
My actual code is giving me grief. I'm having much trouble inject factories/services into other factories.
For example,
when debugging inside function linking() below, I can see neither 'CalculatorService' nor 'MyService' services. However, I can see the 'reportsContext' service.
(function () {
// ******************************
// Factory: 'widgetLinkingFactory'
// ******************************
'use strict';
app.factory('widgetLinkingFactory', ['reportsContext', 'MyService', linking]);
function linking(reportsContext, MyService) {
var service = {
linkCharts: linkCharts
};
return service;
function linkCharts(parId, widgets, parentWidgetData) {
// *** WHEN DEBUGGING HERE, ***
// I CANNOT SEE 'CalculatorService' AND 'MyService'
// HOWEVER I CAN SEE 'reportsContext'
if (parentWidgetData.parentObj === undefined) {
// user clicked on root node of grid/treelist
}
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
// REFRESH HERE...
}
});
}
}
})();
A snippet of reportsContext'service :
(function () {
'use strict';
var app = angular.module('rage');
app.service('reportsContext', ['$http', reportsContext]);
function reportsContext($http) {
this.encodeRageURL = function (sourceURL) {
var encodedURL = sourceURL.replace(/ /g, "%20");
encodedURL = encodedURL.replace(/</g, "%3C");
encodedURL = encodedURL.replace(/>/g, "%3E");
return encodedURL;
}
// SAVE CHART DATA TO LOCAL CACHE
this.saveChartCategoryAxisToLocalStorage = function (data) {
window.localStorage.setItem("chartCategoryAxis", JSON.stringify(data));
}
}
})();
One other point is that in my main directive code, I can a $broadcast event which calls the WidgetLinking factory :
Notice how I'm passing in the widgetLinkingFactory in scope.$on. Is this a problem ?
// Called from my DataModel factory :
$rootScope.$broadcast('refreshLinkedWidgets', id, widgetLinkingFactory, dataModelOptions);
// Watcher setup in my directive code :
scope.$on('refreshLinkedWidgets', function (event, parentWidgetId, widgetLinkingFactory, dataModelOptions) {
widgetLinkingFactory.linkCharts(parentWidgetId, scope.widgets, dataModelOptions);
});
I am wasting a lot of time with these injections, and it's driving me crazy.
Thanks ahead of time for your assistance.
regards,
Bob
I think you might want to read up on factories/services, but the following will work:
var app = angular.module('rage')
app.factory('hi', [function(){
var service = {};
service.sayHi = function(){return 'hi'}
return service;
}];
app.factory('bye', [function(){
var service = {};
service.sayBye = function(){return 'bye'}
return service;
}];
app.factory('combine', ['hi', 'bye', function(hi, bye){
var service = {};
service.sayHi = hi.sayHi;
service.sayBye = bye.sayBye;
return service;
}];
And in controller...
app.controller('test', ['combine', function(combine){
console.log(combine.sayHi());
console.log(combine.sayBye());
}];
So it would be most helpful if you created a plunk or something where we could fork your code and test a fix. Looking over your services it doen't seem that they are returning anything. I typically set up all of my services using the "factory" method as shown below
var app = angular.module('Bret.ApiM', ['ngRoute', 'angularFileUpload']);
app.factory('Bret.Api', ['$http', function ($http: ng.IHttpService) {
var adminService = new Bret.Api($http);
return adminService;
}]);
As you can see I give it a name and define what services it needs and then I create an object that is my service and return it to be consumed by something else. The above syntax is TypeScript which plays very nice with Angular as that is what the Angular team uses.

How would one run two controllers at the same time AngularJS

I'm making a webapp in AngularJS (using Yeoman), and I have a loop to add 1 to a counter every second. This worked fine, until I needed multiple tabs with multiple controllers. I tried running a loop in the main controller, but this didn't work.
I want the gameLoop function in MoneyCtrl to run at all times, is there a better place to put this function?
Does anyone have an idea of how I could do this, or at least achieve the same effect?
Github project
You can put the gameLoop function on the run block.
angular.module('incrementalApp', ['ngAnimate', 'ngCookies', 'ngResource',
'ngRoute', 'ngSanitize', 'ngTouch'
]).config(function($routeProvider) {
//...
}).run(function($rootScope, MoneyService, Vars){
var stop;
$rootScope.loop = function() {
if (angular.isDefined(stop) ) {
return;
}
stop = $interval(function() {
angular.forEach(Vars.clickers, function(clicker){
MoneyService.addMoney((clicker.amount * clicker.production)/Vars.fps);
});
}, 1000/Vars.fps);
$rootScope.stopLoop = function() {
if (angular.isDefined(stop)) {
$interval.cancel(stop);
stop = undefined;
}
};
$rootScope.$on('$destroy', function() {
// Make sure that the interval is destroyed too
$scope.stopFight();
});
};
$scope.loop();
})
And use a service to add the money so you can require the service on each controller.

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

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

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);

Resources