0

I've been trying to use $broadcast and $on but I just can't get the data to move between the two controllers.

On my main webpage i have a button which adds 4 to a var each time it's hit:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body ng-app="app">
    <div ng-controller="mainCtrl">

        <button ng-click="add(4)"> 4 </button>

    </div>
    <script src="../Scripts/angular.js"></script>
    <script src="../assets/js/angular-grid.js"></script>
    <script src="../assets/controller/gods_controller.js"></script>
    <script src="../Scripts/angular-animate.js"></script>
</body>
</html>

In my mainCtrl I have the function add() and use $broadcast to broadcast my value:

var module = angular.module("app", ["angularGrid", "ngAnimate"])

module.controller("mainCtrl", function ($scope, $rootScope) {

var total = 0

    $scope.add = function (x) {
        total += x;

        $rootScope.$broadcast('totalBroadcast', total)

    }

});

Then I have a second controller for my popup using $on to receive the broadcast:

module.controller('popUpCtrl', function ($scope) {


     $scope.$on('totalBroadcast', function(events, args){

  $scope.total = args;
  })

   })

Then my popup HTML uses the second controller and $scope.total as an expression:

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body ng-app="app">
    <div ng-controller="popUpCtrl">

       <p>The total is: {{total}}</p>

    </div>
    <script src="../Scripts/angular.js"></script>
    <script src="../assets/js/angular-grid.js"></script>
    <script src="../assets/controller/gods_controller.js"></script>
    <script src="../Scripts/angular-animate.js"></script>
</body>
</html>

No data seems to be passed to my second controller, the expression doesn't show anything at all.

EDIT


I have also tried using a service, HTML's above remain the same but now I've added a service

module.factory('myService', function () {

    var total = 0;

    var setTotal = function (x) {
        total = x;
    }

    var getTotal = function () {
        return total;
    };

    return {
        setTotal: setTotal,
        getTotal: getTotal
    }


    });

My main controller and ad function are now:

 module.controller("mainCtrl", function ($scope, myService) {

    var total = 0

    $scope.add = function (x) {

        myService.setTotal(x)
    }

 });

and my popupCtrl controller is now this :

module.controller('popUpCtrl', function ($scope, myService) {


    $scope.total = myService.getTotal();

})

{{total}} in my popup is now being expressed as the "0" which var total is equal to in my service. So the data is now being transferred using the service, but the setTotal() method isn't setting the var as instructed by the add() function now. I have injected my service as a dependency to both controllers.

notAChance
  • 1,360
  • 4
  • 15
  • 47
  • you're broadcasting on $rootscope but watching on $scope. Try changing it to $rootscope.$on. – Lee Willis Sep 18 '15 at 10:48
  • 1
    This looks like 2 completely different web pages. If so, each page initializes your app as new instance and there is no persistence in javascript between page loads – charlietfl Sep 18 '15 at 10:48
  • yes they are two different pages, is there no way to do this then? – notAChance Sep 18 '15 at 10:50
  • Angular is based around creating a single page app, so one page loads the javascript and uses views to show the content. – Lee Willis Sep 18 '15 at 10:51
  • Seems you have a fundamental misunderstanding about how angular works within a single page application (SPA). Suggest going through some tutorials. The one on angular docs site is a good starter – charlietfl Sep 18 '15 at 10:54

3 Answers3

1

Its a very bad practice to add watches or broadcast for sharing your data between controllers, do it for injecting a common service in both controllers.

Services provide an easy way for us to share data and functionality throughout our app. The services we create are singletons that can be injected into controllers and other services, making them the ideal place for writing reusable code.

Follow its link https://thinkster.io/a-better-way-to-learn-angularjs/services

Kashif Mustafa
  • 1,152
  • 6
  • 20
  • can you please make it a plunker, you didn't inject your service in both controllers, i can fix your problem if you a make plunker of it. its quite simple – Kashif Mustafa Sep 18 '15 at 12:26
  • i have injected my service into both controllers - see edit again – notAChance Sep 18 '15 at 12:30
  • I have seen your problem, you have initialize ng-app again on both html pages, it means angular initialize again. so make it in one app. Make a master page and initialize app once. This is your problem in your provided code. – Kashif Mustafa Sep 18 '15 at 12:41
  • How do you mean make a master page? Is this possible in HTML? How do I initialize an app once, but have two windows? – notAChance Sep 21 '15 at 09:57
  • HTML itself is a static language. Other frameworks create dynamic HTML (DHTML) such as ASP.NET, PhP. So a pure implementation of a "masterpage" in HTML is not possible. – Kashif Mustafa Sep 21 '15 at 10:06
  • Yes I know this, I was assuming because you suggested using a master page - "Make a master page and initialize app once. This is your problem in your provided code." you knew something I didn't. – notAChance Sep 21 '15 at 13:06
  • Pretty condescending and completely devoid of any effort to answer the specific question by copy-pasting a service tute. – Nick Mitchell Oct 08 '15 at 00:07
0

The reason you are getting zero is that you controller is assigning to value of myService.getTotal() only when it is loading. That means that when you change the total variable it won't be updated.

You need to $watch for the updates:

$scope.$watch(function () {
    return myService.getTotal();
}, function (newVal) {
    $scope.total = newVal;
});

Besides, it looks like you are re initializing your app with new pages. This is not how angular works. Read about angular route and then try to do what I suggested here. It should work if you make it a single page app.

Jahongir Rahmonov
  • 13,083
  • 10
  • 47
  • 91
  • I've created a second app for my popup window. I then pass my main application "app" as a dependency and reference my service which is in my main app and which provides access to my data. I don't see how route would benefit this. It simply won't be a SPA. It is imperative that I use popups as my users need multiple accounts open and need to change data between windows dynamically. – notAChance Sep 21 '15 at 15:13
0

I did find a solution to my initial question, which was to use localStorage.setItem("num", "num") to store the data in the browser. It seems this was developed specifically to share data between tabs/windows, and so is accessible via localStorage.getItem("num").

This answers my original question, however I would now like the total to be updated dynamically. At the moment it is only updated upon refresh. Any tips would be appreciated.


EDIT (ANSWER TO ABOVE)

By using this event listener in my second popup -

window.addEventListener('storage', function (event) {
        $scope.total = parseInt(event.newValue);
        $scope.$apply();
    });

I was able to access the storage and bind it to an expression in my HTML. Bear in mind $scope.apply() needs to be called here because total is outside of the scope.

More detail here - https://developer.apple.com/library/safari/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Name-ValueStorage/Name-ValueStorage.html

notAChance
  • 1,360
  • 4
  • 15
  • 47