Ok i know that isn't a good practice to put a watcher inside a controller, but in this case how can i avoid to use watcher?
ps: $rootscope it's not a option ok?
here is the code:
plunker
Edit - here what i did:
plunker
And here is the js code:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, mainService) {
var flag = false;
$scope.btn = function () {
flag = !flag;
mainService.setData(flag);
}
});
app.controller('DemoOneCtrl', function($scope, mainService) {
$scope.name = 'World';
$scope.mainService = mainService;
$scope.show = false;
$scope.$watch('mainService.getData()', function (data) {
$scope.show = data;
});
});
app.service('mainService', function () {
var data = false;
this.setData = function (str) {
data = str;
};
this.getData = function () {
return data;
};
});
And html:
<div ng-controller="MainCtrl">
<button ng-click="btn()">GO!</button>
</div>
<div ng-controller="DemoOneCtrl">
<p ng-show="show">Hello World</p>
</div>
One way to do it is to bind your ng-show to a service function.
app.controller('MainCtrl', function($scope, mainService) {
var flag = false;
$scope.btn = function () {
flag = !flag;
mainService.setData(flag);
}
});
app.controller('DemoOneCtrl', function($scope, mainService) {
$scope.name = 'World';
$scope.mainService = mainService;
$scope.show = mainService.getData;
});
app.service('mainService', function () {
var data = false;
this.setData = function (str) {
data = str;
};
this.getData = function () {
return data;
};
});
Notice how $scope.show is set to mainService.getData. Now you can bind show() to ng-show.
<p ng-show="show()">Hello World</p>
No $watch needed.
Demo
Related
i try to share data between two different controllers using a service and watch changes but i don't find how to do this. Here is my code
month-select.component.js:
'use strict'
angular
.module('myApp.monthSelect')
.component('myApp.monthSelect', {
templateUrl: 'monthSelect/month-select.template.html',
controller: 'MonthSelectCtrl',
css: 'monthSelect/month-select.style.css'
})
.controller('MonthSelectCtrl', ['$scope', 'selectedMonthSvc', function ($scope, selectedMonthSvc) {
selectedMonthSvc.setDate($scope.dt)
}])
weeks-list.component.js:
'use strict'
angular
.module('myApp.weeksList')
.component('myApp.weeksList', {
templateUrl: 'weeksList/weeks-list.template.html',
controller: 'WeeksListCtrl',
css: 'weeksList/weeks-list.style.css'
})
.controller('WeeksListCtrl', ['$scope', 'selectedMonthSvc', function ($scope, selectedMonthSvc) {
$scope.getDate = selectedMonthSvc.getDate
}])
get-select-month.service.js
angular.module('myApp.svc', [])
.factory('selectedMonthSvc', function () {
var self = this
var date = ''
self.setDate = function (value) {
return date = value
}
self.getDate = function () {
return date
}
return self
})
It works at init i get the date in my WeeksList controllers, but if i change the date in my MonthSelectCtrl, the value don't update in WeekList.
I'm trying to watch it with $watch but it don't work and have no idea where it goes wrong.
Thank you very much for your help.
1st off change factory to service:
.service('selectedMonthSvc', function () {/**/}
Further
You can write watcher to listen on changes.
So instead:
$scope.getDate = selectedMonthSvc.getDate
try:
$scope.getDate = selectedMonthSvc.getDate;
$scope.$watch('getDate', function() {
// here you get new value
});
This is simple demo that demonstrates your case
When second controller updates date, 1st controller listens and reflects on changes:
angular.module('myApp', [])
.controller('Ctrl1', function ($scope, App) {
$scope.status = App.getDate();
$scope.$watch(function(){
return App.getDate();
}, function() {
$scope.status = App.getDate();
});
})
.controller('Ctrl2', function ($scope, App) {
$scope.status = App.getDate();
$scope.$watch('status', function() {
App.setDate($scope.status);
});
})
.service('App', function () {
this.data = {};
this.data.date = 'someDate';
var self = this;
var date = ''
self.setDate = function (value) {
this.data.date = value
}
self.getDate = function () {
return this.data.date;
}
});
Try this:
// selectedMonthSvc service:
angular.module('myApp.svc', [])
.factory('selectedMonthSvc', function () {
var date = '';
var self = this
self.setDate = setDate;
self.getDate = getDate;
return self;
function setDate(value) {
date = value;
}
function getDate() {
return date;
}
})
// WeeksListCtrl controller
.controller('WeeksListCtrl', ['$scope', 'selectedMonthSvc', function ($scope, selectedMonthSvc) {
$scope.getDate = getDate;
function getDate() {
return selectedMonthSvc.getDate();
}
}])
var app = angular.module('app', []);
app.controller('firstController', ['$scope','selectedMonthSvc', function($scope, selectedMonthSvc) {
$scope.date = new Date();
$scope.changeDate = function() {
selectedMonthSvc.setDate(new Date())
}
}]);
app.controller('secondController', ['$scope','selectedMonthSvc', function($scope, selectedMonthSvc) {
$scope.date = '';
$scope.selectedMonthSvc = selectedMonthSvc;
$scope.$watch(function() {
return $scope.selectedMonthSvc.getDate();
}, function(newVal) {
$scope.date = newVal;
}, true);
}]);
app.factory('selectedMonthSvc', [function() {
var date = '';
return {
getDate: function () {
return date;
},
setDate: function(d) {
date = d;
}
}
}])
Here is the working plunker https://plnkr.co/edit/w3Y1AyhcGhGCzon8xAsV?p=preview
/*service */
app.service('sharedProperties', function () {
var property = 'First';
return {
getProperty: function () {
return property;
},
setProperty: function(value) {
property = value;
}
};
});
/*first contoller */
app.controller('loginCtrl',function($scope,$location,$http,$window,sharedProperties){
$scope.submit =function(){
var username=$scope.username;
var pass=$scope.password;
sharedProperties.setProperty(username);
$location.path('/userdashboard');
$window.location.reload();
});
}
});
/*second controller*/
app.controller('empController', function($route,$scope,$http,$routeParams,sharedProperties){
$scope.getEmployees = function(){
alert( sharedProperties.getProperty());
};
};
Try this, it will work for you. :
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="sendData();"></button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
function sendData($scope) {
var arrayData = [1,2,3];
$scope.$emit('someEvent', arrayData);
}
});
app.controller('yourCtrl', function($scope, $http) {
$scope.$on('someEvent', function(event, data) {
console.log(data);
});
});
</script>
Service does not need to return anything. You have to assign everything in this variable. Because service will create instance by default and use that as a base object.
app.service('sharedProperties', function () {
this.property = 'First';
});
Then in controller
sharedProperties.property = $scope.username;
Had you been looking to use factory
app.factory('sharedProperties', function () {
var factory = {};
factory.property = 'Hello';
factory.setProperty = function (value) {
factory.property = value;
};
return factory;
});
Then in controller you would use it
sharedProperties.setProperty($scope.username); // Setter
$scope.var = sharedProperties.property; //getter
EDIT
Working Plnkr
You can assign members to $rootScope, which will store data globally for your app. Just inject $rootScope to each controller.
For instance...
/*first controller */
app.controller('loginCtrl',function($scope,$rootScope,$location,$http,$window,sharedProperties){
$scope.submit =function(){
var username=$scope.username;
var pass=$scope.password;
$rootScope.username = username;
$location.path('/userdashboard');
$window.location.reload();
});
}
});
This will make 'username' available to any controller that injects and consumes $rootScope.
/*second controller*/
app.controller('empController', function($route,$scope,$rootScope,$http,$routeParams,sharedProperties){
$scope.getEmployees = function(){
alert($rootScope.username);
};
};
Say I have following controllers:
controller("MyCtrl1", ["$scope", "$sce", "myService", "$location",
function ($scope, $sce, myService, $location) {
$scope.Resources = window.MyGlobalResorcesObject;
$scope.trustedHtml = function (input) {
return $sce.trustAsHtml(input);
};
$scope.startProcessing = function () {
$scope.processingRequest = true;
};
$scope.endProcessing = function () {
$scope.processingRequest = false;
$scope.$apply();
};
//some MyCtrl1-specific code goes here
}]).
controller("MyCtrl2", ["$scope", "$sce", "myService", "$location",
function ($scope, $sce, myService, $location) {
$scope.Resources = window.MyGlobalResorcesObject;
$scope.trustedHtml = function (input) {
return $sce.trustAsHtml(input);
};
$scope.startProcessing = function () {
$scope.processingRequest = true;
};
$scope.endProcessing = function () {
$scope.processingRequest = false;
$scope.$apply();
};
//some MyCtrl2-specific code goes here
}]);
You see, code is duplicated.I want to reuse common code.
What is the common practice to achieve this?
Use a common service:
module.factory('processing', function($sce) {
function initialize($scope) {
$scope.Resources = window.MyGlobalResorcesObject;
$scope.trustedHtml = function(input) {
return $sce.trustAsHtml(input);
};
$scope.startProcessing = function() {
$scope.processingRequest = true;
};
$scope.endProcessing = function () {
$scope.processingRequest = false;
$scope.$apply();
};
}
return {
initialize: initialize;
}
});
And then in your controllers:
controller("MyCtrl1", function($scope, processing) {
processing.initialize($scope);
}
I have the following JSFiddle
I want two way binding for these sliders that will eventually set the value in the service
Meaning that the on is changed also the second and the value in the service also
HTML:
<div>
<div ng-controller="FirstCtrl">
<input type="range" ng-model="speakerVolume" />
{{speakerVolume}}
</div>
<div ng-controller="SecondCtrl">
<input type="range" ng-model="speakerVolume" />
{{speakerVolume}}
</div>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.controller('FirstCtrl', function($scope, voipService) {
$scope.speakerVolume = voipService.speakerVolume;
$scope.$watch("speakerVolume", function (newValue) {
voipService.speakerVolume = newValue;
voipService.setVolume(newValue);
});
});
myApp.controller('SecondCtrl', function($scope, voipService) {
$scope.speakerVolume = voipService.speakerVolume;
$scope.$watch("speakerVolume", function (newValue) {
$scope.speakerVolume = newValue;
voipService.setVolume(newValue);
});
});
myApp.service('voipService', function() {
this.speakerVolume = 50;
this.setVolume = function(newVal){
self.speakerVolume = newVal;
}
});
Final Answer in Fiddle:
Fiddle - Final Answer
one way is to watch also service value, not just scope variable
var myApp = angular.module('myApp', []);
myApp.controller('FirstCtrl', function($scope, voipService) {
$scope.speakerVolume = voipService.speakerVolume;
$scope.$watch("speakerVolume", function (newValue) {
voipService.speakerVolume = newValue;
});
$scope.$watch(function() {
return voipService.speakerVolume;
}, function (newValue) {
$scope.speakerVolume = newValue;
});
});
myApp.controller('SecondCtrl', function($scope, voipService) {
$scope.speakerVolume = voipService.speakerVolume;
$scope.$watch("speakerVolume", function (newValue) {
voipService.setVolume(newValue);
});
$scope.$watch(function(){
return voipService.speakerVolume;
}, function (newValue) {
$scope.speakerVolume = newValue;
});
});
myApp.service('voipService', function() {
var self = this;
this.speakerVolume = 50;
this.setVolume = function(newVal){
self.speakerVolume = newVal;
}
});
second way is to use $broadcast in the service (when the value is changed) and update values in all controllers when this custom event is fired
function ParentCtrl($scope) {
//some function check whether data object in child scope is still null
}
function ChildCtrl($scope) {
$scope.data={};
$scope.func = function(){
$scope.data.x = 1;
};
};
jsFiddle: http://jsfiddle.net/JHwxP/74/
You can use a system of events like you can see here : http://jsfiddle.net/patxy/RAVFM/
If you have 2 controllers with a shared service, you can do it that way :
var myModule = angular.module('myModule', []);
myModule.factory('mySharedService', function($rootScope) {
var sharedService = {};
sharedService.message = '';
sharedService.prepForBroadcast = function(msg) {
this.message = msg;
this.broadcastItem();
};
sharedService.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
return sharedService;
});
function ControllerZero($scope, sharedService) {
$scope.handleClick = function(msg) {
sharedService.prepForBroadcast(msg);
};
$scope.$on('handleBroadcast', function() {
$scope.message = sharedService.message;
});
}
function ControllerOne($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = 'ONE: ' + sharedService.message;
});
}
function ControllerTwo($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = 'TWO: ' + sharedService.message;
});
}
ControllerZero.$inject = ['$scope', 'mySharedService'];
ControllerOne.$inject = ['$scope', 'mySharedService'];
ControllerTwo.$inject = ['$scope', 'mySharedService'];