Search code examples
angularjsangularjs-directiveangular-ngmodelisolate-scopeangularjs-select

Issues with passing ng-model to custom directive and making it work


I've created a custom directive that auto-populates a select with a list of countries. The directive has a preselect isolate scope attribute, that if set to true will preselect a country.

ng-model is also passed as an isolate scope attribute The problem is that ng-model won't be set.

Could anyone give me some pointers on how to make the <auto-countries> directive so that I'm able to set ng-model ?

here's my directive's code:

app.directive('autoCountries', function() {
    return {
        restict: 'E',
        controller: 'CountriesCtrl as ctrl',
        scope: {
            preselect: '=',
            ngModel: '='
        },
        template: [

            '<select ng-if="!preselect" ng-model="ngModel">',
                '<option value="">Select Country</option>',
                '<option ng-repeat="country in ctrl.countries" value={{country.name}}>',
                    '{{country.name}}',
                '</option>',
            '</select>',

            '<select ng-if="preselect" ng-model="ngModel">',
                '<option ng-repeat="country in ctrl.countries" ng-selected="ctrl.countryFromIP == country.name" value={{country.name}}>',
                    '{{country.name}}',
                '</option>',
            '</select>',
        ].join('')
    }
})

What makes things more weird is that in a simpler version of the directive that doesn't use at all the preselect, the ng-model will be set.

It's kinda hard to understand without an example, so here's a Plunkr! http://plnkr.co/edit/e1HPgGQlne7Q4TcNJ9XT?p=preview


Solution

  • You should use ngOptions instead of ngRepeat. I forked dave's plnkr and adjusted it a bit. Your template with and without preselection will look like this:

    '<select ng-model="ngModel" ng-options="country.name as country.name for country in ctrl.countries"></select>'
    

    I did the pre-selection in the countries controller instead of the view/template, just like in angular's documentation for ngOptions.

    $scope.ngModel = $scope.preselect ? $scope.ngModel = vm.countries[3].name : "";
    

    (if preselect equals true then set default for ngModel, else set empty string - javascript ternary operator.)