Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - Is there an easy way to set a variable on "sibling" scopes?

Tags:

angularjs

I have this problem where I am trying to make a click on a div hide all the other divs of the same "kind". Basically I'd have to, from a child scope set the variable on all other "sibling" scopes.

To illustrate this, I have created the following:

HTML

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
        <div ng-repeat="model in models" ng-controller="MyChildCtrl">
            <a ng-click="toggleVisibility()">toggle {{ model.name }} {{ visibility }}</a>
            <div ng-show="visibility">
                {{ model.name }}
            </div>
        </div>
    </div>
</div>​

JavaScript

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

    function MyCtrl($scope) {
        console.debug('scope');
        $scope.models = [
            { name: 'Felipe', age: 30 },
            { name: 'Fernanda', age: 28 },
            { name: 'Anderson', age: 18 }
        ];
    }

    function MyChildCtrl($scope) {
        $scope.visibility = false;
        $scope.toggleVisibility = function() {
            $scope.visibility = !$scope.visibility; 
        }
    }

JSFiddle: http://jsfiddle.net/fcoury/sxAxh/4/

I'd like that, every time I show one of the divs, that all other divs would close, except the clicked one.

Any ideas?

like image 234
kolrie Avatar asked Dec 11 '22 19:12

kolrie


2 Answers

@kolrie while your approach works I would suggest a different solution which doesn't require any changes to the model. The basic idea is to keep a reference to a selected item and calculate viability by comparing a current item (inside ng-repeat) with a selected one.

Using this solution the toggle function would become:

$scope.toggleVisibility = function(model) {
    $scope.selected = model;
};

and calculating visibility is as simple as:

$scope.isVisible = function(model) {
    return $scope.selected === model;
};

Finally the relevant part of the markup is to be modified as follows:

<div ng-controller="MyCtrl">
    <div ng-repeat="model in models">
        <a ng-click="toggleVisibility(model)">toggle {{ model.name }} {{ isVisible(model) }}</a>
        <div ng-show="isVisible(model)">
            {{ model.name }}
        </div>
    </div>
</div>

Here is a complete jsFiddle: http://jsfiddle.net/XfsPp/

In this solution you can keep your model untouched (important if you want to persist it back easily) and have AngularJS do all the heavy-lifting.

like image 175
pkozlowski.opensource Avatar answered Dec 14 '22 07:12

pkozlowski.opensource


OK, I have added a visible attribute to the model, and I managed to get this done:

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

function MyCtrl($scope) {
    console.debug('scope');
    $scope.models = [
        { name: 'Felipe', age: 30, visible: false },
        { name: 'Fernanda', age: 28, visible: false },
        { name: 'Anderson', age: 18, visible: false }
    ];
}

function MyChildCtrl($scope) {
    $scope.toggleVisibility = function() {
        angular.forEach($scope.models, function(model) {
            model.visible = false;
        });
        $scope.model.visible = true;
    }
}

Live here: http://jsfiddle.net/fcoury/sxAxh/5/

Is this the most efficient way? Do you think it's a good practice if I inject this visible attribute into my model data after getting it via AJAX?

like image 44
kolrie Avatar answered Dec 14 '22 08:12

kolrie