0

I have the the following two dimensional array:

 SideNavItems= [["Parent Section 1", "Parent Section 2"],["Parent Section 3", "Parent Section 4"]]

I want to use ng-repeat to display them the following way on a page that has tabbed navigation:

Desired output:

When first tab is selected:

Parent Section 1
Parent Section 2

When second tab is selected:

Parent Section 3
Parent Section 4

Current output:

When first tab is selected:

Parent Section 1
Parent Section 2
Parent Section 3
Parent Section 4

I have a $index variable that changes based on what tab is selected. Can I set it so that only the contents of the first array(element 0 of the 2D array) are repeated when the index is 0, the contents of the second array(element 1 of the 2D array) are repeated when the index is 1, and so on if the 2D array had more elements?

Here is the html I have for repeating the arrays:

            <div id="field">
                    <div ng-repeat="row in SideNavItems">
                        <div ng-repeat="cell in row" >                  
                                <a ng-click="level=2">{{cell}}</a>

                        </div>
                    </div>
            </div>

and I don't know if this will be very relevant but here is the HTML for the tabs. The getClass methods giving active classes that change the tabs appearance in CSS. The toggleSelect method changes the current index to the active tab.

<nav>
    <ul>   
           <li ng-class="getClass($index)" ng-repeat="tab in tabs">
                <a ng-click="toggleSelect($index)" ng-class="getLinkClass($index)">{{tab}}</a>
           </li>
    </ul>
</nav>

I have similar arrays with the child sections for each of these parent sections and hope to do the same thing if there is a way to make this work. I guess I would need another variable to act as a second index though...

***EDIT 2/3/15 2:00PM

Using your advice, I was able to get my desired output. I am now trying to get similar functionality for the children of these parent sections and it seems a bit more complicated. I actually have a 3D array:

 [
   [[Parent1Child1, Parent1Child2],[Parent2Child1, Parent2Child2, Parent2Child3]],
   [[Parent3Child1, Parent3Child2],[Parent4Child1, Parent4Child2, Parent4Child3]]
 ]

Desired Output: When first tab is selected:

Parent Section 1
  Parent1Child1
  Parent1Child2

Parent Section 2
  Parent2Child1
  Parent2Child2
  Parent2Child3

When second tab is selected:

Parent Section 3
  Parent3Child1
  Parent3Child2

Parent Section 4
  Parent4Child1
  Parent4Child2
  Parent4Child3

Each section will eventually be an collapsable/expandable accordion and that's what I started coding toward but maybe I need to back up and work on it spitting out the desired input shown above, and then I can play around with ng-click showing/hiding the correct content for the expand/collapse functionality. He is what I have so far and it seems to be close. I describe the output after the code.

toggleSelect code:

 //gets tab tiles order from csv
    $scope.tabs= tabsService.mainTabs;  

    //Assigns active classes to main tabbed navigation
    $scope.selectedIndex = 0;
    $scope.sideNavItems = productCategoryService.sideNavItems;
    $scope.sideNavChildren = productCategoryService.sideNavChildren;
    $scope.toggleSelect = function(ind){
            $scope.selectedIndex = ind;

            $scope.currentTabSideNavItems = $scope.sideNavItems[ind];

            $scope.selectedChildIndex = 0;
            $scope.toggleChildIndex = function(childIndex){
            $scope.selectedChildIndex = childIndex;

             $scope.currentSideNavChildren = $scope.sideNavChildren[ind][childIndex];
            }
    }

HTML

 <div id="field">
                <div ng-repeat="item in currentTabSideNavItems">
                    <a ng-click="toggleChildIndex($index)">{{item}}</a>
                        <div ng-repeat="child in currentSideNavChildren">
                            <a ng-click="toggleChildIndex($index)">{{child}}</a>
                        </div>
                </div>
  </div>     

With this code, I get the proper children appearing as I click on the corresponding Parent Section header, but the children appear under all the parent sections on the current page. For example:

When first tab is selected and I click on Parent Section 1:

Parent Section 1
  Parent1Child1
  Parent1Child2

Parent Section 2
  Parent1Child1
  Parent1Child2

When first tab is selected and I click on Parent Section 2:

Parent Section 1
  Parent2Child1
  Parent2Child2
  Parent2Child3

Parent Section 2
  Parent2Child1
  Parent2Child2
  Parent2Child3

Am I over complicating things again? How might I work toward getting the proper children with their parents? Thank you so much for your time it is very appreciated.

