1
votes

I made a directive for a custom dropdown. Everything works as expected - I define all the options in my controller and pass them on to the directive. Directive generates the html and on change it passes on the selected value to my ngModel.

What I would like to improve is. That initially I just set the ngModel to either PUBLIC, PRIVATE or HIDDEN. Then the directive (already knows?) the icon and the value to display inside the dropdown. When selection is made my model is again just either PUBLIC, PRIVATE or HIDDEN not { name: 'Public', icon: 'globe', value: 'PUBLIC' }.

Directive:

.directive('sidPrivacyDropdown', function () {

    return {
        template:   '<div class="input-group sid-privacy-dropdown">\
                        <ui-select ng-model="selectedValue" theme="bootstrap" search-enabled="false" ng-disabled="disabled">\
                            <ui-select-match>{{selectedValue.name}}</ui-select-match>\
                            <ui-select-choices repeat="option in selectOptions">\
                                <div><span class="icon icon-{{option.icon}}"></span>{{option.name}}</div>\
                            </ui-select-choices>\
                        </ui-select>\
                    </div>',
        scope: {
            selectedValue: '=',
            selectOptions: '='
        },
        replace: true
    };
});

Controller:

$scope.privacyOptions = [
    { name: 'Public',   icon: 'globe',  value: 'PUBLIC'     },
    { name: 'Members',  icon: 'group',  value: 'MEMBERS'    },
    { name: 'Hidden',   icon: 'lock',   value: 'HIDDEN'     }
];

HTML:

<div sid-privacy-dropdown selected-value="edit.privacy.field" select-options="privacyOptions"></div>

Since I'm relatively new to Angular and directives I have no idea how or where should I modify the values. Eventually I want the ngModel to be just a constant.

I also prepared a Plunker

Edit! Maybe this will help to better understand what I want:

Here is a Plunker, that does half of what I want it to do: Plunker. I can now just assign 'HIDDEN' as the initial value. And the directive takes the correct item from all the options and displays it. I can't get it to work the other way around. When the 'selectedObject' changes it should update the selectedValue.

1
I don't understand what your question is. What does it mean for ngModel to be constant. What ngModel are you talking about? - New Dev
Sorry If I wasn't clear enough... I want the edit.privacy.field to be either PUBLIC, MEMBERS or HIDDEN. When setting the initial value for the edit.privacy.field I want to set it to again either PUBLIC, MEMBERS or HIDDEN. Currently I have to assign it like this $scope.privacyOptions[0]. And when I pass it to the server, I want it's value to be a word, not an { 'name:'Public', icon:'globe', value:'PUBLIC' } object. - Artur K.
I don't want to do the same conversion before and after. First from 'PUBLIC' to { name: 'Public', icon: 'globe', value: 'PUBLIC' } and after that before I pass it on, from Object to 'PUBLIC' - Artur K.

1 Answers

0
votes

I found a working solution by using $watch. Feedback would be helpful. Because $watch seems somewhat like cheating and makes me feel that there a better solution is available.

Anyway, I had to change my directive to this.

app.directive('sidPrivacyDropdown', function () {

    return {
        template:   '<div class="input-group sid-privacy-dropdown">\
                        <ui-select ng-model="$parent.selectedObject" theme="bootstrap" search-enabled="false" ng-disabled="disabled">\
                            <ui-select-match>{{selectedObject.name}}</ui-select-match>\
                            <ui-select-choices repeat="option in selectOptions">\
                                <div><span class="glyphicon glyphicon-{{option.icon}}"></span>{{option.name}}</div>\
                            </ui-select-choices>\
                        </ui-select>\
                    </div>',
        scope: {
            selectedValue: '=',
            selectOptions: '='
        },
        link: function(scope, elem, attrs) {
            scope.$watch('selectedObject', function(obj){
                scope.selectedValue = obj['value'];
            });
            scope.selectedObject = angular.copy(scope.selectOptions.filter(function(obj){return obj['value'] === scope.selectedValue})[0]);
        },
        replace: true
    };
});

First I find the corresponding privacy object for the selectedObject and use that inside the template. Now when ui-select updates the selectedObject I use $watch to catch that and set the selectedValue to selectedObject['value'].

This way this does what I wanted but I think this could be done without $watch?