0

I'm quite new to AngularJS and I'm trying to define 4 seperate select elements usign element directives.

app.directive('playerselect', function() {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'templates/directives/player-select.html',
    }
});

<select ng-options="player.full_name for player in players">
    <option value="" selected disabled>Kies een speler</option>
</select>

When a user selects an option in one of the select elements I want the other select elements to be updated, so that the selected option gets disabled in all other select elements. Basically, I want to make sure that each option can get chosen only once.

Any ideas on how to do this?

2 Answers 2

4

I would do it like this:

directive

app.directive('playerSelect', function() {
    return {
        templateUrl: ...
        scope: {
            players: '=',
            selectedPlayer: '=',
            selectedPlayers: '=',
        },
        controller: function($scope) {
            $scope.isDisabled = function(player) {
                return $scope.selectedPlayers.indexOf(player) > -1 &&
                       player !== $scope.selectedPlayer)
            };
        },
    }
});

directive template

<select ng-model="selectedPlayer">
  <option ng-repeat="player in players" ng-disabled="isDisabled(player)">{{player}}</option>
</select>

controller

app.controller('PlayerController', function($scope) {
    $scope.players = ...
    $scope.selectedPlayers = [
        $scope.player1,
        $scope.player2,
        $scope.player3,
        $scope.player4,
    ];
});

controller template

<div ng-controller="PlayerController">
  <player-select players="players" selected-players="selectedPlayers" selected-player="player1"></player-select>
  <player-select players="players" selected-players="selectedPlayers" selected-player="player2"></player-select>
  <player-select players="players" selected-players="selectedPlayers" selected-player="player3"></player-select>
  <player-select players="players" selected-players="selectedPlayers" selected-player="player4"></player-select>
</div>
Sign up to request clarification or add additional context in comments.

4 Comments

So there's no way to do this using ng-options?
@CasCornelissen the problem is using ng-options with ng-disabled. You could possibly use ng-options and instead of disabling the options you remove them from the players list, that might be better UX also.
ah I understand. Thanks for the answer, I'll see which path I'll choose.
@materik glad i could help. please select this as the approved answer if it answered your question :)
1

Check this jsFiddle for see it in action.

I would recommend you an use of directive two way data binding and ngModelController.

So in your html :

<player-select players="players" ng-model="select1"></player-select>
<player-select players="players" ng-model="select2"></player-select>
<player-select players="players" ng-model="select3"></player-select>

In your controller :

$scope.players = [{
    name: 'foo'
}, {
    name: 'bar'
}, {
    name: 'baz'
}];

And the directive, using scope.$watch for update each list :

angular.module('fiddleApp').directive('playerSelect', function ($rootScope) {
    return {
        restrict: 'E',
        require: 'ngModel',
        scope: {
            players: '='
        },
        template: '<select ng-model="selected" ng-options="player.name for player in     playersCopy"></select>',
        link: function (scope, el, attrs, ngModel) {

            function update() {
                scope.playersCopy = angular.copy(scope.players);
                if (scope.selected) {
                    scope.playersCopy.push(scope.selected);
                }
            }

            scope.$watch('selected', function (newValue, oldValue) {
                if (newValue) {
                    scope.players.splice(scope.players.map(function (a) {
                        return a.name
                    }).indexOf(newValue.name), 1);

                    if (oldValue) { scope.players.push(oldValue); }

                    ngModel.$setViewValue(scope.selected);
                    $rootScope.$broadcast('playersUpdate');
                }
            });

            scope.$on('playersUpdate', function () {
                update();
            });

            update();
        }
    };
});

2 Comments

Would it be possible to disable them (disabled attribute on the option) instead of removing them?
Yup, but as @materik said you will not be able to use ng-options on select

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.