clho
clho

Reputation: 301

AngularJS ng-repeat not binding next value for expressions that used in attributes

Here is my code

<script>
    var app = angular.module('TestApp', []);
    app.controller('TestCtrl', function ($scope) {
        $scope.tests = [
            {
                id: '1',
                name: 'Test 1',
                count: '10',
                children: [{
                    name: 'Test Child 1'
                }]
            },
            {
                id: '2',
                name: 'Test 2',
                count: '19',
                children: [{
                    name: 'Test Child 2'
                }]
            },
            {
                id: '3',
                name: 'Test 3',
                count: '18',
                children: [{
                    name: 'Test Child 3'
                }]
            }
        ];
    });

    function test() {
        alert($('#testtest').attr('href'));
    }
</script>
<div ng-app="TestApp" ng-controller="TestCtrl">
    <div class="panel panel-default">
        <div class="panel-heading clearfix" ng-repeat="test in tests">
            <a id="testtest" data-toggle="collapse" href="#div_{{test.id}}" onclick="test();" class="pull-left" style="padding-top: 7.5px;">{{test.id + ' ' + test.name}} <span class="badge">{{test.count}}</span></a>
        </div>
        <div id="div_{{test.id}}" class="panel-collapse collapse">
            <div class="panel-body">
                <table id="tbl_{{test.id}}" class="table table-hover">
                    <thead>
                        <tr>
                            <td>Name</td>
                        </tr>
                    </thead>
                    <tbody>
                        <tr ng-repeat="child in test.children">
                            <td>{{child.name}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

I'm trying to create a list of panels, with tables in it.

The outcome is: enter image description here

When I click the name of the panel, it was suppose to expand the panel body, but the panel body wasn't expanding. So I alert() thehref="#div_{{test.id}}"it showed #div_1 for all three items.

It is suppose to be #div_1, #div_2 and #div_3 just like the 1,2 and 3 number generated on the panel header.

What is my mistake?

P/s: Sorry for the bad explaination

Upvotes: 1

Views: 340

Answers (3)

Shaohao
Shaohao

Reputation: 3511

Malkus and Fedaykin both pointed out the important concept of development using AngularJS. My answer is just a wrap of these two. I have made a working example here.

Changes that I made:

<a id="testtest" data-toggle="collapse" ng-href="#div_{{test.id}}"
       class="pull-left" style="padding-top: 7.5px;" ng-click="selectTest(test)">
   {{test.id + ' ' + test.name}}<span class="badge">{{test.count}}</span>
</a>

As you can see, I have used ng-click to pass the select test object to the controller and console.log(test). You will be able to see the object in the console.

$scope.selectTest = function(test) {
    console.log(test);
    $scope.selectedTest = test;
}

This approach allows you to have the whole object and modify it.

Another change I made is:

<div class="panel-collapse collapse" ng-attr-id="div_{{test.id}}" 
     ng-repeat="test in tests">
     ...
</div>

As Fedaykin mentioned, you only ng-repeat the panel header, which means the scope of test is only in the header. You are not able to access the test out of the header, because it is out of scope. Therefor you have to do another ng-repeat on the panel body.

I don't like this approach because it gives you less control what it has to display. And when you are encountering a giant data, you don't want to render all the data to front-end because it will cause latency and etc. So, the best approach is display the selected data when users click the corresponding panel.

Suggestion

Try to using ng-click with ng-show, ng-hide, ng-if to do this.

Upvotes: 1

Malkus
Malkus

Reputation: 3726

I see a few things that are giving you trouble:

You want to use ng-href hence the errors with the alerts. Also you should use ng-click not onclick

 <a id="testtest" data-toggle="collapse" ng-href="#div_{{test.id}}"     
     ng-click="test();" class="pull-left" style="padding-top: 7.5px;">
            {{test.id + ' ' + test.name}} 
     <span class="badge">{{test.count}}</span></a>

For the panels that aren't exanding ng-repeat only repeats the element and its contents. The section below starts after the ng-repeat ends. You should also use ng-attr-id to update the ID with a value from the scope

 <div ng-attr-id="div_{{test.id}}" class="panel-collapse collapse"> 

A good rule of thumb with angular:

any time you want to use something from the scope to update an element or element attribute see if angular has a directive to manage it. AngularJS compiles the DOM you should not be accessing or manipulating elements without a directive, in this case ng-href, ng-click and ng-attr-id

Upvotes: 0

Fedaykin
Fedaykin

Reputation: 4552

You are ng-repeating only the headers, you need to do it for the panels too, please try this out and let me know:

<div ng-app="TestApp" ng-controller="TestCtrl">
    <div class="panel panel-default">
        <div class="panel-heading clearfix" ng-repeat="test in tests">
            <a id="testtest" data-toggle="collapse" href="#div_{{test.id}}" onclick="test();" class="pull-left" style="padding-top: 7.5px;">{{test.id + ' ' + test.name}} <span class="badge">{{test.count}}</span></a>
        </div>
        <div id="div_{{test.id}}" class="panel-collapse collapse"  ng-repeat="test in tests">
            <div class="panel-body">
                <table id="tbl_{{test.id}}" class="table table-hover">
                    <thead>
                        <tr>
                            <td>Name</td>
                        </tr>
                    </thead>
                    <tbody>
                        <tr ng-repeat="child in test.children">
                            <td>{{child.name}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

Upvotes: 1

Related Questions