Is it ok to bind whole service to controller scope? - angularjs

For instance this service :
services.factory('ElementsService', function () {
var currentElement = 'default element';
var service = {
getCurrentElement: function () {
return currentElement;
},
setCurrentElement: function (elmnt) {
currentElement = elmnt;
}
}
return service;
I often find useful to do the following from controllers :
controllers.controller('ElementsCtrl', function($scope, ElementsService) {
$scope.elementsService = ElementsService;
});
To be able to bind the service variables in the html and stay up to date if the variables get changed by some other controller or service. Like so :
<p>The current element is : {{elementsService.getCurrentElement()}}</p>
My question is : is this ok or should I avoid doing this?

Sure the concept is OK and saves having to make a number of different scope variables
Another way you can do it is
angular.extend($scope, ElementsService );
Then in the view you immediately have access to the same data and methods that are returned from the factory
<button ng-click="setCurrentElement(someObj)">test</button>

Related

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

Angularjs pass value from one page to another

In the following code i am trying to change to another page on click and want to pass the object i how can i do it. In the following code i get it as undefined.how to go about this
<button ng-href="#/page1" value="{{i.display}}"></button>
app.controller("ctrls",['$scope','$location',function($scope,$location){
$scope.func = function(i) {
$scope.var=i
$location.path("/rel");
};
]);
app.controller("ctrls",'$scope',function($scope) {
console.log($scope.var) //undefined
]);
Pages normally have controller(s), a service can be created to share data between pages ( by injecting service in associated controllers). Like:
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
In your controller A:
myService.set(yourSharedData);
In your controller B:
$scope.desiredLocation = myService.get();
Happy Helping!
Use a service (best) https://docs.angularjs.org/guide/services
Or $rootScope (bad, but simpler) https://docs.angularjs.org/api/ng/service/$rootScope

angularjs initiating controller scope from a service

I want to be able to preserve scope data between route changes, so I created a service to return saved data to a controller for it to initiate on scope.
app.factory('answerService', function () {
var answers = {
1 : { text : "first answer" },
2 : { text : "second answer" }
}
return {
getAllAnswers: function () {
return answers;
},
getFirstAnswer: function () {
return answers[1];
}
}
});
In my controller, I initiate the first answer by calling the service to get the first answer.
app.controller('myController', function ($scope, answerService) {
$scope.firstAnswer = answerService.getFirstAnswer();
$scope.answers = answerService.getAllAnswers();
});
http://jsfiddle.net/hientc/gj5knrg7/2/
The problem I'm having is that $scope.firstAnswer is somehow also being binded to $scope.answers. I don't want that, I only want the input to bind to scope.firstAnswer.text
What am I doing wrong?
This is because answers[1] is an object reference, and assigning its value to another variable signifies that the variable is a reference to that object. In order to get a copy of that value you can copy it using angular.copy().
Simply change getFirstAnswer() function to something like this:
DEMO
getFirstAnswer: function () {
return angular.copy(answers[1]);
}

Bind the value of a service to a controller so it updates if the service updates

There are a lot of references that discuss this, but I just need someone to confirm if this is right or not. If i have a service which I want to share information with a controller, and the controller should update on changes to the service I need to return an object from the service, like:
.factory('myService', ['$http', function($http) {
var data = {};
var service = {
constant: 1234,
getData: function() {
return data;
},
doCalculation: function() {
service.constant = data.const*25;
},
requestData: function() {
return $http.get('/blah')
.then(function( response ) {
data = response.data;
}
}
}
return service;
}])
Now to pass it to a controller for use and have it update if requestData is invoked again during maybe a route resolve() I would and can't do:
.controller('myCtrl', ['myService', function(myService) {
var self = this;
// PART 1
self.data = myService.constant; // this is not bound and will not update, yes?
self.data1 = myService.getData(); // this is not bound and will not update, yes?
// So, the above would be assigned or invoked only once on init of controller and
// would have to reset manually by assigning either a value or the result of the
// the function call again
self.myService = myService; // pass entire service
// Now, in controller functions or in the UI I can invoke the functions or access
// values, and those results will be bound and update on changes to the service
// since I've passed it in its entirety
self.getData = function() {
return self.myService.getData();
}
// PART 2
self.getData = myService.getData; // would you ever do this?
// You wouldn't have to pass the entire service if it had a bunch of different
// parts that maybe you didn't want to be available...
}]);
PART 1
<div ng-show="myCtrl.myService.doCalculation() === someNumber">You can't see me unless doCalculation resolves to someNumber</div>
PART 2
<div ng-show="myCtrl.getData() === anotherNumber">Would this work? and would you want to do this?</div>
I just can't seem to get the concept of how sharing data between a service(s) and a controller(s) works, and when it is working and when it won't. If all you can do is say correct, wrong, wrong, oh man so wrong, that's kewl, but if you can also say and this is why, I'd be ecstatic to put this away as finally resolved so I don't keep questioning it.
I wouldn't go too far here..
A controller is your view's helper. You need to generate vars and functions on your scope to help your view accomplish things.
Your business model however, is something that you would like to have one reference.
What I do is create my business model on a service, so multiple entities can share it(e.g. other services, directives, controllers etc.).
When my controller kicks in, I add a pointer to the model from the service and use the same reference between them. I bind the models properties to the view.
So:
A controller has it's own methods(dont share the service's methods). A controllers method should be short and use a service method as a helper.
A controller should have a reference to the business model which is created by a service. All your ajax calls should come from the service and populate\send the model that the service is holding.
A controller should have basic view functions(e.g. decide which css class to apply to an element). When you submit a form, the controller function should call the service's submit which will perform you ajax call.
Example:
Html:
<div ng-app="app">
<div ng-controller="myCtrl">
<input type="text" ng-model="Model.propA" />
<br/>
<input type="text" ng-model="Model.propB" />
<div ng-show="ShouldShowSecondDiv()">Second Div.</div>
<br/>
<button ng-click="SubmitForm()">Submit</button>
</div>
</div>
JS:
var app = angular.module('app', []);
app.controller('myCtrl', function ($scope, myService) {
// simple controller "view method".
$scope.ShouldShowSecondDiv = function () {
return $scope.Model.propB > 12;
};
// "complex" "non-view method" -> use service.
$scope.SubmitForm = function () {
myService.SubmitModelToServer();
};
// get the ref. from the service.
$scope.Model = myService.GetModel();
});
app.service('myService', function () {
this.Model = {};
// perform an ajax to get the model or whatever.
this.GetModel = function () {
this.Model = {
propA: 'Im prop A',
propB: 12
};
return this.Model;
};
// submit it to the server via $http. Check the log and you will see the binding(if you changed a value in the view).
this.SubmitModelToServer = function () {
console.log("ajax or whatever....submitted");
console.log(this.Model);
};
});
JSFIDDLE.

AngularJS, Using a Service to call into a Controller

I am new to Angular, what I would like to accomplish is: From a Service / Factory to call methods directly into a controller.
In the following code, I would like from the valueUserController I would like to create a method from the service myApi and set the value inside the valueController.
Here is my code:
modules/myApi.js
var MyApi = app.factory('MyApi', function()
var api = {};
api.getCurrentValue = function() {
// needs to access the Value controller and return the current value
}
api.setCurrentValue = function(value) {
// needs to access the Value controller and set current value
}
api.getValueChangeHistory = function() {
// access value controller and return all the values
}
);
controllers/value.js
app.controller('valueController', function($scope) {
var value = 0;
function getValue() {
return value;
}
function setValue(inValue) {
value = inValue;
}
// ......
});
controllers/valueUser.js
app.controller('valueUserController', function($scope, myApi) {
function doStuff() {
var value = myApi.getValue();
value++;
myApi.setValue(value);
}
});
I am finding to do this in AngularJS pretty difficult and I haven't found any similar post on here.
Thanks for any help,
Andrea
Trying to communicate with a specific controller from a service is not the correct way of thinking. A service needs to be an isolated entity (which usually holds some state), by which controllers are able to interact with.
With this in mind, you can use something like an event pattern to achieve what you are looking for. For example, when your service completes some particular process, you can fire an event like so:
$rootScope.$broadcast('myEvent', { myValue: 'someValue' });
Then any controller in your system could watch for that event and perform a specific task when required. For example, inside your controller you could do the following:
$scope.$on('myEvent', function(event, data){
// Do something here with your value when your service triggers the event
console.log(data.myValue);
});

Resources