Angular $watch a service object from a controller and read properties - angularjs

I've been trying to watch a service object from a controller. I've been trying to solve this problem in a nice way but it has been imposible. the only solution I could find is this one (see the code). The thing is when I "console.log" the returned value, I can see the object but I can not access to the properties. it says "undefined". So the only solution I could find is this one but I don't like it too much. Any ideas???
This is my "watcher" of my controller:
$scope.$watchCollection(function(){return angular.toJson(measuresServ.getFinalMeasuresVal())},function(newVal, oldVal) {
$scope.measures = JSON.parse(newVal);
console.log($scope.measures);
console.log($scope.measures.temperatura);
});
This is the object of my service:
var finalMeasures = {};
return {
getMeasures : function(){
finalMeasures.temperatura = 24;
finalMeasures.humedad = 45;
},
getMeasuresVal: function(){
return finalMeasures;
}
}

I think it should work:
$scope.$watch(function () {
return measuresServ.getFinalMeasuresVal();
}, function (newVal, oldVal) {
console.log(newVal);
}, true);

Related

Auto trigger function throuigh service in angularjs

hi all i am using angulrajs passing one value from one controller to another controller using service it's work fine but my need is when service value change in controller 2 i get the service value in one scope when scope value change i need trigger the function it's called refresh function when service value change and that i need to call the refresh function here my fiddle
https://jsfiddle.net/ctawL4t3/10/
You can just $watch your value.storeObject. Though it's not best of the practices, but it suits this kind of feature.
$scope.$watch('value.storedObject', function(newVal) {
if(newVal !== '') {
refresh()
}
})
working fiddle (open console to see refresh function logging)
You can try to use angular default $emit, $broadcast, or try to do 2 simple functions in own service
angular.module('app').factory('StoreService', function() {
var listeners = {};
var emit = function(name, val) {
if(listeners[name]) {
listeners[name](val)
}
}
var on = function(name, callback) {
listeners[name] = callback;
}
return {
emit: emit,
on: on,
storedObject: ''
};
});
JSFiddle example
JSFiddle example $watch
JSFiddle example ng-change is better because, you can use easily debounce
you can use broadcast function for that
Please check this SO link to find the related answer
How to call a function from another controller in angularjs?
app.controller('One', ['$scope', '$rootScope'
function($scope) {
$rootScope.$on("CallParentMethod", function(){
$scope.parentmethod();
});
$scope.parentmethod = function() {
// task
}
}
]);
app.controller('two', ['$scope', '$rootScope'
function($scope) {
$scope.childmethod = function() {
$rootScope.$emit("CallParentMethod", {});
}
}
]);

problems with $watch function

I'm not really sure about this issue but it seems that sometimes when I activate $watch for a function then it doesn't work.
for example I have this simple service
angular.module('sp-app').factory('mediaSources', function() {
var storages = [];
return {
addStorage: function(storage) {
storages.push(storage);
},
getStorages: function() {
return storages;
}
}
});
and when I watch getStorage method in order to update my view it doesn't call change callback or calls only at initialization stage
$scope.$watch(function($scope) {
return mediaSources.getStorages();
}, function() {
console.log('call')
});
and I can only track changes by watching length property of returned array
return mediaSources.getStorages().length;
and I wonder because I have written similar think somewhere else within my application and it works fine.
If i interpret what you are trying to do, you should not need to set a watch on something like this, you can just use a factory like so :
angular.module('app').factory('mediaSources', function(){
var storages = {};
storages.list = [];
storages.add = function(message){
storages.list.push(message);
};
return storages;
});
then in the controller you want to receive/update the data to for instance, you would do
$scope.myControllerVar = mediaSources.list;
No need to watch over it, it should update for you.
You will have to set up watcher with equality flag as the third argument:
$scope.$watch(function($scope) {
return mediaSources.getStorages();
}, function() {
console.log('call');
}, true);

Possibility of sharing variable from directives to services in Angular

I am in situation where have to pass LntLng variables to a service where an $http.get request is made using those latitude and longitude variables as URL parameters.
I tried some ways by using localstorage, this localstorage methodology was useful to some extent but it can set variables only once and not updating to new values if user change his location to some other place.I need to update the variable with new vaule every time user change there address.
.factory('someFactory', function($http) {
return {
get: function(result) {
var latitude='value from directive variable';
var longitude='value from directive variable';
$http.get('http://www.someapi.com/?longitude=' + longitude + '&latitude='+ latitude + '&customer_number=00000')
.success(function(result) {
});
}
}
});
Directive:
popupPromise.then(function(el) {
var searchInputElement = angular.element(el.element.find('input'));
scope.selectPlace = function(place) {
ngModel.$setViewValue(place);
map.setCenter(place.geometry.location); // from here i will get new updated place object with variable i need..My problem is to access the 'place' object in service .
ngModel.$render();
console.log('rendering');
el.element.css('display', 'none');
$ionicBackdrop.release();
};
};
NOTE: I'm going to take value from directive only after the 'place' object is updated and will send that value to service after directive is fully loaded.
Any suggestions please.
You can achieve this easily via $watch or $observe (if place value is coming from the directive attributes) in the directive.
// Service
.factory('someFactory', function($http) {
return {
get: function(lat, lng) {
return $http.get('http://www.someapi.com/?longitude=' + lng + '&latitude='+ lat + '&customer_number=00000');
}
}
});
// Directive
directives.directive('someDirective', ['someFactory', function(someFactory) {
return {
link: function($scope, element, attr) {
function responseHandler() {
// Your code on response from the API
ngModel.$setViewValue(place);
map.setCenter(place.geometry.location); // from here i will get new updated place object with variable i need..My problem is to access the 'place' object in service .
ngModel.$render();
console.log('rendering');
el.element.css('display', 'none');
$ionicBackdrop.release();
}
// Look for the change in place entered by user
attr.$observe('place', function(newValue) {
if (newValue) {
someFactory.get(newValue.lat, newValue.lng).then(responseHandler);
}
});
// OR //
// Watch for any scope variable (if you have place object as stored in Scope)
$scope.$watch('place', function(newValue) {
if (newValue) {
someFactory.get(newValue.lat, newValue.lng).then(responseHandler);
}
});
},
};
}]);

how to update all the variable changes in the service to the $scope.var in controller

I'm trying to update a variable in my controller every time a variable is updated in my service. I'm using the $scope.$watch(), but unfortunately only the last change is being effected. Here is the code that I used. Does anyone know what is wrong with this?
Service:
rApp.factory('pService', ['$http', '$rootScope', '$sanitize',
function ($http, $rootScope, $sanitize) {
var pService = {};
//Some other code
pService.Update=function(status)
{
if(status.LastItemId!=undefined)
{
pService.disItemId = status.LastItemId;
}
}
//Some other code
return pService;
});
Controller:
rApp.controller('dController', ['$scope','$rootScope' 'pService' ,dispenseController]);
function dController($scope,$rootScope, pService) {
$scope.$watch(function () { return pService.disItemId }, function (newVal, oldVal) {
if (newVal != oldVal) {
$scope.lastItemId = pService.disItemId;
}
})
});
In your specific case :
You don't need to use $watch. Actually you don't have any use of $watch in standard angular application.
Just do this in your controller :
$scope.lastItem = pService;
And then use the var like this :
$scope.lastItem.disItemId;
This will always point to the updated disItemId.
Problem
If you bind your var like this :
Service
[...]
service.serviceVar = 1;
return service
[...]
This will create a "1" var with a reference.
Controller
[...]
$scope.myvar = Service.serviceVar;
[...]
This will bind $scope.myvar to the "1" reference.
If you do this in your service or in an other controller :
service.serviceVar = 2;
You will create a new var "2" with a new reference and you will assign this reference to service.serviceVar. Badly all your old references to the old 1 var will not update.
Solution
To avoid that do it like this :
Service
[...]
service.servicevar = {};
service.servicevar.value = 1;
return service
[...]
You create an object with a new reference and assign it to servicevar. You create a var "1" and assign it to servicevar.value.
Controller
[...]
$scope.myvar = Service.servicevar;
[...]
You assign the servicevar reference to your scope var.
view
{{myvar.value}}
You can use the value by using the property of your var.
Updating the var doing this :
service.servicevar.value = 2;
You will create a new var "2" with a new reference and replace the old reference by this one.
BUT this time you keep all your references to servicevar in your controllers.
I hope i was clear and it solve you issue.
EDIT
My answer was only a partial answer on this question.
Here is the update plunker
First you had a type on the controller definition. You're closing the braces too early. Here is the good definition
app.controller('MainCtrl',['$scope','pService',
function MainCtrl($scope,pService) {
$scope.serviceVar=pService.myVar;
$scope.val = $scope.serviceVar;
}]);
Then you were using windows.interval in angular you need to use the $interval service instead
Example :
app.factory('pService',function($interval){
var pService={};
pService.myVar={};
pService.myVar.count=1;
$interval(function(){
pService.myVar.count++;
},1000);
return pService;
});
Then my problem was occuring. You were binding the value instead of the object in your controller. It looks like this now :
$scope.val = $scope.serviceVar;
Hope it helped you

Injecting data objects into a directive factory in AngularJS

So I have a directive that takes in data objects as an argument into the scope. The problem is that I handle all my data in my service layer.
So this is some normal non-directive code:
angular.module('app').factory('appFactory', ['appValues', function(appValues) {
var getStuff = function() { return appValues.stuff; };
}]);
But if want to reuse the factory inside a directive and get appValues as an argument:
angular.module('app').directive('myDir', [function() {
return {
...
scope: {
values: '='
}
....
};
}]);
But this puts it on the scope and not into my data layer. So now I need to send the values object to every function call in my directive factory:
angular.module('app').factory('myDirFactory', [function() {
var getStuff = function(values) { return values.stuff; };
}]);
Is there any good pattern to solve this and keep data in the data-layer and bypass the scope/controller?
Also, the factory will be a singleton shared amongst instances of the directive? How should I solve that then? Create a new injector somehow? Submit to putting lots of data object logic into the controller (which I've been thought not to do)?
It was a while ago, and I guess that a simple soultion is simply to provide an function initialize(value) {... return {...};} and then the returned object has access to the value argument without providing it as a parameter everywhere:
angular.module('myDir').factory('myDirFactory', [function() {
var initialize = function(values) {
var getStuff = function() {
return values;
};
return {
getStuff: getstuff;
};
};
return {
initialize: initialize
};
}]);

Resources