I'm trying to make it so that I can just add "requestCounter" to any controller and get a value that is constantly updated with the number of requests. The interceptor code is working, however the value provided by injecting requestCounter is always {count: 0}. What am I not understanding!
angular.module('theApp')
.provider('requestCounter', function ($httpProvider) {
this.$get = function () {
var activeRequests = 0;
var obj = {count: activeRequests};
$httpProvider.defaults.transformRequest.push(function(data) {
activeRequests++;
return data;
});
$httpProvider.defaults.transformResponse.push(function(data) {
activeRequests--;
return data;
});
return obj;
};
});
the controller
angular.module('theApp')
.controller('PurchaseCtrl', function ($scope, requestCounter) {
$scope.requests = requestCounter;
});
the markup
<h1>There are {{requests.count}} requests loading</h1>
In the beginning you are assigning a primitive value of activeRequests = 0 to your obj, so they are not linked to each other. You can try with:
var activeRequests = {number: 0};
var obj = {count: activeRequests};
Then you can have your counted number in obj.count.number
Related
I'm using a service in order to pass data between different instances of an AngularJS controller. I know that this is not the best way to do it but it's the way that fits my case. The problem is that I cannot get data out of that Service.
var app = angular.module('MovieApp', ['ngResource']);
app.factory('factMovies', function($resource) { //this returns some movies from MongoDB
return $resource('/movies');
});
app.service('SnapshotService', function(factMovies) {
//this is used to pass data to different instances of the same controller
//omitted getters/setters
this.snapshots = [];
this.init = function() {
var ctrl = this;
var resp = factMovies.query({}, function() {
if (resp.error) {
console.log(resp.error)
} else {
tempDataset = []
//do stuff and put the results in tempDataset
ctrl.snapshots.push(tempDataset);
console.log(tempDataset); //prints fine
return tempDataset;
}
});
};
});
app.controller('TileController', function(SnapshotService) {
this.dataset = [];
this.filters = [];
this.init = function() {
var ctrl = this;
var data = SnapshotService.init(function() {
console.log(ctrl.data); //doesn't even get to the callback function
});
};
});
I really can't figure out what I'm doing wrong..
SnapshotService.init() doesn't take any parameters - meaning the anonymous function you pass in with the SnapshotService.init() call in TileController does nothing.
What you need to do is add the parameter to the init function definition and then call it in the code:
app.service('SnapshotService', function(factMovies) {
//this is used to pass data to different instances of the same controller
//omitted getters/setters
this.snapshots = [];
this.init = function(cb) {
var ctrl = this;
var resp = factMovies.query({}, function() {
if (resp.error) {
console.log(resp.error)
} else {
tempDataset = []
//do stuff and put the results in tempDataset
ctrl.snapshots.push(tempDataset);
console.log(tempDataset); //prints fine
cb(ctrl.snapshots);
}
});
};
});
I'm trying to update a global angularjs module.value in one controller with an array, and then retrieving that global array through in a service. But the array doesn't exist.
app.js
app.factory('featureClaims', function($q) {
var featureClaims = {};
featureClaims.init = function() {
featureClaims.claims = [];
}
featureClaims.get = function() {
return $q.when(featureClaims.claims);
}
featureClaims.set = function(data) {
featureClaims.claims = data;
return $q.when(featureClaims.claims); // I'm using the $q library to return a promise.
}
return featureClaims;
});
loginController
let loginController = function($scope, loginService, toastrObj, featureClaims) {
$scope.login = function(){
featureClaims.init();
featureClaims.set(result.data.FeatureClaims); // updating ok here
}
}
app.controller("loginController", ["$scope", 'loginService', 'toastrObj', 'featureClaims',loginController]);
home service
let homeService= function(featureClaims) { // featureClaims.claims is null
return{
validateUser: function(expectedClaim) {
if(expectedClaim !== ""){
featureClaims.get().then(function(data){
return data.includes(expectedClaim); // data is return as undefined
})
}
return false;
}
}
};
app.factory('homeService',['featureClaims', homeService]);
I don't think you can use a value service this way. From this post the author states: "Note: Make sure that you never overwrite the value service/object as a whole otherwise your assignment is lost. Always reassign the property values of the value object. The following assignment is wrong and does not lead to the expected behavior"
Instead why don't you convert your value to a factory like so:
app.factory('featureClaims', function($q) {
var featureClaims = {};
featureClaims.init = function() {
featureClaims.claims = [];
}
featureClaims.get = function() {
return $q.when(featureClaims.claims);
}
featureClaims.set = function(data) {
featureClaims.claims = data;
return $q.when(featureClaims.claims); // I'm using the $q library to return a promise.
}
return featureClaims;
});
In your controller:
featureClaims.init();
// you need to wait for the promise to resolve with 'then'
featureClaims.set(['foo', 'bar']).then(function(response) {
console.log(response); // logs ["foo", "bar"]
});
featureClaims.get().then(function(response) {
console.log(response); // logs ["foo", "bar"]
});
Tested and working. You will want to create a get method that simply returns the data instead of setting it first.
I am trying to pass a JSON string value that is stored in one controller to another. I am using a custom service to pass the data, but it doesn't seem to be passing the value.
The First controller where the JSON string value is stored:
filmApp.controller('SearchController',['$scope', '$http','$log','sharedService',function($scope,$http,$log,sharedService){
$scope.results = {
values: []
};
var vm = this;
vm.querySearch = querySearch;
vm.searchTextChange = searchTextChange;
vm.selectedItemChange = selectedItemChange;
function querySearch(query) {
return $http.get('https://api.themoviedb.org/3/search/movie?include_adult=false&page=1&primary_release_year=2017', {
params: {
'query': query,
'api_key': apiKey
}
}).then(function(response) {
var data = response.data.results.filter(function(obj) {
return obj.original_title.toLowerCase().indexOf(query) != -1;
})
return data;
for (var i = 0; i < data.results.length; i++) {
$scope.results.values.push({title: data.results[i].original_title});
// $log.info($scope.results.values);
}
return $scope.results.values;
})
};
function searchTextChange(text) {
// $log.info('Search Text changed to ' + text);
}
function selectedItemChange(item) {
$scope.value = JSON.stringify(item);
return sharedService.data($scope.value);
}
}]);
The custom Angular service - The value is received here:
filmApp.service('sharedService',function($log){
vm = this;
var value = [];
vm.data = function(value){
$log.info("getValue: " + value); // received value in log
return value;
}
});
The Second controller that wants to receive the JSON value from the First controller:
filmApp.controller('singleFilmController',['$scope', '$http','$log','sharedService',function($scope,$http,$log,sharedService){
var value = sharedService.data(value);
$log.info("Data: " + value);
}]);
The value is received in the service but the second controller can't seem to access it. Not sure why it is happening as I'm returning the value from the data() method from the service. Also, the selectedItemChange method is used by the md-autocomplete directive.
A good approach would be using a Factory/Service. take a look at this: Share data between AngularJS controllers
Technically, you can resolve this by simply changing your service definition to
(function () {
'use strict';
SharedService.$inject = ['$log'];
function SharedService($log) {
var service = this;
var value = [];
service.data = function (value) {
$log.info("getValue: " + value); // received value in log
service.value = value;
return service.value;
};
});
filmApp.service('SharedService', SharedService);
}());
But it is a very poor practice to inject $http directly into your controllers. Instead, you should have a search service that performs the queries and handle the caching of results in that service.
Here is what that would like
(function () {
'use strict';
search.$inject = ['$q', '$http'];
function search($q, $http) {
var cachedSearches = {};
var lastSearch;
return {
getLastSearch: function() {
return lastSearch;
},
get: function (query) {
var normalizedQuery = query && query.toLowerCase();
if (cachedSearches[normalizedQuery]) {
lastSearch = cachedSearches[normalizedQuery];
return $q.when(lastSearch);
}
return $http.get('https://api.themoviedb.org/3/search/movie?' +
'include_adult=false&page=1&primary_release_year=2017', {
params: {
query: query,
api_key: apiKey
}
}).then(function (response) {
var results = response.data.results.filter(function (result) {
return result.original_title.toLowerCase().indexOf(normalizedQuery) !== -1;
}).map(function (result) {
return result.original_title;
});
cachedSearches[normalizedQuery] = results;
lastSearch = results;
return results;
}
});
}
}
filmApp.factory('search', search);
SomeController.$inject = ['$scope', 'search'];
function SomeController($scope, search) {
$scope.results = [];
$scope.selectedItemChange = function (item) {
$scope.value = JSON.stringify(item);
return search.get($scope.value).then(function (results) {
$scope.results = results;
});
}
}
filmApp.controller('SomeController', SomeController);
}());
It is worth noting that a fully fledged solution would likely work a little differently. Namely it would likely incorporate ui-router making use of resolves to load the details based on the selected list item or, it could equally well be a hierarchy of element directives employing databinding to share a common object (nothing wrong with leveraging two-way-binding here).
It is also worth noting that if I were using a transpiler, such as TypeScript or Babel, the example code above would be much more succinct and readable.
I'm pretty new to AngularJS but I'm pretty sure all you are doing is two distinct function calls. The first controller passes in the proper value, the second one then overwrites that with either null or undefined
I usually use events that I manually fire and catch on my controllers. To fire to sibling controllers, use $rootScope.$emit()
In the other controller then, you would catch this event using a $rootscope.$on() call
This article helped me a decent amount when I was working on this in a project.
app.controller('ItemDetailsCtrl', function($scope,FavoriteService) {
var parameter = $scope.Diamoni.Favorites;
});
app.service("FavoriteService",[function(){
this.fav = 0;
}]);
I would like to pass the variable parameter from ItemDetailsCtrl controller to FavoriteService, So this.fav=0; become this.fav=parameter Any suggestions? Thanks in advance.
Dont use $rootScope, instead use a function to set the params
In your service
var self = this;
this.setParam = function(param){
self.fav = param
}
In your controller
FavouriteService.setParam(parameter)
I think the cleanest way will be to expose your fav variable through get/set methods.
app.controller('ItemDetailsCtrl', function($scope, FavoriteService) {
var parameter = $scope.Diamoni.Favorites;
FavoriteService.setFav(parameter);
console.log(FavoriteService.getFav()); // will be the proper value
});
app.service("FavoriteService",[function(){
var fav = 0;
this.setFav = setFav;
this.getFav = getFav;
function setFav(favValue) {
fav = favValue;
}
function getFav() {
return fav;
}
}]);
try this out:
app.controller('ItemDetailsCtrl', function($scope,FavoriteService) {
var parameter = $scope.Diamoni.Favorites;
FavoriteService.setParam(parameter);
});
app.service("FavoriteService",[function(){
var service = this;
service.setParam = function(parameter) {
service.fav = parameter;
};
}]);
I added a method to the service to set the fav variable.
its easy to implement this kind of logic using factory instead of service. if you want i can send you the factory code snippet
EDIT
using factory:
app.controller('ItemDetailsCtrl', function($scope,FavoriteService) {
var parameter = $scope.Diamoni.Favorites;
FavoriteService.setParam(parameter);
});
app.factory('FavoriteService', ['', function(){
var service = {}
service.setParam = function(parameter) {
service.fav = parameter;
};
return service;
}])
}]);
Here's a neat data sharing service example, where we store different data using set and get methods. Remember to store the values in an object or you can get some strange results sometimes.
Service:
graphs.service('graphsData', [function() {
var graphs = this;
var data = {
all: null,
list: null,
single: null
};
graphs.set = function(k, v) {
data[k] = v;
};
graphs.update = function(k, s, v) {
data[k][s] = v;
};
graphs.get = function(k, v) {
return data;
};
}]);
From your controller:
// Stores the this.fav variable as myFavoriteValue (data.myFavoriteValue)
graphsData.set('myFavoriteValue', this.fav);
To get the value simply call the get function of the service:
graphsData.get().myFavoriteValue;
Simply put, i have a Poller that returns msgdata and newdata variables based on conditions however the returned value in this case is always undefined. The Conditions should be overriding the initial variable initialising correct inside the service?
How can i get the Poller.msgdata and Poller.newdata to Return the TRUE or FALSE to the controller?
Controller:
app.controller('sidemenuController', ['$scope', 'projectsModal', 'sendMessageModal', 'Poller', '$timeout',
function($scope, projectsModal, sendMessageModal, Poller, $timeout) {
var update = function() {
$timeout(update, 5000);
$scope.inbox = Poller.msgdata;
$scope.project = Poller.newdata;
console.log("Updated SideMenu Controller: " + Poller.msgdata);
}
update();
$scope.projects = Poller.projects;
$scope.messages = Poller.messages;
$scope.sendMessage = sendMessageModal.activate;
$scope.showModal = function() {
projectsModal.deactivate();
projectsModal.activate();
};
$scope.toggle = function(){
$scope.checked = !$scope.checked
projectsModal.deactivate();
sendMessageModal.deactivate();
}
}]);
Service:
app.factory('Poller', Poller);
Poller.$inject = ['$http', '$timeout'];
function Poller($http, $timeout) {
var projectcache = { response: [], calls: 0 };
var msgcache = { response: [], calls: 0 };
var newdata;
var msgdata;
var poller = function () {
$timeout(poller, 5000);
$http.get('http://localhost/app/controllers/php/getProjects.php')
.then(function(r) {
if (r.data.projects.length > projectcache.response.length) {
newdata = true;
angular.copy(r.data.projects, projectcache.response);
} else {
newdata = false;
};
console.log(msgdata);
});
$http.get('http://localhost/app/controllers/php/getMessages.php')
.then(function(m) {
if (m.data.messages.length > msgcache.response.length) {
msgdata = true;
angular.copy(m.data.messages, msgcache.response);
} else {
msgdata = false;
};
});
};
poller();
return {
projects: projectcache.response,
messages: msgcache.response,
newdata: newdata,
msgdata: msgdata
};
};
Your polling method reassigns the local variables newdata and msgdata, but it doesn't reassign the fields of the object returned by the service, which are initialized to undefined and never modified after.
You need to keep a reference to the returned object in a variable:
var service = { ... };
...
return service;
and in the polling method, change the values inside the service:
service.newdata = false;
When you do
return {
projects: projectcache.response,
messages: msgcache.response,
newdata: newdata,
msgdata: msgdata
};
The data you get from Poller.newdata should always be the initial value of var newdata, because javascript do not pass by reference.
projects and messages work because you are doing angular.copy, which keeps the same reference.
An easy way to fix this would be passing back an object instead of boolean itself
var checkNew = {};
in poller function
checkNew.newdata = true;
in return
checkNew: checkNew
in controller
$scope.inbox = Poller.checkNew.msgdata;
$scope.project = Poller.checkNew.newdata;
A cleaner way (imo) to do this would be exposing the poller function as a service function to the controller. By this way you don't need to have a timeout on the service, it gets data whenever the controller calls it.