Sidemenu scope

I’m trying to build a todo list app. I can’t access a variable in my sidemenu. Any ideas why?
index.html

  <body ng-app="IonicFirebaseTodoApp">
    <ion-side-menus>

      <ion-side-menu-content ng-controller="ContentController">
        <ng-include src="'templates/centercontent.html'"></ng-include>
      </ion-side-menu-content>

      <!-- Left menu -->
      <ion-side-menu side="left">
        <ng-include src="'templates/sidemenu.html'"></ng-include>
      </ion-side-menu>

      <!-- Right menu -->
      <ion-side-menu side="right">
      </ion-side-menu>
    </ion-side-menus>
</body>

app.js

'use strict';
// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
var app = angular.module('IonicFirebaseTodoApp', ['ionic', 'firebase']);

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

content-controller.js

'use strict';

app.controller('ContentController', function($scope,
                                             $ionicModal,
                                             Projects,
                                             $firebase,
                                             $ionicLoading,
                                             $ionicSideMenuDelegate) {

  // Load projects
  var projectsUrl = 'https://ionic-guide-harry.firebaseio.com/projects/';
  var projectRef = new Firebase(projectsUrl);
  var firebaseKeyRegEx = /^-[A-Za-z0-9]{19}$/;

  // 3-way bind projects variable
  $scope.projects = $firebase(projectRef);

  $scope.showLoading = function() {
    $scope.loading = $ionicLoading.show({
      content: 'Loading',
      animation: 'fade-in',
      showBackdrop: true,
      maxWidth: 200,
      showDelay: 500
    });
  };
  $scope.hideLoading = function(){
    $scope.loading.hide();
  };
  $scope.showLoading();

  // tasks that need to be run once projects are loaded
  // select project from localstorage if present
  $scope.projects.$on('loaded', function() {
    $scope.hideLoading();
    $scope.projectKeys = $scope.projects.$getIndex();
    $scope.lastActiveProjectKey = Projects.getLastActiveKey();
    if (firebaseKeyRegEx.test($scope.lastActiveProjectKey)) {
      $scope.selectProject($scope.lastActiveProjectKey);
    } else {
      $scope.selectProject($scope.projectKeys[0]);
    }
    console.log($scope.projectKeys);
  });

  // utility function for creating a new project with the given projectTitle
  var createProject = function(projectTitle) {
    var newProject = Projects.newProject(projectTitle);

    // store project to firebase projects, upon success make it active project
    $scope.projects.$add(newProject).then( function(ref) {
      $scope.selectProject(ref.name());
    });
  };

  // Trigger modal for a new project
  $scope.newProject = function() {
    var projectTitle = prompt('Project name');
    if(projectTitle) {
      createProject(projectTitle);
    }
  };

  // Selects the given project by it's firebase key
  $scope.selectProject = function(key) {
    $scope.activeProject = $scope.projects.$child(key);
    $scope.activeTasks = $scope.activeProject.$child('tasks');
    $scope.taskKeys = $scope.activeTasks.$getIndex();
    Projects.setLastActiveKey(key);
    //TODO figure what this was doing
    //$scope.sideMenuController.close();
  };

  // Create our modal
  $ionicModal.fromTemplateUrl('templates/newtaskmodal.html', function(modal) {
    $scope.taskModal = modal;
  }, {
    scope: $scope
  });

  $scope.createTask = function(task) {
    if(!$scope.activeProject || !task) {
      return;
    }
    $scope.activeTasks.$add({
      title: task.title,
      finished: false
    }).then(function(/*ref*/) {
      $scope.activeTasks = $scope.activeProject.$child('tasks');
      $scope.taskKeys = $scope.activeTasks.$getIndex();
      $scope.hideLoading();
    });
    $scope.taskModal.hide();
    $scope.showLoading();

    // reset task title
    task.title = '';
  };

  $scope.newTask = function() {
    $scope.taskModal.show();
  };

  $scope.closeNewTask = function() {
    $scope.taskModal.hide();
  };

  $scope.toggleProjects = function() {
    //$scope.sideMenuController.toggleLeft();
    $ionicSideMenuDelegate.toggleLeft();
  };

  $scope.toggleTask = function(key) {
    var taskFinishedRef = $scope.activeTasks.$child(key).$child('finished');
    console.log(taskFinishedRef);
    taskFinishedRef.on('value', function(snapshot) {
      console.log(snapshot.val());
    });
    if($scope.activeTasks.$child(key).finished) {
      console.log($scope.activeTasks.$child(key));
      $scope.activeTasks.$child(key).finished = !$scope.activeTasks.$child(key).finished;
    } else {
      $scope.activeTasks.$child(key).finished = 'true';
    }
    console.log($scope.activeTasks.$child(key).finished);
  };

});

