AngularJS : watching Service properties - javascript

Take the following plunk as an example:
http://plnkr.co/edit/vKFevXhhSprzFvesc6bG?p=preview
var app = angular.module('plunker', []);
app.service('SomeService', ['$rootScope', function ($rootScope) {
var service = {
value: false
}
return service;
}]);
app.controller('MainCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.value = SomeService.value;
//$scope.$watch(function () { return SomeService.value; }, function (data) { $scope.value = data; });
}]);
app.controller('SecondaryCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.toggleValue = function () {
SomeService.value = !SomeService.value;
}
}]);
2 controllers and a service, 1 controller (SecondaryCtrl) updates a property on the service and the other controller (MainCtrl) references this property and displays it.
Note the $watch expression commented out in MainCtrl - with this line uncommented, everything works as expected but my question - is it necessary? Shouldn't the watch be implicit or am I doing something wrong?

When you assign the value of SomeService.value to your scope variable, you are creating a copy of the variable which is a distinct object from the value inside SomeService. By adding the watch expression you were simply keeping the two variables (the one in the scope and the one in SomeService) synchronised.
The easiest way to go about this is not to copy the value, but create a reference to the service itself. So in MainCtrl
$scope.someService = SomeService;
and in your html
Value: {{someService.value}}
this way you are actually binding to the value inside SomeService.

Related

Common JS file to share variable and methods between two controllers

