Matthew Scerri
Matthew Scerri

Reputation: 325

Angular scope nesting in ui bootsrap tab containing pagination

I've come across an issue with angular and ui-bootstrap which I'm not sure I have an elegant solution for.

I have a UI Bootstrap tabset, with one tab containing a table with a UI Bootstrap pagination template.

Since each tab seems to have a scope of its own, the table row (with ng-repeat) must reference the $parent.test as a data source rather than the variable name directly.

As such, I'm not sure if this is the best solution, even if it seems to work perfectly fine? what if you have more nested scopes? Would you need to call $parent.$parent.$parent.test to access the data in your main controller scope?

Thanks

var testApp = angular.module('testApp', ['ui.bootstrap','testControllers']);
var testdata = 
[{'number': '1', 'name': 'A' }
,{'number': '2', 'name': 'B' }
,{'number': '3', 'name': 'C' }
,{'number': '4', 'name': 'D' }
,{'number': '5', 'name': 'E' }
,{'number': '6', 'name': 'F' }];

var testControllers = angular.module('testControllers', []);

testControllers.controller('TestListController', function($scope){
    $scope.totalItems = 6;
    $scope.page = 1;
    $scope.itemsPerPage = 2;
    $scope.getData = function () {
        $scope.test = [testdata[$scope.page*2-2],testdata[$scope.page*2-1]];
    };
    $scope.getData();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script>
<div ng-app="testApp">
<div ng-controller='TestListController'>
    <tabset>
        <tab><tab-heading>Tab 1</tab-heading>
		<table>
        <thead>
            <tr>
                <th>Item</th>
                <th>Name</th>
            </tr>
        </thead>
    
        <tbody>
            <tr ng-repeat="item in $parent.test">
                <td>
                    {{item.number}}
                </td>
                <td>
                    {{item.name}}
                </td>
            </tr>
        </tbody>
    </table>
	<pagination 
		total-items="$parent.totalItems" 
		ng-model="$parent.page" 
		max-size="5" 
		boundary-links="true" 
		ng-change="$parent.getData()" 
		items-per-page="$parent.itemsPerPage" 
		previous-text="<" next-text=">" 
		first-text="<<" last-text=">>">
	</pagination>
	</tab>
    </tabset>
</div>
</div>

Upvotes: 1

Views: 1113

Answers (1)

Richard Vella
Richard Vella

Reputation: 186

The issue is that you are not keeping a reference to the original "this" context in the $scope.getData() function call. Have a look at the code below:

I also suggest you read through this article: Getting Out of Binding Situations in JavaScript

<!DOCTYPE html>
<html lang="en">
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script> 
        <meta charset="UTF-8">
        <title>Document</title>

        <script>
            var testApp = angular.module('testApp', ['ui.bootstrap','testControllers']);

            var testdata =
                [{'number': '1', 'name': 'A' }
                ,{'number': '2', 'name': 'B' }
                ,{'number': '3', 'name': 'C' }
                ,{'number': '4', 'name': 'D' }
                ,{'number': '5', 'name': 'E' }
                ,{'number': '6', 'name': 'F' }];


            var testControllers = angular.module('testControllers', []);

            testControllers.controller('TestListController', function($scope){

            // Pagination
            $scope.total = testdata.length;
            $scope.maxSize = 10;
            $scope.currentPage = 1;
            $scope.numPerPage = 2;

            $scope.getData = function () {

                // keep a reference to the current instance "this" as the context is changing
                var self = this;
                console.log(self.currentPage);
                var itemsPerPage = self.numPerPage; 
                var offset = (self.currentPage-1) * itemsPerPage;
                $scope.test = testdata.slice(offset, offset + itemsPerPage)

            };

            $scope.getData();
        });


        </script>
    </head>
    <body>

        <div ng-app="testApp">
            <div ng-controller='TestListController'>
                <tabset>
                <tab><tab-heading>Tab 1</tab-heading>
                    <table>
                        <thead>
                            <tr>
                                <th>Item</th>
                                <th>Name</th>
                            </tr>
                        </thead>

                        <tbody>
                            <tr ng-repeat="item in test">
                                <td>{{item.number}}</td><td>{{item.name}}</td>
                            </tr>
                        </tbody>
                    </table>
                    <pagination
                        total-items="total" 
                        ng-model="currentPage"
                        max-size="maxSize"
                        boundary-links="true"
                        ng-change="getData()"
                        items-per-page="numPerPage"
                        previous-text="<" next-text=">"
                        first-text="<<" last-text=">>">
                    </pagination>
                    <div>
                        Page: {{currentPage}}<br/>
                        Total Items: {{total}}                          
                    </div>
                </tab>
                </tabset>
            </div>
        </div>
    </body>
</html>

Upvotes: 1

Related Questions