I have two controllers, say controller1 and controller2.
I have function called function1 defined in controller1.
When I try to call function1 from controller2 using $scope.$broadcast, it works fine in desktop browsers.
But it does not enter into $scope.$on which is written in controller1 in Ipad browser chrome.
I have tried different ways for this to work. importing controller1 into controller2 and so on. But then variables in the browser does not reflect its values.
$scope.$on in controller1:
$scope.$on("con1function", function(event, activity, action) {
$scope.function1(activity,'dashboard');
})
Controller2:
$scope.con2function = function() {
$scope.$broadcast("con1function",data[0], '');
}
can anyone tell me what is wrong here? Or what is the way in which I can make this work for the Ipad as well.
You can try $rootScope.$broadcast("con1function","Hi there") to broadcast the message and $scope.$on() to recieve it.
If your controllers are not related (as parent or child) then just $scope.broadcast or $scope.emit may not work.
var myApp = angular.module('myApp',[]);
myApp.controller('controller1', function ($scope,$rootScope) {
$scope.sendMessage = function(){
console.log("in sendMessage");
$rootScope.$broadcast("con1function","Hi there")
}
});
myApp.controller('controller2', function ($scope,$rootScope) {
console.log("in controller2");
$scope.$on("con1function", function(event, activity) {
console.log('dashboard',activity);
});
});
Also make sure that required controllers are loaded in your script or HTML.
Related
based on this reply link I tried to send a data when I click on a button and call a method from Controller1 to Controller2
this is my try:
Controller1:
$scope.DetailsLivraison = function(){
var idv = $scope.idBonSortie;
$rootScope.$emit("CallParentMethod", idv);
}
Controller2:
$rootScope.$on("CallParentMethod", function(){
$scope.parentmethod(idv);
});
$scope.parentmethod = function(idv) {
//Data traitment
}
my problem is that,the method in the second controller is not called,I have defined $rootscope in both controllers
any help please to solve the problem
thanks for help
Firstly, to make this happen both your controllers should be active at that time.
Secondly, you can use the code below:
$rootScope.$broadcast('CallParentMethod', { //can also use $emit
idv: idv,
});
At the receiving end in the other controller:
$rootScope.$on('CallParentMethod', function(event, args) {
$scope.parentmethod(args.idv);
});
I have checked some of the topics for this matter and i got an understanding of controllers are there to initiate scope and i need to use services for this matter but i dont know how.
so here is the problem. i have index page which body has only one div and inside the div i have ng-include listening to a function called viewFile() which is described on controllerA. on the first initial attempt i load a view called login.html and display it. when users logs in and its successful, which are handled in controllerB, i return a token and now i want to load main.html page using viewFile() in controllerA. is there a call back function or notify controller or something for this? or can i write a service that takes care of this for me?
I'm not using ngRoute because i dont want my URL to change to mysite.com/#/login.html and then mysite.com/#/main.html
.controlle("A", function ($scope, sharedVariable){
$scope.token = sharedVariable.getToken();
$scope.viewFile = function(){
if($scope.token == "")
return "view/Login.html";
else
return "view/main.html";
}
}
.controller("B", function ($scope, $http, sharedVariable)){
http({
get ...
.success: function(data){
$scope.token = sharedVariable.setToken();
// INVOKE viewFile from above controller
}
})
}
and here is the index.html body part
<body>
<div ng-controller="A"><ng-include src="viewFile()"></ng-include></div>
</body>
look at this simple example http://jsfiddle.net/derkoe/T85rg/presentation/ here personService.person is shared between two controllers similarly you can write your viewFile function in one service like personService. Then call personService.viewFile from any controller. You can pass $scope as its argumen. Something like below
var myModule = angular.module('myModule', []);
myModule.factory('myService', function($rootScope) {
var sharedService = {};
sharedService.viewFile = function($scope) {
if($scope.token == "")
return "view/Login.html";
else
return "view/main.html";
};
return sharedService;
});
If you want to change the view using different condition define you viewFile function in some service or put it in routescope. Then you can call it from multiple controllers. But I don't think without refresh angularjs will be able to load a different view html
I have a service that watches something on the rootscope and does something in response. Nobody else requires that service as a dependency. How do I tell the service to start doing its thing?
This is how I do it for now.
angular.module('app')
.service('myService', function ($rootScope) {
return function () {
$rootScope.$on("...", function () {
//do stuff
});
};
})
.run(function (myService) {
myService();
});
Is there a cleaner way to do this?
I've implemented similar things, but using a directive, and not a service:
app.directive('myDirective', function() {
return {
controller: function($scope) {
$scope.$on('myEvent', function () {
// Do stuff
});
}
}
});
And then used this in the root element of my application, which can, for example, be body:
<body ng-app="app" my-directive>
The benefit of using directives in this way over services is that it makes it a touch less global / final. For example, if you end up wanting some scopes to not be able to $emit events to this handler, then you could move the myDirective to another element. Or you could maybe down the road you'll want a part of your app to respond slightly differently to myEvent, so you can add another instance of myDirective, maybe passing it some options via attributes. On the whole it leaves it a lot more open to adding complex behaviour.
When using AngularJS and doing a redirect using $location.path('/path') the new page takes a while to load, especially on mobile.
Is there a way to add a progress bar for loading? Maybe something like YouTube has?
For a progress bar as YouTube has, you can take a look at ngprogress. Then just after the configuration of your app (for example), you can intercept route's events.
And do something like:
app.run(function($rootScope, ngProgress) {
$rootScope.$on('$routeChangeStart', function() {
ngProgress.start();
});
$rootScope.$on('$routeChangeSuccess', function() {
ngProgress.complete();
});
// Do the same with $routeChangeError
});
Since #Luc's anwser ngProgress changed a bit, and now you can only inject ngProgressFactory, that has to be used to create ngProgress instance. Also contrary to #Ketan Patil's answer you should only instantiate ngProgress once:
angular.module('appRoutes', ['ngProgress']).run(function ($rootScope, ngProgressFactory) {
// first create instance when app starts
$rootScope.progressbar = ngProgressFactory.createInstance();
$rootScope.$on("$routeChangeStart", function () {
$rootScope.progressbar.start();
});
$rootScope.$on("$routeChangeSuccess", function () {
$rootScope.progressbar.complete();
});
});
if it is the next route that takes time to load e.g. making ajax call before the controller is run (resolve config on route) then make use of $route service's $routeChangeStart, $routeChangeSuccess and $routeChangeError events.
register a top level controller (outside ng-view) that listens to these events and manages a boolean variable in its $scope.
use this variable with ng-show to overlay a "loading, please wait" div.
if the next route loads fast (i.e. its controller runs quickly) but data that are requested by the controller take a long to load then, i'm afraid, you have to manage the visibility state of spinners in your controller and view.
something like:
$scope.data = null;
$http.get("/whatever").success(function(data) {
$scope.data = data;
});
<div ng-show="data !== null">...</div>
<div ng-show="data === null" class="spinner"></div>
use angular-loading-bar
Standalone demo here ..
https://github.com/danday74/angular-loading-bar-standalone-demo
Here is a working solution which I am using in my application. ngProgress is the best library out there for showing load-bars when changing urls.
Remember to inject the ngProgressFactory instead of ngProgress, as opposed to Luc's solution.
angular.module('appRoutes', []).run(function ($rootScope, ngProgressFactory) {
$rootScope.$on("$routeChangeStart", function () {
$rootScope.progressbar = ngProgressFactory.createInstance();
$rootScope.progressbar.start();
});
$rootScope.$on("$routeChangeSuccess", function () {
$rootScope.progressbar.complete();
});
});
Update Nov-2015 - After analyzing this approach with chrome timings, I have observed that this would not be the correct way for adding a loading bar. Sure, the loading bar will be visible to visitors,but it will not be in sync with actual page load timings.
PRELIMINARIES
I am developing a web app using angularjs. At some point, my main controller connects to a web service which sends data continuously. To capture and process the stream I am using (http://ajaxpatterns.org/HTTP_Streaming). Everything works like a charm. I would like to share these streaming data with another controller that will process and display them via a jquery chart library (not yet decided which one I gonna use but it is out of the scope of this question). To share these data I have followed this jsfiddle (http://jsfiddle.net/eshepelyuk/vhKfq/).
Please find below some relevant parts of my code.
Module, routes and service definitions:
var platform = angular.module('platform', ['ui']);
platform.config(['$routeProvider',function($routeProvider){
$routeProvider.
when('/home',{templateUrl:'partials/home.html',controller:PlatformCtrl}).
when('/visu/:idVisu', {templateUrl: 'partials/visuTimeSeries.html',controller:VisuCtrl}).
otherwise({redirectTo:'/home',templateUrl:'partials/home.html'})
}]);
platform.factory('mySharedService', function($rootScope) {
return {
broadcast: function(msg) {
$rootScope.$broadcast('handleBroadcast', msg);
}
};
});
PlatformCtrl definition:
function PlatformCtrl($scope,$http,$q,$routeParams, sharedService) {
...
$scope.listDataVisu ={};
...
$scope.listXhrReq[idVisu] = createXMLHttpRequest();
$scope.listXhrReq[idVisu].open("get", urlConnect, true);
$scope.listXhrReq[idVisu].onreadystatechange = function() {
$scope.$apply(function () {
var serverResponse = $scope.listXhrReq[idVisu].responseText;
$scope.listDataVisu[idVisu] = serverResponse.split("\n");
sharedService.broadcast($scope.listDataVisu);
});
};
$scope.listXhrReq[idVisu].send(null);
var w = window.open("#/visu/"+idVisu);
$scope.$on('handleBroadcast', function(){
console.log("handleBroadcast (platform)");
});
}
VisuCtrl definition:
function VisuCtrl($scope,$routeParams,sharedService) {
$scope.idVisu = $routeParams.idVisu;
$scope.data = [];
/* ***************************************
* LISTENER FOR THE HANDLEBROADCAST EVENT
*****************************************/
$scope.$on('handleBroadcast', function(event,data){
console.log("handleBroadcast (visu)");
$scope.data = data[$scope.idVisu];
});
}
Injection:
PlatformCtrl.$inject = ['$scope','$http','$q','$routeParams','mySharedService'];
VisuCtrl.$inject = ['$scope','$routeParams','mySharedService'];
PROBLEM DEFINITION
When running this code, it looks like only the PlatformCtrl controller listens for the handleBroadcast event. Indeed, having a look to the console all what is displayed is only handleBroadcast (platform) every time new data arrive. I am very surprised because I have read in the official documentation that the $broadcast function
dispatches an event name downwards to all child scopes (and their
children) notifying the registered ng.$rootScope.Scope#$on listeners.
Since all the scopes in a given app inherits from $rootScope, I do not get why the $on function in VisuCtrl is not launched every time new data are broadcasted.
What I think is that when you open a new browser window you are launching a new AngularJS instance. This way it's not possible that the two controllers are able to communicate via a service.
If you have problems with scopes communicating, you can inject the $rootScope and see whether all the scopes that should communicate are actually instanciated.
function VisuCtrl($scope, $routeParams, sharedService, $rootscope) {
console.log($rootScope);
}
Your request flow comes out of the angular, therefore it would not be recognized until the next $digest phase (see how angular handles two-way binding via dirty matching). To get in to the angular world you need to use $apply:
$scope.listXhrReq[idVisu].onreadystatechange = function() {
$scope.$apply(function () {
var serverResponse = $scope.listXhrReq[idVisu].responseText;
$scope.listDataVisu[idVisu] = serverResponse.split("\n");
sharedService.broadcast($scope.listDataVisu);
});
};
Could it be that your VisuCtrl hasn't been initialized yet, since you are using custom routing?
Is it still the same, when you navigate to /visu/:idVisu?