I have two pages where I have 1 common tab which contains some functionality. I have already code ready for that tab for 1 page and now I want to reuse all that code in my second page without duplicating the code.
For example, this is my code for page 1 of tab :
app.controller('myCtrl', ['$scope', '$window', 'myService', '$filter', function ($scope, $window, myService,$filter) {
$scope.myObj = [
{id:1,location : null},
{id:2,location : null}
]
//Lots of other variables here which are common and will be used in both the tabs and lots of methods which are also common
}]);
$scope.myObj is heavily used in all methods which will be common in both the tabs so I would like to have 1 common js file in which I will keep all this common variables and methods so that I don't have to copy-paste all these methods in both the controller of 2 pages to avoid code duplication.
I found 1 example like below but I am not getting how to share methods and complex variables like my $scope.myObj:
How to share common logic between controllers?
You can simply use angular factory and use it among your controllers to get common variable values. This is one of many possible ways
Create a factory where you'll place common variable values
angular.module("commonmodule", [])
.factory('sharedFactory', function () {
var sharedVariable = 1;
return {
getSharedValue : function () {
return sharedVariable;
},
setSharedValue : function (newValue) {
sharedVariable = newValue;
}
}
}});
Just inject above factory in your controller and use them:
First Controller :
angular.module('maincontrollerone', ["commonmodule"])
.controller('controllerone', ["$scope", "sharedFactory", function ($scope, sharedFactory) {
sharedFactory.setSharedValue("someValueFromCtr1");
}
Second Controller
angular.module('maincontrollertwo', ["commonmodule"])
.controller('controllertwo', ["$scope", "sharedFactory", function ($scope, sharedFactory) {
$scope.value1 = sharedFactory.getSharedValue();
// value of $scope.value1 = 'someValueFromCtr1';
}
Create an Angular Service service, maybe we can use myService.
In the service, Make sure that you are not reseting the reference of the sharedObject by assigning new values to it. You have to change the value only.
Ex:in myService
app.service('myService', ['configService', '$http', '$log', '$q',
function (configService, $http, $log, $q) {
var self = this;
var self.sharedObjects ={};
}
add all the objects that are shared as properties of myService.sharedObjects
DO NOT assign new value to myService.shareObjects, but u can set properties to myService.shareObjects like
myService.shareObjects.prop1,myService.shareObjects.prop2

Angular doesn't work when defining a service and factory separately

I'm trying to write a simple angular service and a factory like below:
html:
<div ng-controller="mycontroller">
{{saycheese}}
</div>
Javascript
var myApp = angular.module('myApp', []);
myApp.service('myservice', function() {
this.sayHello = function() {
return "from service";
};
});
myApp.factory('myfactory', function() {
return {
sayHello: function() {
return "from factory!"
}
};
});
//defining a controller over here
myapp.controller("mycontroller", ["myfactory", "myservice", function(myfactory, myservice) {
$scope.saycheese = [
myfactory.sayHello(),
myservice.sayHello()
];
}]);
But the JSFiddle still just displays {{saycheese}} instead of angular mapping the function.
Link to my fiddle:
http://jsfiddle.net/PxdSP/3047/
Can you point me where am I going wrong in this case ? Thanks.
You have several syntax errors in your code, and checking the console would have helped without questioning the SO. Here's one possible way to write the controller (demo):
myApp.controller("mycontroller", ["$scope", "myfactory", "myservice",
function($scope, myfactory, myservice) {
$scope.saycheese = [
myfactory.sayHello(),
myservice.sayHello()
];
}]);
Apart from obvious fix myapp => myApp (variable names are case-sensitive in JavaScript), $scope should be passed into controller as an argument (and mentioned as its dependency if using arrayed - proper - form of controller definition, as you did) before you can access it. Otherwise you just get ReferenceError: $scope is not defined exception when controller code is invoked.
Couple things:
myapp.controller(...) should be myApp.controller(...)
You need to inject $scope in your controller.
Fixed controller:
myApp.controller("mycontroller", ["myfactory", "myservice", "$scope", function(myfactory, myservice, $scope) {
$scope.saycheese = [
myfactory.sayHello(),
myservice.sayHello()
];
}]);

Angular: Not able to access variables in controller using service

I am trying to share a variable between a controller and a function. But i get an error from the controller, saying this:
TypeError: Cannot read property 'getSet' of undefined
I have gone through numerous tutorials, but don't know where am I going wrong.
My service code is like this:
app.service('shareData', function() {
var selected = ["plz", "print", "something"];
var putSet = function(set) {
selected = set;
};
var getSet = function() {
return selected;
};
return {
putSet: putSet,
getSet: getSet
};
});
I am able to reach selected from my function defined like this:
setDisplay = function($scope, $mdDialog, shareData) {
console.log(shareData.getSet()); // this is working
$scope.selected = shareData.getSet();
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
};
My controller is like this:
app.controller('topicController', ['$scope', '$http', '$mdDialog', 'shareData',
function ($scope, $http, $mdDialog, $mdToast, shareData) {
console.log(shareData.getSet()); // NOT WORKING
}]);
You had extra $mdToast in your topicController controller's factory function, you need to remove it.
The reason behind it was not working is, currently you had 4 dependency mentioned in array like ['$scope', '$http', '$mdDialog', 'shareData', function & then you are using its instance inside the function next to DI array. Inside that function you had actually 5 dependencies where $mdToast extra. So behind the scene what happening is $scope of function hold an value of '$scope' DI array likewise you go right to left. But when it comes to $mdToast(in controller function) it was holding a value of 'shareData'(of DI array) & then the next parameter shareData get nothing.
app.controller('topicController', ['$scope', '$http', '$mdDialog', 'shareData',
function ($scope, $http, $mdDialog, shareData) { //<--removed $mdToast
console.log(shareData.getSet());
}
]);
NOTE: You are using DI inline array annotation, so the sequence in which dependency are injected in array, in same sequence you should
inject then in underlying factory function.

AngularJS $rootScope variable exists, but not accessible

I set a $rootScope variable in one of my modules and now want to access that same $rootScope variable in another module. Thus far I can see that in both modules the variable has been set properly, but when I try accessing the variable in $rootScope, I only get undefined.
How can I access this variable without doing a factory/service workaround? The variable is really simple and $rootScope should suffice for what I need. I've put some generic sample code below to illustrate the issue:
file1.js
var app = angular.module('MyApp1', []);
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.myFunc = function() {
$rootScope.test = 1;
}
}
file2.js
var app = angular.module('MyApp2', []);
app.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.need_to_access_this = $rootScope.test; // undefined
console.log($rootScope); // returns JS object w/ test property set to 1
}
I was just stuck in the same problem when I figured out that you have define those properties for $rootScope before the controllers or services load. So what I did was set inital values when the application runs. In your case it will be like:
app.run(function($rootScope){
$rootScope.test="variable";
})
`
In Ctrl1 the $rootScope.test value is set inside the $scope.myFunc.
The problem is that you aren't calling that function, so the test property in $rootScope is never set.
You need to call $scope.myFunc(); in Ctrl1 or set $rootScope.test = 1; dirrectly in the Controller:
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.myFunc = function() {
$rootScope.test = 1;
};
$scope.myFunc();
}
or
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$rootScope.test = 1;
}
EDIT:
The above suggestions still remain valid, thus you need to call myFunc().
But the problem with your code is that Ctrl1 belongs to MyApp1 and Ctrl2 belongs to MyApp2.
Every application has a single root scope (docs here)
You will need to create Ctrl2 as a controller of MyApp1:
angular.module('MyApp1')
.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.need_to_access_this = $rootScope.test; // undefined
console.log($rootScope); // returns JS object w/ test property set to 1
}]);

$scope is undefined in Controller

I have the worlds simplest controller which i want access to $scope but it is "undefined" and I cannot, for the life of me work out why, however all the functions are called corectly, the DataService, etc is working perfectly, just i have no access to $scope?!
controller code is below
app = angular.module("windscreens", []);
app.controller('DamageCtrl', function($scope, DataService) {
$scope.setDamageLocation = function(location) {
DataService.getDamage().setLocation(location);
};
$scope.isLocation = function(requiredLocation) {
return DataService.getDamage().getLocation() === requiredLocation;
};
$scope.progress = function() {
};
});
To access a property on the scope from your HTML template you only need to use the property name, you don't need to write $scope with it.
Example:
<button ng-click="progress()"></button>
In your javascript you will only have access to the $scope inside the controller and its functions. If you call an external resource, for example: DataService module, it won't have access to the $scope unless you pass it as an argument explicitly.
I managed to get it working using the alternative syntax. As detailed below, still not sure why it wasn't working but hey hum
app.controller('DamageCtrl', ['$scope', 'DataService',
function($scope, DataService) {
$scope.setDamageLocation = function(location) {
DataService.getDamage().setLocation(location);
};
$scope.isLocation = function(requiredLocation) {
return DataService.getDamage().getLocation() === requiredLocation;
};
$scope.progress = function() {
console.log($scope);
};
}
]);

Categories