centercontent.html

<ion-pane>
  <ion-header-bar class="bar-dark">
    <button menu-toggle="left" class="button button-icon icon ion-navicon"></button>
    <h1 class="title">Todo App</h1>
    <button class="button button-icon icon ion-compose" ng-click="newTask()"></button>
  </ion-header-bar>
  <ion-content>
    <ul class="list">
      <li ng-repeat="key in taskKeys"
          ng-click="toggleTask(key)"
          ng-class="{active: activeTasks[key].finished === true}">
        <ion-checkbox ng-model="isChecked">{{ activeTasks[key].title }}</ion-checkbox>
      </li>
    </ul>
  </ion-content>
</ion-pane>

sidemenu.html

<ion-pane>
<header class="bar bar-header bar-dark">
  <h1 class="title">Projects</h1>
  <button class="button button-icon" ng-click="newProject()">
    <i class="icon ion-plus"></i>
  </button>
</header>
<ion-content>
{{ projectKeys}}
  <ul class="list">
    <li ng-repeat="key in projectKeys"
        ng-click="selectProject(key)"
        ng-class="{active: activeProject === project}">
        test
      {{ projects[key].title }}
    </li>
  </ul>
</ion-content>
</ion-pane>

In centercontent.html I can access $scope variables. But in sidemenu.html I can’t. I want to access $scope.projectKeys

1 Like

I’m pretty sure it’s because ng-controller is placed on the center content. If I put it on <ion-side-menus> instead how do I make the variables available to all sub views?

1 Like

I’ve done more research and I think the controller needs to encapsulate both views

  <body ng-app="IonicFirebaseTodoApp">
    <ion-side-menus ng-controller="ContentController">

      <ion-side-menu-content>
        <ng-include src="'templates/centercontent.html'"></ng-include>
      </ion-side-menu-content>

      <!-- Left menu -->
      <ion-side-menu side="left">
        <ng-include src="'templates/sidemenu.html'"></ng-include>
      </ion-side-menu>

      <!-- Right menu -->
      <ion-side-menu side="right">
      </ion-side-menu>
    </ion-side-menus>
</body>

now how do I access ContentController variables from the templates?

I put my side-menu functions in the rootScope, as you can inject + access that in regular controllers, but not a third controller. I’m not sure if there’s an easier way to do it or not.

So I’d call $rootScope.projectKeys = blah in my main controller, then access it via key in root.projectKeys in the template.

Let me know if it works for you :smile:

Kevin

I’m posting this answer, hoping that someone may find it useful. I ran into a similar issue wherein code was a lot similar to one shown above. All I did was passed the $rootScope to my sidemenu controller and reassigned it to $scope there initially. Everything started working thereon! Something like below:

'use strict';app.controller('ContentController', function($scope, $rootScope,
                                             $ionicModal,
                                             Projects,
                                             $firebase,
                                             $ionicLoading,
                                             $ionicSideMenuDelegate) {
$scope = $rootScope;
//do your further processing here
1 Like

You might as well keep using rootscope. All you did is assign variable ‘scope’ to rootscope, meaning everything bound to scope is bound to rootscope