简体   繁体   中英

Ng-click/ ng-repeat issues

I'm trying to create an accordion using angular js and angular material. The problem is that when i'm using ng-repeat, all accordions in the array open when I click the button. I want only want to open the one that i click. Any ideas how I accomplish this? I have tried to google but i'm not finding exactly what i'm looking for

This is my html

<div class="accordionwrapper" layout="column" layout-align="center center">
    <div class="accordion" ng-repeat="question in questions">

        <div class="accordionheader" layout="row" layout-align="space-between center">
            <h3>{{question.q}}</h3>

            <md-button class="md-icon-button md-accent" aria-label="Favorite" ng-click="toggleaccordion()" ng-if="!accordionOpen">
                <md-icon md-svg-icon="images/add.svg"></md-icon>
            </md-button>
            <md-button class="md-icon-button md-accent" aria-label="Favorite" ng-click="toggleaccordion()" ng-if="accordionOpen">
                <md-icon md-svg-icon="images/minus.svg"></md-icon>
            </md-button>
        </div>

        <div class="accordioncontent" ng-show="accordionOpen">
            <p>{{question.a}}</p>
        </div>

    </div>

And my js

 $scope.accordionOpen = false;


$scope.toggleaccordion = function () {
    $scope.accordionOpen = !$scope.accordionOpen;
    console.log($scope.accordionOpen)
}

Thanks!

You need to keep track of the state of each individual accordion, using an array. This means that accordionOpen should be an array and that toggleaccordion should be like this :

$scope.toggleaccordion = function($index){
  $scope.accordionOpen[$index] = !$scope.accordionOpen[$index]

Finally, you should call the function using the $index variable that is provided by angular inside an ng-repeat :

<md-button class="md-icon-button md-accent" aria-label="Favorite" ng-click="toggleaccordion($index)" ng-if="accordionOpen[$index]">

All your accordions created by using ng-repeat depend on one variable, which is accordionOpen. Create an array of boolean flags and put it into questions array so that each of the accordions would have its own flag.

When you're calling $scope.accordionOpen = !$scope.accordionOpen; the scope is the parent of all the ngRepeat scopes. They inherit the accordionOpen value.

There might be more solutions to this - set the accordionOpen = true in ngClick instead of calling controller function: EDIT: Note: This won't probably work because the md-button ng-if uses it's own scope. It's always better to stick to some kind of model object, that other answers or second solution suggest.

<md-button 
    class="md-icon-button md-accent" 
    aria-label="Favorite" 
    ng-click="accordionOpen = true"
    ng-if="!accordionOpen">
        <md-icon md-svg-icon="images/add.svg"></md-icon>
</md-button>

or add a property to the question itself

js:

$scope.toggleaccordion = function (question) {
    question.$accordionOpen = !question.$accordionOpen;       
}

html

<md-button ng-click="toggleaccordion(question)" ng-if="!question.$accordionOpen">
     <md-icon md-svg-icon="images/add.svg"></md-icon>
</md-button>

<div class="accordioncontent" ng-show="question.$accordionOpen">
    <p>{{question.a}}</p>
</div>

Read more on scopes: https://docs.angularjs.org/guide/scope

You are using a single variable in scope to toggle a collection of accordian , because of this all accordians toggle on the change of single varialbe .

To avoid it every accordian should have it's own set of toggle flag.To achieve it keep the flag with the record itself( in your case the question object)

    <div class="accordionheader" layout="row" layout-align="space-between center">
        <h3>{{question.q}}</h3>

        <md-button class="md-icon-button md-accent" aria-label="Favorite" ng-click="toggleaccordion(question)" ng-if="!question.accordionOpen">
            <md-icon md-svg-icon="images/add.svg"></md-icon>
        </md-button>
        <md-button class="md-icon-button md-accent" aria-label="Favorite" ng-click="toggleaccordion(question)" ng-if="question.accordionOpen">
            <md-icon md-svg-icon="images/minus.svg"></md-icon>
        </md-button>
    </div>
<!-- In ng-show use a variable which will make sure that every object will get it's own toggle status field -->
    <div class="accordioncontent" ng-show="question.accordionOpen">
        <p>{{question.a}}</p>
    </div>

</div>

And in your js use like this

$scope.questions.forEach(function(question){
    question.accordionOpen = false ;
});


$scope.toggleaccordion = function (question) {
    question.accordionOpen = !question.accordionOpen;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM