AngularJS automatically updating controller data by service - javascript

I'm having some basic problems with angular at the moment. I just wrote a service that reads the temperature of an external device in an interval of five seconds. The service saves the new temperature into a variable and exposes it via a return statement. This looks kind of this (simplified code):
angular.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = 0,
requestTemp = function() {//some logic here},
onResponseTemp = function (temp) {
m_temp = temp;
},
//some other private functions and vars ...
foo = bar;
//request new temperture every 5s, calls onResponseTemp after new data got received
$interval(requestTemp, 5000);
return {
getTemp = function(){return m_temp;}
}
}]);
I use a controller to fetch the data from the service like this:
angular.controller("tempCtrl", ["$scope", "tempService", function ($scope, tempService) {
$scope.temp = tempService.getTemp();
}]);
In my view I access it like this:
<div ng-controller="tempCtrl">
<p>{{temp}}</p>
</div>
But I only get 0 and the value never changes. I have tried to implement a custom Pub/Sub pattern so that on a new temperature my service fires an event that my controller is waiting for to update the temperature on the scope. This approach works just fine but I'm not sure if this is the way to go as angular brings data-binding and I thought something this easy had to work by itself ;)
Help is really appreciated.

Please see here http://jsbin.com/wesucefofuyo/1/edit
var app = angular.module('app',[]);
app.service("tempService", ["$interval", function ($interval) {
//revealing module pattern
var m_temp = {
temp:0,
time:null
};
var requestTemp = function() {
m_temp.temp++;
m_temp.time = new Date();
};
var startTemp = function() {
$interval(requestTemp, 3000);
};
return {
startTemp :startTemp,
m_temp:m_temp
};
}]);
app.controller('fCtrl', function($scope,tempService){
$scope.temp = tempService;
$scope.temp.startTemp();
});

You are returning a primitive from your service, if you want to update an primative you need to reftech it. You should return an object, as on object is passed by reference, you get the actual values in your controller.
do this in your service:
return m_temp;
And this in your controller:
$scope.temp = tempService;
and your view will update as soon as the service gets updated.
Does this help you?

i think you should use $interval in controller ot in service
$interval(tempService.getTemp(), 5000);

Related

Unable to sync AngularJS service with controllers (angular.copy)

I have set up two controllers (Controller A and Controller B) and a service (Service). I am attempting to sync the data from controller A to the service, and present that information to Controller B.
Within my Service, I've established a variable confirmdata and get and set functions:
function setData(data) {
confirmdata = angular.copy(data);
}
function getData() {
return confirmdata;
}
In controller A I've created a function syncto sync information from the controller to the service:
this.sync = function () {
var data = {
payment: this.getpayment()
}
Service.setData(data);
In controller B I've assigned a function as:
this.sync = function () {
this.viewData = Service.getData();
console.log('TestingData', this.viewData);
For a reason I am unaware of; my console log simply returns undefined when it should be returning the results of the getpayment() function. Am I missing something here?
The fact that you are getting undefined would indicate that you haven't initialized 'confirmdata' in your service. Whether this is the actual issue though, isn't clear. For a simple example, I would design your service like this:
myApp.factory('sharedService', [function () {
var confirmdata = {};
return {
setData: function (newData) { confirmdata = newData; },
getData: function getData() { return confirmdata; }
}
}]);
Take a look at this plunker. It gives an example of data being shared between controllers via a service.

Getters and Setters in AngularJS

confirm("Ohhh, hello there, is it Ok to click Cancel?");
I think that this is, basically, a question about CRUD on Angular. I'm kind of confused about getters and setters, mainly because Angular do almost all the job in getting and setting things because of its two way data binding. I want to know what's the best scalable way to create getters and setters so I wont need to modify my functions in the future.
On the first Arrangement, I'm trying to be as simple as I can be, but I feel uncomfortable in getting and getting to set.
Arrangement 01:
$scope.getData = function(){
$http.get(url + '/data')
.then( function (res) {
return res.data; } );
};
$scope.setData = function () {
$scope.data = $scope.getData();
};
$scope.insertData = function (data) {
$http.post(url + '/data', { data: data})
.then( function (res) {
// nothing here. } );
};
On this second Arrangement, however, I'm trying to go directly where I need to. When I fetch data from the server, I'm automagicaly setting my $scope.data to the retrieved data;
Arrangement 02:
$scope.getData = function () {
$http.get(url + '/data')
.then( function (res) {
$scope.data = res.data;
});
};
$scope.insertData = function (data) {
$http.post( url + '/data', { data: data })
.then( function (res) {
$scope.getData(); //To update.
//OR $scope.data.push(res.data);
});
};
Looking further, I've found this on the Angular Docs, but what's the point in using a getter/setter if Angular already do it? Looking into other technologies, it's hard to compare, because Angular has auto-get.
I don't even know how to formulate this question. But, basically, I want to know how could my getters and setters harm my future application and if there's a good way and why to create getters and setters in Angular.
Thanks for any advice.
You good practice is to wrap your logic into Service. You have to know that in Angular, all services are Singleton, there is only a single instance of a Service.
I've made a simple example, by using $q.defer() which is the promise manager from the deferred API.
$q.defer() get 2 methods :
resolve(value) : which resolve our associated promise, by giving her the final value
reject(reason) : which resolve an promise error.
Controller
(function(){
function Controller($scope, $q, Service) {
//Use promise manager
var defer = $q.defer();
///Create our promise
var promise = defer.promise;
$scope.data = [];
var newData = [
{
name:'john',
age: 25
},
{
name: 'toto',
age: 13
}
];
Service.get().then(function(data){
//Retrieve our data
$scope.data = data;
//Set new data to our factory
Service.set(newData);
//Retrieve new data
Service.get().then(function(data){
//Resolve new data
defer.resolve(data);
});
});
//Retrieve new dataset
promise.then(function(data){
$scope.data = data;
})
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
Service
(function(){
function Service($q){
var data = [0,1,2,3,4];
function set(value){
data = value;
}
function get(){
return $q(function(resolve){
//Simulate latency
setTimeout(function(){
//Resolve our data
resolve(data);
}, 1000);
});
}
return {
get: get,
set: set
};
}
angular
.module('app')
.factory('Service', Service);
})();
HTML
<body ng-app='app' ng-controller="ctrl">
<pre>{{data}}</pre>
</body>
So, you can set some data by using the service, and retrieve it when you want. Don't forget that service is singleton.
You can see the Working Plunker
In JavaScript you typcially don't use getters and setters like in OOP languages, especially because you do not have a notion of privateness (so anyone can access your fields). ES5 has getters and setters, but it also adds this missing capabilities of hiding implementation details. In case you want getters and setters for additional logic in your AngularJS app, you could simply define additional fields which are updated using $watch.
Furthermore you solution with sending an HTTP request on every change is a it of an overhead if you do this per field. What you instead to is writing directly to fields.
While e.g. WPF/C# requires you to define setters to raise OnPropertyChanged, you don't need this in AngularJS. Everything that you write in AngularJS will automatically trigger a so-called $digest cycle, where it checks for changes that have been made. It will then automagically update your user interface, give that you use template bindings or ng-model directives.
If you think like pure Javascript, is basic the same logic, what angular does is create modules for you to use the best practice, so it is easy to use them.
function DataService($http) {
this.get = function() {
return $http.get(...);
}
this.create = function(newData) {
return $http.post(...);
}
..
}
and using angular, like Ali Gajani sayd, you basically can do this,
angular.module('myApp').service('DataService', ['$http', DataService]);
or with a factory style
function DataService($http) {
var myPrivateVariable = "something";
function get() {
return $http.get(...);
}
...
// expose them public
return {
get: get
};
}
angular.module('myApp').factory('DataService', ['$http', DataService]);

Not able to get the content of model in multiple controllers AngularJS

Hope, my question itself, conveys what I am look for.
Will put the words in detail
1. Created the Module.
var ang = angular.module('myApp', []);
I have a controller called controller1, and includes the 'campaign' factory.
//controllerone.js
ang.controller('controller1', function(campaign){
$scope.campaigns = new campaign();
//Here the whole campaign object is displayed with data, refer the Image 1 attached
console.log($scope.campaigns);
});
ang.factory('campaign', function($http){
var campaign = function(){
this.timePeriodList = buildTimePeriodList();
...
...
this.campaignList = [];
};
Campaigns.prototype.fetchCampaigns = function() {
//Some service call to load the data in this.campaignList
};
});
Now trying to call the same campaign factory in the second controller, getting only the object structure, not getting the data.
//controlertwo.js
ang.controller('controller2', function(campaign){
$scope.campaigns = new campaign();
//Here only the campaign object structure is displayed, but no data for campaignList, ref image 2 attached
console.log($scope.campaigns);
});
Since, factory service is a singleton object, I was expecting for same result as I got in controllerone.js,
Image 1:
Image 2:
In angular factory I would suggest a different approach.Try not to attach anything to the Prototype of a object. Instead you can create an object in the scope of your angular factory, attach what you want to it and return it. For example:
ang.factory('campaign', function ($http) {
var campaign = {};
campaign.method1 = function () {
//..
}
campaign.campaignList = [];
//...
campaign.fetchCampaigns = function () {
//Some service call to load the data in this.campaignList
};
});
//Than in your controllers if campaign is injected you can use it that way:
ang.controller('controller2', function (campaign) {
campaign.fetchCampaigns();// This will fill the list and it will remain filled when other controllers use this factory...
console.log(compaign.campaignList);
});
Anything you dont want to be exposed out of the factory simply do not attach it to the campaign object.
Create campaign in a service. Eg-campaignService
Updated code---
var ang = angular.module('myApp', []);
ang.service('campaignService', function($scope){
var campaign = function(){
this.timePeriodList = buildTimePeriodList();
...
...
this.campaignList = [];
}
return campaign;
});
ang.controller("controller1", ["campaignService",
function($scope, $rootScope, campaignService){
$scope.campaigns=campaignService.campaign();
}
]);
ang.controller("controller2", ["campaignService",
function($scope, $rootScope, campaignService){
$scope.campaigns=campaignService.campaign();
console.log($scope.campaigns);
}
]);

Moving logic to a service in Angular

I've ended up with a lot of logic in my controller which I realise is not good. Therefore I would like to move this to a service.
At the moment the controller accepts a url which will either be from YouTube or Vimeo. It detects whether the string "youtube" or "vimeo" is present in the url and then does what it needs to do accordingly. Here's part of the "logic" that currently resides in the controller:
if url.indexOf("youtube") > -1 {
variable_1 = "Something";
variable_2 = "Something";
//do some more stuff
}
else {
variable_1 = "Something";
variable_2 = "Something";
//do some more stuff
}
$scope.task.items.push("I need to add things to this array too");
A Service is the way to go but my first question is a service or a factory?
This is what I'm working on but I'm not sure how I would pass the variables that exist in the controller (variable_1 and variable_2) back to the controller when the service has completed.
myApp.service('urlService', function() {
this.detectProvider = function() {
if url.indexOf("youtube") > -1 {
}
else {
}
//how can I push things to the $scope array here?
};
});
In your service
myApp.service('urlService', function() {
this.detectProvider = function(url) {
arrayOfMyVars = new Array();
if url.indexOf("youtube") > -1 {
arrayOfMyVars.push("Something");
arrayOfMyVars.push("SomethingElse");
}
else {
arrayOfMyVars.push("Something");
arrayOfMyVars.push("SomethingElse");
}
//how can I push things to the $scope array here?
return arrayOfMyVars;
};
});
in your controller
var res = urlService.detectProvider(url);
variable_1=res[0];
variable_2=res[1];
$scope.task.items.push('the thing you need to push'); // maybe res[2] and in your service you had another arrayOfMyVars.push('the thing you need to push')...
Don't forget to import your service into your controller ;)
A Service is the way to go but my first question is a service or a
factory?
Simply speaking it does not matter. From personal point of view just use what suits you best. A service will create a new instance of the function, a factory will simply execute the function and do not create a new instance of it.
About your second question: Simply return variable_1 and variable_2 in your services method and assign them to your $scope.
myApp.service('urlService', function() {
this.detectProvider = function(url) {
if url.indexOf("youtube") > -1 {
...
return [variable_1, variable_2];
}
else {
...
return [variable_1, variable_2];
}
};
});
Service or Factory both are singleton instances. At the end u will get object only.
In service you will create using functtion constructor
In Factory we can construct it using object literrals

Modifying Angular Factory Object from inside a function

This is the function that I am working with to call my factory
var myService = function($http) {
return {
bf: null,
initialize: function() {
this.promise = $http.get(this.server + "/requestkey").success(function(data) {
myService.bf = new Blowfish(data.key);
});
}
}
And I am creating this object using
TicTacTorrent.service('AService', ['$http', myService]);
However, when calling AService.initialize() it creates the promise object like it should, but it doesn't update the BF object. I'm confused as to how to update the bf object to be the new value. How would I reference myService.bf since this.bf would create a local instance for .success function?
Try this:
var myService = function($http) {
this.bf = null;
return {
bf: this.bf,
initialize: function() {
this.promise = $http.get(this.server + "/requestkey").success(function(data) {
myService.bf = new Blowfish(data.key);
});
}
}
Where do you want to initialize?
Have you seen the $provider example code?
Search for "provider(name, provider)" and check if it suits your need.
Otherwise I'm unsure what the code you'vew written will run like.
I usually write factories like this:
angular.module('app').factory('myService', ['$http', function($http) {
var publicObj = {};
publicObj.bf = ""; // Just to make sure its initialized correctly.
publicObj.initialize = function() {snip/snap... myService.bf = new Blowfish(data.key);};
return publicObj;
}]);
The difference might be that you previous code returned an inline anonymous object which might have a hard time referring to itself. But by that logic it should work by just making myService return a predeclared var and returning that.

Categories