简体   繁体   中英

angularjs $scope and controller

I'm new to angular, I've read couple of articles on scope and controllers but I think I still don't get it.

Lets say we have a code

    var myApp = angular.module("myApp", []);
    myApp.controller("myCtrl", function($scope) {

        $scope.array = [1,2,3];

        $scope.show = false;
        $scope.toggle = function (){
            $scope.show = !$scope.show;
            console.log($scope.show);
        };
    });

and markup:

<body ng-app="myApp">
<ul ng-controller="myCtrl">
    <li ng-repeat="n in array">
        <a href="#" ng-click="show = !show">Click here to show</a>
        <span ng-show="show">Something to show</span>
    </li>
</ul>
</body>

Everything works when I use "ng-click="show = !show" in the ng-show. But when I use toggle() insted it doesn't. My question is how to change the code to make method toggle() work ? How to access the actuall scope than I'm operating in in the controller ? Should I use ng-controller="myCtrl" on each li tag ? Should I have a controller for each scope that is created by the directives in my markup ? What is the best practise here ?

The reason that things seem strange is that ngRepeat uses an isolate scope. That means it creates a new child scope off of the parent.

When you use show = !show , you are creating a show value on that child scope.

When you use toggle , you are trying to call a method on the scope that doesn't exist.

You could try calling $parent.toggle() on the click event, but that will set the show value on the parent scope rather than individual rows.

What's being said is true, the show inside the ngRepeat is different from the show in myCtrl . However, even if it weren't, there's only one variable show in myCtrl , so every item would be hidden and shown together when toggling.

If you want to toggle individual rows, they each need their own flag. There are several ways to accomplish this. But to avoid too much logic in the view, and to avoid the use of $parent , one way would be to use the controller as syntax, and keep a list of show flags, taking advantage of the fact that ngRepeat supplies the array index as $index .

var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function() {
    var myCtrl = this;
    myCtrl.array = [1,2,3];
    myCtrl.show = [false, false, false];

    myCtrl.toggle = function (index){
        myCtrl.show[index] = !myCtrl.show[index];
        console.log(myCtrl.show);
    };
});

Then the view:

<body ng-app="myApp">
<ul ng-controller="myCtrl as ctrl">
    <li ng-repeat="n in ctrl.array">
        <a href="#" ng-click="ctrl.toggle($index)">Click here to show</a>
        <span ng-show="ctrl.show[$index]">Something to show</span>
    </li>
</ul>
</body>

You could also use an array of objects if you plan to do something complicated where keeping track of two arrays would be difficult. Something like:

myCtrl.array = [
  {val: 1, show: false},
  {val: 2, show: false},
  {val: 3, show: false},
];

Then the toggle function would be:

myCtrl.toggle = function(obj){
  obj.show = !obj.show;
};

and the view:

<body ng-app="myApp">
<ul ng-controller="myCtrl as ctrl">
    <li ng-repeat="n in ctrl.array">
        <a href="#" ng-click="ctrl.toggle(n)">Click here to show</a>
        <span ng-show="n.show">Something to show</span>
    </li>
</ul>
</body>

Edit: here's a plunkr for each.

http://plnkr.co/edit/sBhY00c5LU4YMeHlqjG7?p=preview

http://plnkr.co/edit/axO9sEB6oHQeDwIRLU4a?p=preview

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