Solution 1 :

You will need to setup parent and child controller for them to access $scope object.

<div ng-controller="UserTasksCtrl">


    <!-- Tabs for Nav -->
    <ul class="nav nav-tabs">
        <li class="nav-item" id="headingTasks" ng-class="{ 'active': vm.tabTasks }">
            <a data-target="#tabTasks" data-toggle="tab" class="nav-link pt-1 pr-2 pb-1 pl-2"
               ng-class="{ 'active': vm.tabTasks }"
               ng-click="vm.loadTasks()">Tasks</a>
        </li>
        <li class="nav-item" id="headingAddEditTask" ng-class="{ 'active': vm.tabAddEditTasks }" ng-if="vm.tabAddEditTasks">
            <a data-target="#tabAddEditTasks" data-toggle="tab" class="nav-link pt-1 pr-2 pb-1 pl-2"
               ng-class="{ 'active': vm.tabAddEditTasks }">{{vm.addEditText}} <span ng-if="(vm.addEditUnsaved)" style="font-size: 85%;"><i class="fa fa-fw fa-warning text-warning"></i></span></a>
        </li>
    </ul>
    
    
    <div ng-controller="JobsCtrl">

        <!-- Tabs content -->
        <div class="tab-content">
            <!--Tasks-->
            <div id="tabTasks" class="tab-pane fade show tab-pane-bordered" ng-class="{ 'active show': vm.tabTasks}">
                <div class="row p-1 m-0">
                    <div class="col-12 p-0 m-0">
                        <div ng-include="vm.pageTasks"></div>
                    </div>
                </div>
            </div>

            <!--Add/Edit Task-->
            <div id="tabAddEditTasks" class="tab-pane fade show tab-pane-bordered" ng-class="{ 'active show': vm.tabAddEditTasks }">
                <div class="row p-1 m-0">
                    <div class="col-12 p-0 m-0">
                        <div ng-include="vm.pageAddEditTask"></div>
                    </div>
                </div>
            </div>
        </div>  
    
    </div>
</div>

Solution 2 :

It turns out that accessing a nested $parent within $parent was the key I needed. In the child controller, I passed in $scope into the init() as a parameter (e.g. init($scope), and then I set a vm.variable equal to that parameter (in this instance, ‘scope’) as such: vm.rootScope = scope.$parent.$parent.vm;. This gave me full access to everything declared in the parent controller, including functions, and allowed me to change the tabs.

Problem :

I have an AngularJs page with tabs in the UI. Each tab loads different data. One of these is a list of tasks for a user. The user can search on this tab for various tasks, and when they find one, they can click on it, and it will bring up an edit form for that task on another tab.

I can’t figure out how to show that other tab, since the tab selection resides in the parent controller (the main page), and the tabs all have their own child controllers.

Parent controller:

"use strict";

angular
.module("userTasks.controllers", [])

.controller("UserTasksCtrl",
    ["$scope", "$window", "$uibModal", "$filter", "$location", "$routeParams", "api",
    function($scope, $window, $uibModal, $filter, $location, $routeParams, api) {
        var vm = this;
        vm.activeTab = "Tasks";

        vm.loadTaskList = (
            function() {
                vm.pageTaskList = "/Content/UserTasks/taskList.html";
            }
        );

        vm.loadAddEditTask = (
            function() {
                vm.pageAddEditTask = "/Content/UserTasks/tasksAddEdit.html";
            }
        );

        vm.doTabRouting = (
            function() {
                switch (vm.activeTab) {
                    case "Tasks":
                        vm.tabTasks = true;
                        vm.loadTasks();
                        break;
                    case "CreateTask":
                        vm.tabAddEditTask = true;
                        vm.loadAddEditTask();
                        break;
                    default:
                        vm.tabDetails = true;
                        vm.loadDetails();
                        break;
                }
            }
        );
    }
]);

Child controler:

"use strict";

angular
.module("userTasks.controllers_Tasks", [])

.controller("TasksCtrl",
    ["$scope", "$routeParams", "$filter", "$uibModal", "$uibModalStack", "taskAPI",
    function ($scope, $routeParams, $filter, $uibModal, $uibModalStack, taskAPI) {
        var vm = this;

        vm.openTaskAddEdit = (
            function(task) {
                vm.root.task= {
                    Id: task.Id
                };

                vm.root.tabTasks        = false;
                vm.root.tabAddEditTask  = true;

                vm.root.activeTab       = "CreateTask";
                vm.root.pageAddEditJob  = "/Content/UserTasks/taskAddEdit.html";
                vm.root.tab             = "CreateTask";
            }
        );
    }
]);

The index.html (parent page) with the tabs:

    <!-- Tabs for Nav -->
    <ul class="nav nav-tabs">
        <li class="nav-item" id="headingTasks" ng-class="{ 'active': vm.tabTasks }">
            <a data-target="#tabTasks" data-toggle="tab" class="nav-link pt-1 pr-2 pb-1 pl-2"
               ng-class="{ 'active': vm.tabTasks }"
               ng-click="vm.loadTasks()">Tasks</a>
        </li>
        <li class="nav-item" id="headingAddEditTask" ng-class="{ 'active': vm.tabAddEditTasks }" ng-if="vm.tabAddEditTasks">
            <a data-target="#tabAddEditTasks" data-toggle="tab" class="nav-link pt-1 pr-2 pb-1 pl-2"
               ng-class="{ 'active': vm.tabAddEditTasks }">{{vm.addEditText}} <span ng-if="(vm.addEditUnsaved)" style="font-size: 85%;"><i class="fa fa-fw fa-warning text-warning"></i></span></a>
        </li>
    </ul>

    <!-- Tabs content -->
    <div class="tab-content">
        <!--Tasks-->
        <div id="tabTasks" class="tab-pane fade show tab-pane-bordered" ng-class="{ 'active show': vm.tabTasks}">
            <div class="row p-1 m-0">
                <div class="col-12 p-0 m-0">
                    <div ng-include="vm.pageTasks"></div>
                </div>
            </div>
        </div>

        <!--Add/Edit Task-->
        <div id="tabAddEditTasks" class="tab-pane fade show tab-pane-bordered" ng-class="{ 'active show': vm.tabAddEditTasks }">
            <div class="row p-1 m-0">
                <div class="col-12 p-0 m-0">
                    <div ng-include="vm.pageAddEditTask"></div>
                </div>
            </div>
        </div>
    </div>

I want to be able to call vm.openTaskAddEdit(task) from the task list tab, and have it open the task add/edit tab and load that data. And in theory, the way to do that is to call the main, parent, controller, after setting the parent scope’s variables, and fire off the doTabRouting() method. I’m able to set the variables the doTabRouting() uses, but I can’t actually trigger the method.

I’ve tried accessing it through $scope, but when I get into vm.openTaskAddEdit(), I get the awesome error of “$scope is not defined”.

Comments

Comment posted by PKD

I do have parent and child controllers set up. The main (parent) controller contains the tabs, and in normal navigation clicking on a tab loads the child controller in an ng-include. The contents of each tab are ng-includes with their own controllers. I’m even passing all of the scoped variables of the parent controller to the child controllers (that’s the “vm.root” you see in my code). I just can’t access the actual parent $scope, which is what I need to be able to do to call the vm.doRouting() method.

By