0

I'm new to Angular but enjoying getting to know it! I'm having no problem populating data but I'm stuck on this navigational problem.

I have a sidebar divided into two navigation s. Both are reading from nested JSON of 'areas' and 'reports'. The idea is that the currently selected/clicked item in the left hand list will populate the elements in the right hand list, according to its children in the JSON.

I've got the initial population working fine. It reads the 'areas' and assigns the active area, which displays the reports. I then have a directive which applies css classes on the click event, but how can I get it to also alter the active area?

I'm currently doing scope.activeArea = scope.areas[1];, but this does not work. The index is just there for development; that will be replaced by the index of the clicked element.

My HTML:

<div id="reports-subnav" ng-controller="reportAreasController">
    <ul class="subnav-areas" >
        <li ng-repeat="x in areas">
            <a class="subnav-area-button" href="#" my-cool-directive>
                <i class="{{ x.iconClass }}"></i>
            </a>
        </li>        
    </ul>


    <ul id="nav-subsection" class="subnav-reports">

        <li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><a href="<?php echo SITE_ADDR; ?>/{{ r.controller }}/{{ r.action }}"><span class="{{ r.iconClass }}"></span> {{ r.name }}</a></li>

    </ul>

</div>

And Javascript:

var app = angular.module("focalWeb", []); 

app.controller("reportAreasController", ['$scope','$http', function($scope, $http) { 

    $http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){ 

        $scope.areas = data.areas;
        $scope.activeArea = $scope.areas[0];

    });

}] );

app.directive("myCoolDirective", function() {
    return {
        restrict: "A",
        link: function(scope, elem, attrs) {
            $(elem).click(function() {
                //var target = $(elem).next(".panel-collapse");
                //target.hasClass("collapse") ? target.collapse("show") : target.collapse("hide");
                $('.subnav-areas li').removeClass('active');
                $(this).parent().addClass('active');
                scope.activeArea = scope.areas[1];
            });
        }
    }
});

Thanks!

Edit

Thanks to charlietfl's guidance my code now looks like this:

HTML

<div id="reports-subnav" ng-controller="reportAreasController">
    <ul class="subnav-areas" >
        <li class="subnav-area" ng-repeat="x in areas">
            <a class="subnav-area-button" href="#" ng-click="showReports($event, x.id)">
                <i class="{{ x.iconClass }}"></i>
            </a>
        </li>        
    </ul>


    <ul id="nav-subsection" class="subnav-reports">

        <li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><a href="<?php echo SITE_ADDR; ?>/{{ r.controller }}/{{ r.action }}"><span class="{{ r.iconClass }}"></span> {{ r.name }}</a></li>

    </ul>

</div>

JS

var app = angular.module("focalWeb", []); 

app.controller("reportAreasController", ['$scope','$http', function($scope, $http) { 

    $http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){ 

        $scope.areas = data.areas;
        $scope.activeArea = $scope.areas[0];

        $scope.showReports = function($event, index) {
            $scope.activeArea = $scope.areas[index -1];
            var theLi = angular.element($event.currentTarget).parent();
            theLi.parent().find('li').removeClass('active');
            theLi.addClass('active');
        }

    });

}] );

Edit 2

HTML

<div id="reports-subnav" ng-controller="reportAreasController">
    <ul class="subnav-areas" >
        <li class="subnav-area" ng-repeat="x in areas" ng-class="{active: x==activeArea}">
            <a class="subnav-area-button" href="#" ng-click="showReports($event, x)">
                <i class="{{ x.iconClass }}"></i>
            </a>
        </li>        
    </ul>


    <ul id="nav-subsection" class="subnav-reports">

        <li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><a href="<?php echo SITE_ADDR; ?>/{{ r.controller }}/{{ r.action }}"><span class="{{ r.iconClass }}"></span> {{ r.name }}</a></li>

    </ul>

</div>

JS

var app = angular.module("focalWeb", []); 

app.controller("reportAreasController", ['$scope','$http', function($scope, $http) { 

    $http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){ 

        $scope.areas = data.areas;
        $scope.activeArea = $scope.areas[0];

        $scope.showReports = function($event, item) {
            $scope.activeArea = item;
        }

    });

}] );

Thanks again charlietfl!

SimonDunne
  • 32
  • 1
  • 8
  • your event handler is changing scope from outside angular context. Any scope changes outside angular need to notify angular to run a digest. Get rid of jQuery.js and focus on using built in directives like `ng-click` and `ng-class` for things like this – charlietfl Sep 15 '16 at 12:43
  • Strongly suggest reading [thinking-in-angularjs-if-i-have-a-jquery-background](http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background) – charlietfl Sep 15 '16 at 12:44
  • @charlietfl Thanks very much - that's helped me understand a lot better. I've posted edited code. – SimonDunne Sep 15 '16 at 14:04
  • get in habit of passing whole object into functions...not just the id. Makes it much easier for many operations. Still trying to do dom manipulation though...there should never be any `angular.element` or any dom reference in a controller. Think of changing data model properties first...and let that drive the view. – charlietfl Sep 15 '16 at 14:06
  • inside function for example `$scope.showReports = function($event, item) {$scope.activeItem =item...` ...then can use `ng-class="{active: x==activeItem]'` – charlietfl Sep 15 '16 at 14:11
  • @charlietfl That is so simple - works a charm. Thanks so much! – SimonDunne Sep 15 '16 at 14:17
  • most important takeaway from that link i gave you is to always think of the data model first – charlietfl Sep 15 '16 at 14:23

0 Answers0