Search code examples
javascriptangularjscordovaonsen-ui

Passing data between controllers in OnsenUI+AngularJS+PhoneGap


I found similar questions to mine being asked, and answered, but I think my scenario is different. I started from the sample code here enter link description here for a simple app with a sliding menu that uses Google Maps.

I am creating a prototype that lets users submit new items that are added to a list of pending items, and then added to the map. I am now concentrating on the first part - letting users create items, and updating the list of pending submissions automatically. I then added a simple form to create new item:

<ons-page>
    <ons-toolbar fixed-style ng-controller="SlidingMenuController">
        <div class="left">
            <ons-toolbar-button ng-click="slidingMenu.toggleMenu()"><ons-icon icon="bars"></ons-icon></ons-toolbar-button>
        </div>
        <div class="center">New Submission</div>
    </ons-toolbar>
    <ons-row style="margin-top: 10px; text-align: center;">
        <ons-col ng-controller="NewSubmissionController">
            <p style="font-size: 12px;">Please insert a brief description of your find and its material.</p>
             <textarea style="width: 97%;" id="subDescrText" class="textarea" rows="4" placeholder="Type your description here..." value="" ng-model="subDescription"></textarea>
        <ons-button style="margin-top: 24px;" ng-click="doStore()">
            Store
        </ons-button>
        </ons-col>
    </ons-row>
</ons-page>

And another page to list the created submissions:

<ons-page>
    <ons-toolbar>
        <div class="left">
            <ons-toolbar-button ng-click="slidingMenu.toggleMenu()"><ons-icon icon="bars"></ons-icon></ons-toolbar-button>
        </div>
        <div class="center">Pending Submissions</div>
    </ons-toolbar>
    <div style="text-align: center;">
        <ons-list id="pendingList" var="aPendingList" ng-controller="PendingListController">
            <ons-list-item ng-repeat="pi in pendingItems">
                <p>{{pi.description}}</p>
                <span>{{pi.material}}</span>
            </ons-list-item>
        </ons-list>
    </div>div>
    <p style="margin-top: 12px; text-align: center; width: 100%;" >
        <ons-button ng-click="">
            Upload All
        </ons-button>
    </p>
</ons-page>

I then added these controllers:

app.controller('NewSubmissionController', function($scope) {
    $scope.selMat;
    $scope.subDescription;

    $scope.doStore = function() {
        alert('In NewSubmissionController.doStore() - Sel material: ' + $scope.selMat + '\nDescr: ' + $scope.subDescription);

        var newPI = new SubmissionItem($scope.selMat, $scope.subDescription, '');
        $scope.$emit('newPI', newPI);
        slidingMenu.setMainPage('pendingList.html', {closeMenu: true});
    };

});

// Pending list controller
app.controller('PendingListController', function($scope) {
    $scope.pendingItems = [];
    $scope.$on('newSubEvent', function(e, subMat, descr) {
        alert('In PendingListController, event newSubEvent - sub mat: ' + subMat + '\nDescription: ' + descr);
    });

    $scope.addPendingItem = function(newPi) {
        alert('In PendingListController.addPendingItem() - ' + newPi);
        $scope.pendingItems.unshift(newPi);
        // Some code here to update the list of pending submissions...
    };
});

In this version I had tried to use the event system as suggested by other replies here. Unfortunately it doesn't work, because the two controller are not child and parent. Moving PendingListController inside NewSubmissionController doesn't work either, and I reckon it's because the two controllers are on two different views.

What is the best solution to call PendingListController.addPendingItem() from NewSubmissionController?


Solution

  • As you are using multiple pages which require Multiple Pages Managing Pattern.

    So from there, you have the choices to add a main controller for the main navigation page (in your case, that would be sliding menu page), so then you can share the $rootScope among the child controllers.

    It's advisable to use Dependency Injection as your solution, you can use service or factory to help "passing/sharing" your data between controllers.

    Demo code below shows:

    • how you can utilise Service to let controllers communicate
    • how is $rootScope can be used to live update data

    Using service to share data between controllers

    angular.module('app', [])
      .service('mainService', function($http) {
        var self = this;
        self.userList = [];
    
        self.login = function(newUser) {
          self.userList.push(newUser + ' ' + (self.userList.length + 1));
          return self.userList;
        };
      })
    
    .controller('MainCtrl', function($rootScope, $scope, mainService) {
    
      $scope.mainAddUser = function() {
        $rootScope.users = mainService.login('Main');
      };
    })
    
    .controller('LoginCtrl', function($rootScope, $scope, mainService) {
      $scope.loginAddUser = function() {
        $rootScope.users = mainService.login('Login');
      };
    });
    

    Demo http://plnkr.co/edit/OvG0oj6EmDU5GMi1eBaU?p=preview