0

I have a directive that reads sync data from <title> tag. Then it trigger a service which $broadcast the data to all controllers.

But the controllers under <body> tag are not receiving this. However if I move ng-app attr from html to body, and move the directive with the controller from head to body. Then all the controllers will work properly.

Here is my sample code: http://jsbin.com/oBAMOs/4/edit?html,js,console,output

From the code I believe you can pretty much guess what I am trying to do. So why is this happening and is there a better way to achieve this?

hugo der hungrige
  • 12,382
  • 9
  • 57
  • 84
oceanlau
  • 3
  • 1

2 Answers2

1

navCtrl doesn't exist at the point at which you send your broadcast. You can confirm that by putting log statements at the beginning of each controller and the send. You'll see you send before navctrl is created. ("title" happens then "send" then "nav")

An easy way to resolve this is to push your $broadcast till after the browser finishes all current queued up tasks (which will include rendering the rest of the DOM, and thus the instantiation of navCtrl). You can accomplish this by placing the broadcast within a $timeout that has a delay of 0. As follows:

 $timeout (function() {
    $rootScope.$broadcast('processed');
  },0);

and make sure to pass timeout in:

.factory('syncPageid', ['$rootScope','$timeout', function($rootScope,$timeout){

This is a by product of the single threaded nature of javascript. For a discussion on why timeout works here and the underlying issue you can check out: setTimeout with zero delay used often in web pages, why? and http://ejohn.org/blog/how-javascript-timers-work/

Community
  • 1
  • 1
KayakDave
  • 24,636
  • 3
  • 65
  • 68
  • +1 Never thought those kind of issues would occur with angularjs, but thats probably on of the reasons why you usually try to avoid broadcasts. They don't really fit in. Still trying to wrap my head around it. But it makes sense though. – hugo der hungrige Nov 12 '13 at 04:36
  • Yea it's ultimately a javascript thing. Events are so tied to the dom that there's clearly risks - especially when triggering one during initialization like this. – KayakDave Nov 12 '13 at 04:40
  • 1
    I'm still very curious what he is trying to achieve. I'm wondering what kind of synchronous data needs to be broadcasted like that. – hugo der hungrige Nov 12 '13 at 04:49
  • Well the sample code is pretty much all that it is. I have a smarty variable that tells me the page id. And I need to update the `` and activate the nav item accordingly. I'm sure broadcasting like this is not the best option. So what's the best way to do this? @hugoderhungrige – oceanlau Nov 12 '13 at 05:12
  • @oceanlau hard to say without knowing a little more. A quick and dirty way would be to assign a global javascript-variable via smarty. If given you can also parse url-parameters or the whole url, if need too. Actually its an interesting question, how communicate between angularjs and the server in such cases. – hugo der hungrige Nov 12 '13 at 13:53
0

Instead of just

$rootScope.$broadcast('processed');

you can have

$rootScope.$broadcast('processed', "data_you_need_to_pass_around");

and catch that like

$scope.$on('processed', function (e, args){
    $scope.title = args;
    console.log('titleCtrl: ' + args);
 });

http://jsbin.com/oBAMOs/11/edit

And then ofcourse your syncPageid factory can expose it to all other code bits that is interested in pageid. But having a factory just to facilitate passing data between places bits makes no good sense.

salek
  • 444
  • 4
  • 14