user95227
  • 1,853
  • 2
  • 18
  • 36
  • In my opinion, you are going to something far too complicated. Instead of all that arrays, can't you just use json objects? – Patrick Ferreira Feb 04 '15 at 09:45
  • @PatrickFerreira I'm currently using [jquery-csv](https://code.google.com/p/jquery-csv/) to read csv files that are stored in the app data folder as arrays. So I have an array for every level of the app that contains the sections at each level. At first it wasn't difficult use arrays like tab1SideNavItems(with all the parent sections for tab1) and tab1SideNavItem1Children(with the child sections of tab1 section1) to "hard code" these tabs and sections. I started putting these arrays in arrays so that I could have a loop create whatever sections are listed on the csv, which can change. – user95227 Feb 04 '15 at 13:08
  • @PatrickFerreira reached character cap on the last comment but here's a bit more info. The backend of the app updates the app.data folder on the users machine to have a specific folder structure with all of the app's content inside. The front end uses the csv files in these folders to navigate this folder structure and know the proper order to display content. – user95227 Feb 04 '15 at 13:25

2 Answers2

3

In my opinion, you really want to keep this out of the UI and hide it away in the controller. You already have an action called toggleSelect in your controller by the looks of things, inside that you can set a new scope property to be only the side nav items of the currently selected tab, something like;

$scope.toggleSelect = function(index) {
  // existing code here

  $scope.currentTabSideNavItems = SideNavItems[index];
}

And your markup can be simplified to:

<div id="field">
    <div ng-repeat="item in currentTabSideNavItems">
        <a ng-click="level=2">{{item}}</a>
    </div>
</div>

That way the logic for extracting out the items to be displayed is hidden nicely in your controller, and can be tested.

DoctorMick
  • 6,703
  • 28
  • 26
  • it's my first time using AngularJS and the project is starting to get complex. I'm trying to stay on top of best practices so I really appreciate this insight. I'll look into changing things up and maybe post back after lunch. Thanks! – user95227 Feb 03 '15 at 15:59
  • thanks again! Your help worked, but now I'm trying to get the sub-sections working correctly. Please check out my edit if you have any time. – user95227 Feb 03 '15 at 19:08
1

As @DoctorMick said, it's better to "separate logic from view" I made a snippet on jsfiddle with your needs, hope this helps.

<section ng-app="App" ng-controller="Ctrl">
    <nav>
        <ul>
            <li ng-repeat="tab in tabs" ng-click="updateSideNavItems($index)" ng-class="{active: $index === currentIndex}"> <a>{{tab}}</a>

            </li>
        </ul>
    </nav>
    <div id="field">
        <div ng-repeat="cell in SideNavItems">
          {{cell}}    
        </div>
    </div>
</section>
var app = angular.module('App', []);

app.controller('Ctrl', function ($scope) {
    var SideNavItems = [
        ["Parent Section 1", "Parent Section 2"],
        ["Parent Section 3", "Parent Section 4"]
    ];
    $scope.tabs = ['tab1', 'tab2', 'tab3'];

    $scope.updateSideNavItems = function updateSideNavItems(index) {
        $scope.currentIndex = index;
        if (index === 0) $scope.SideNavItems = SideNavItems[0];
        else if (index === 1) $scope.SideNavItems = SideNavItems[1];
        else $scope.SideNavItems = [].concat.apply([], SideNavItems);
    }

    // defaults
    $scope.currentIndex = 0;
    $scope.updateSideNavItems($scope.currentIndex);
});
Patrick Ferreira
  • 1,983
  • 1
  • 15
  • 31
  • Thank you so much I used your guys' advice and got the parent sections displaying correctly. Please look at my edit and see if you have any ideas for the children. Thank you so much for the js.fiddle it really helped! – user95227 Feb 03 '15 at 19:10
  • I just fork my previous [fiddle](http://jsfiddle.net/optyler/sz2vnj6q/1/) to match your need in another way... as I said, 3D arrays for that kind of work are too complex I think. If someone, or you, need to maintain the code next year... nobody will know how this works :-p BTW, if you want to create "views" for your single page app, you should better use [angular-ui/ui-router](https://github.com/angular-ui/ui-router) – Patrick Ferreira Feb 04 '15 at 11:13
  • thank you again so much for the help. I've tried to adjust your new fiddle to have multiple parent sections under each tab (like your original fiddle) but have been unsuccessful. Can this be achieved? Sorry to bug you so much, but thanks for sacrificing your time. – user95227 Feb 04 '15 at 14:03