I have a trobule about using $rootScope.$broadcast and $scope.$on
I have a one module and two controller(Controller1 & Controller2).
var app = angular.module("app",[]);
app.controller("Controller1",function ($scope,$rootScope){
$scope.$on("msgUpdated",function (event,data){
console.log(data.message);
})
app.controller("Controller2",function ($scope,$rootScope){
$scope.msg = "Hi!";
$rootScope.$broadcast("msgUpdated",{message:msg});
});
This above is my code.
The problem is that my Controller1's $scope.$on is not working.
Why? I don't get it.
and, How can I fix it to fire Controller1's $scope.$on ?
<body ng-app="app">
<div ng-controller="Controller1">
<h1>{{msg1}}</h1>
<input ng-model="test" ng-blur="sendMsg()"/>
</div>
<div ng-controller="Controller2">
<h1>{{msg2}}</h1>
<input ng-model="test" ng-blur="sendMsg()"/>
</div>
</body>
var app = angular.module('app',[])
.controller('Controller1',['$rootScope','$scope',function($rootScope,$scope){
$scope.msg1 = "Start";
$scope.sendMsg = function() {
$rootScope.$emit('msg',$scope.test);
};
var cleanup = $rootScope.$on('msg2', function (event,data) {
$scope.msg1 = data;
});
$scope.$on('$destroy', cleanup);
}])
.controller('Controller2',['$rootScope','$scope',function($rootScope,$scope){
$scope.msg2 = "Start2";
$scope.sendMsg = function() {
$rootScope.$emit('msg2',$scope.test);
};
var cleanup = $rootScope.$on('msg', function (event,data) {
$scope.msg2 = data;
});
$scope.$on('$destroy', cleanup);
}]);
Here is fiddler:
I always use $rootScope.$emit and clean up.
http://jsfiddle.net/hbqsbLyg/
Related
look, click the button, $scope.optionis change, but $watch is not work, can`t console.log the option value , why?
I am sorry , it is my mistake , but it still is a problem in I use width d3.js
I use d3.js append a rect into page, and I want to when I click the rect can chagne the option value, but $watch is not work, why?
angular.module('myapp',[]).controller('myCtrl', function($scope){
$scope.option = '123';
$scope.d3TreeDraw = {
source : {
name: 'myTree'
},
updata: function(){
var _self = this;
var tree = d3.layout.tree().nodeSize([90, 60]);
var nodes = tree.nodes(_self.source).reverse();
nodes.forEach(function(d) { d.y = d.depth * 90; });
var svg = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 200)
var node = svg.selectAll("g.node")
.data(nodes)
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.style('cursor','pointer')
.on('click', function(d){
console.log('click'); // can console.log
$scope.option = '456';
console.log($scope.option) //is change
})
nodeEnter.append("rect")
.attr('width',150)
.attr('height', 30)
.style('fill', '#000')
}
}
$scope.d3TreeDraw.updata();
$scope.$watch('option', function(){
console.log('change:' + $scope.option); // when option is change,can not console.log
})
})
1) First You have taken myTree.onClick() and your function has onclick
So, the onClick() spelling mismatched.
Change button to <button ng-click="myTree.onclick()">456</button>
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="myTree.onclick()">{{data}}</button>
<br>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
$scope.data = '100';
$scope.myTree = {
onclick: function() {
$scope.data = '456';
}
}
$scope.$watch('data', function(){
console.log($scope.data);
alert($scope.data);
})
});
</script>
</body>
</html>
Here is a working DEMO.
EDIT:
By checking your edit, I saw that your scope assignment is outside of angular.
So, you need to $apply() the $scope
Change,
$scope.option = '456';
to,
$scope.$apply(function() {
$scope.option = '456'
});
The above method, runs the digest cycle manually, and apply the changes for the scope.
Performance:
If you write $scope.$apply() it will run complete digest cycle, which will affect the performance, so we sent a function into the $apply method and only ran the digest cycle of specific `scope.
Hence, you can $watch the scope whenever you want.
you have a upper case letter in the function name
change this
<button ng-click="myTree.onClick()">456</button>
to this
<button ng-click="myTree.onclick()">456</button>
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.data = '123';
$scope.$watch('data', function(){
console.log($scope.data);
})
$scope.myTree = {
onclick: function() {
$scope.data = '456';
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<button ng-click="myTree.onclick()">456</button>
</div>
My spring mvc controller returns an object.
My scenario is:
On click of a button from one page say sample1.html load a new page say sample2.html in the form of a table.
In sample1.html with button1 and controller1--> after clicking button1-->I have the object(lets say I got it from backend) obtained in controller1.
But the same object should be used to display a table in sample2.html
How can we use this object which is in controller1 in sample2.html?
You can use a service to store the data, and inject it in your controllers. Then, when the value is updated, you can use a broadcast event to share it.
Here is a few example:
HTML view
<div ng-controller="ControllerOne">
CtrlOne <input ng-model="message">
<button ng-click="handleClick(message);">LOG</button>
</div>
<div ng-controller="ControllerTwo">
CtrlTwo <input ng-model="message">
</div>
Controllers
function ControllerOne($scope, sharedService) {
$scope.handleClick = function(msg) {
sharedService.prepForBroadcast(msg);
};
}
function ControllerTwo($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = sharedService.message;
});
}
Service
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;
});
JSFiddle demo
you can use factory to share data between controllers
<div ng-controller="CtrlOne">
<button ng-click="submit()">submit</button>
</div>
<div ng-controller="CtrlTwo">
{{obj}}
</div>
.controller('CtrlOne', function($scope, sampleFactory) {
$scope.sampleObj = {
'name': 'riz'
}; //object u get from the backend
$scope.submit = function() {
sampleFactory.setObj($scope.sampleObj);
}
})
.controller('CtrlTwo', function($scope, sampleFactory) {
$scope.obj = sampleFactory.getObj();
})
.factory('sampleFactory', function() {
var obj = {};
return {
setObj: function(_obj) {
obj = _obj;
},
getObj: function() {
return obj;
}
}
})
I have setup an RXJS observable. I have two components which subscribe to a subject in service factory. How do I unsubscribe a selected component to the subject so that a button is pressed it stops listening to the subject broadcast?
See my jsfiddle Unsubscribe App
My code:
<div ng-app="myApp" ng-controller="mainCtrl">
<script type="text/ng-template" id="/boxa">
BoxA - Message Listener: </br>
<strong>{{boxA.msg}}</strong></br>
<md-button ng-click='boxA.unsubcribe()' class='md-warn'>Unsubscribe A</md-button>
</script>
<script type="text/ng-template" id="/boxb">
BoxB - Message Listener: </br>
<strong>{{boxB.msg}}</strong></br>
<md-button ng-click='boxB.unsubcribe()' class='md-warn'>Unsubscribe B</md-button>
</script>
<md-content class='md-padding'>
<h3>
{{name}}
</h3>
<label>Enter Text To Broadcast</label>
<input ng-model='msg'/></br>
<md-button class='md-primary' ng-click='broadcastFn()'>Broadcast</md-button></br>
<h4>
Components
</h4>
<box-a></box-a></br>
<box-b></box-b>
</md-content>
</div><!--end app-->
var app = angular.module('myApp', ['ngMaterial']);
app.controller('mainCtrl', function($scope,msgService) {
$scope.name = "Observer App Example";
$scope.msg = 'Message';
$scope.broadcastFn = function(){
msgService.broadcast($scope.msg);
}
});
app.component("boxA", {
bindings: {},
controller: function(msgService) {
var boxA = this;
boxA.msgService = msgService;
boxA.msg = '';
boxA.msgService.subscribe(function(obj) {
console.log('Listerner A');
boxA.msg = obj;
});
boxA.unsubscribe=function(){
};
},
controllerAs: 'boxA',
templateUrl: "/boxa"
})
app.component("boxB", {
bindings: {},
controller: function(msgService) {
var boxB = this;
boxB.msgService = msgService;
boxB.msg = '';
boxB.msgService.subscribe(function(obj) {
console.log('Listerner B');
boxB.msg = obj;
});
boxB.unsubscribe=function(){
};
},
controllerAs: 'boxB',
templateUrl: "/boxb"
})
app.factory('msgService', ['$http', function($http){
var msgSubject = new Rx.ReplaySubject();
return{
subscribe:function(subscription){
msgSubject.subscribe(subscription);
},
broadcast:function(msg){
console.log('success');
msgSubject.onNext(msg);
}
}
}])
As per my comment above the new RxJs 5 Beta now changed from subscription.dispose() to subscription.unsubscribe() Please refer to here https://github.com/ReactiveX/rxjs/blob/master/MIGRATION.md#subscription-dispose-is-now-unsubscribe
Please see updated fiddle: here
the subscribe function returns a Disposable to work with and you must first return the subscription from your factory (line 60):
subscribe: function(subscription){
return msgSubject.subscribe(subscription);
}
This will let you store your subscription in each controller to work with in the future. (line 21 & 42)
var boxASubscription = boxA.msgService.subscribe(function(obj) {
console.log('Listerner A');
boxA.msg = obj;
});
You can then call the dispose method on the subscription when you want to unsubscribe:
boxA.unsubscribe = function(){
console.log('Unsubscribe A');
boxASubscription.dispose();
};
n.b.
For some reason I couldn't get your demo to work with <md-button> so I changed this to <button> for the sake of the demo.
index.html
<body >
<p ng-controller="MainCtrl as mv">Hello {{mv.name}}!</p>
<hr>
<div ng-controller="MainCtrl2 as mv">
<input type="text" ng-model="name">
<button ng-click="mv.setN(name)">submit</button><br>
Hello {{name}}<br>
Hello {{mv.name}}!
</div>
</body>
app.js :
var app = angular.module('plunker', []);
app.service('myService', function() {
var my = this;
my.name = "original";
});
app.controller('MainCtrl', function(myService) {
var mv = this;
mv.name = myService.name;
});
app.controller('MainCtrl2', function(myService) {
var mv = this;
mv.name = myService.name;
mv.setN = function(a) {
myService.name = a;
};
});
why isn't the service able to establish communication between controllers ?I have seen a similar example of factory which is working for communication.
my plunk:
http://plnkr.co/edit/L5uRHPQiXqQV6K7twHul?p=preview
Check the working demo: http://plnkr.co/edit/cTqJImTLdDwPzGsKxN6W?p=preview
Always use Object to share models. Your service should be changed to:
app.service('myService',function(){
var my=this;
my.n = {
name: 'paven'
};
my.setN=function(a){
my.n.name=a;
console.log("name change to "+my.n.name);
}
});
I have this code:
controller:
function deleteRootCategory(){
$scope.rootCategories[0] = '';
}
function getCategories(){
categoryService.getCategories().then(function(data){
$scope.rootCategories = data[0];
$scope.subCategories = data[1];
$scope.titles = data[2];
});
}
getCategories();
service:
var getCategories = function(){
var deferred = $q.defer();
$http({
method:"GET",
url:"wikiArticles/categories"
}).then(function(result){
deferred.resolve(result);
});
}
return deferred.promise;
}
html:
<div ng-controller="controller">
<div ng-repeat="root in rootCategories"> {{root}} </div>
<div ng-repeat="sub in subCategories"> {{sub}} </div>
<div ng-repeat="title in titles">{{title}}</div>
</div>
html2:
<div ng-controller="controller">
<div ng-include src="html"></div>
<button ng-click="deleteRootCategory()">Del</button>
</div>
When I click the deleteRootCategory-button the array $scope.rootCategories is updated, but the view won't ever change.
What am I missing?
Thanks
You will probably want to have a broadcast event set up when the value is changed in the service. Something like this.
.service("Data", function($http, $rootScope) {
var this_ = this,
data;
$http.get('wikiArticles/categories', function(response) {
this_.set(response.data);
}
this.get = function() {
return data;
}
this.set = function(data_) {
data = data_;
$rootScope.$broadcast('event:data-change');
}
});
Have both controllers waiting for the event, and using the set to make any changes to the array.
$rootScope.$on('event:data-change', function() {
$scope.data = Data.get();
}
$scope.update = function(d) {
Data.set(d);
}