Search code examples
angularjsselectangularjs-directiveangularjs-ng-repeatng-options

AngularJS: Set default select option when using directive to apply select drop down to page



EDIT/UPDATE I have added a plunker for this issue: http://plnkr.co/edit/mlYKJQc7zQR0dsvDswMo


I am loading in data from the previous page into $scope.visit in my page controller. I would like to have a directive that constructs and loads select elements on the page with options from the database. Here is what I have so far:

app.directive('popList', ['$http', function($http) {
    'use strict';
    var directive = {
        restrict: 'EA',
        link: link,
        scope: {
            popList: '='
        },
        template: function(elem,attrs) {
            return  '<select '+
                        'ng-model="'+attrs.model+'" '+
                        'ng-options="option.name for option in ddlOpts track by option.id" '+
                        'required '+
                    '></select>';
        }
    };
    return directive;
    function link(scope, elem, attrs, ctrl) {
        var data = {
                sTableName: attrs.tbl
            };
        $http.post('ddl.asmx/populateDDL',data).
        then(function(response) {
            console.log('This is the value I want to set it to '+scope.$parent.visit.data.state_id);
            //ddlOpts loads with no problem
            scope.ddlOpts = response.data.d;
        });

    }
}]);

Then the HTML looks like this:

<div style="width: 5%" class="tableLabel">State</div>
<div
    style="width: 27%;"
    class="tableInput"
    model="visit.data.state_id"
    tbl="tblStates"
    pop-list="states"
>
</div>

Essentially I pass in the name of the table that holds my drop down options. I also pass in the model which will tell the select what value is the default (if it has one.)

I can get the data loaded into the select element as options with no problem. I have checked the ng-model to ensure that I have the correct value to match to the ng-value. I have tried ng-repeat then started all over with ng-options but I cannot for the life of me get the select option to set the default to the ng-model value.

I am starting to think its because the when the select is constructed its in a different scope than the where the controller set the data to $scope.visit. Can someone explain why the two scopes don't recognize one another or just explain why I can't set my default value to the value stored in the ng-model?

Here is the page controller just in case you need for reference:

app.controller('demographicsFormCtrl', function($rootScope, $scope, $cookies, $http, $window, $route) {
    if (
        typeof $cookies.get('visitTrack') === 'undefined' ||
        typeof $cookies.get('visitInfo') === 'undefined' ||
        typeof $cookies.get('visitData') === 'undefined'
    ){
        window.location.href = "#/";
        return false;   
    }
    $scope.visit = {};
    $scope.visit.track = JSON.parse($cookies.get('visitTrack'));
    $scope.visit.data = JSON.parse($cookies.get('visitData'));
    $scope.visit.info = JSON.parse($cookies.get('visitInfo'));
    $rootScope.preloader = true;
    console.log('controller set');

});

Solution

  • First, thanks to Ravi as I couldn't have found the answer without him...

    OK so here is the skinny on doing this in a directive. The database was sending down an object with just a key and an integer value. Angular, when using ng-options, was creating an object with k/v pairs of id-int, name-string... As you can see here in this plunk when I converted the database data (MANUALLY) to match the outcome of the selected option it worked like a charm...

    See it here: http://plnkr.co/edit/mlYKJQc7zQR0dsvDswMo

    Essentially when trying to change the value of your directive created just make sure the data object in ng-model matches the data object created by ng-options...

    or if you have the same issue with the served data you can write in something after you set ddlOpts to set based on the int sent from the DB like so:

    app.directive('popList', ['$http', function($http) {
        'use strict';
        var directive = {
            restrict: 'EA',
            scope: {
                model: '='
            },
            template: function(elem,attrs) {
                return  '<select '+
                            'ng-model="model" '+
                            'ng-options="option.name for option in ddlOpts track by option.id" '+
                            'required '+
                        '></select>';
            },
            link: link
        };
        return directive;
        function link(scope, elem, attrs) {
            var defaultInt;
            if (typeof scope.model === "number"){
                defaultInt = scope.model;
            }else{
                defaultInt = parseInt(scope.model);
            }
            var data = {
                    sTableName: attrs.tbl
                };
            $http.post('/emr4/ws/util.asmx/populateDDL',data).
            then(function(response) {
                scope.ddlOpts = response.data.d;
    // THIS LINE BELOW HERE SETS THE VALUE POST COMPILE
                angular.forEach(scope.ddlOpts, function (v, i) {
                    if (v.id === defaultInt) {
                        scope.model = v;
                    }
                });
            });
    
        }
    }]);
    

    iTS ALWAYS BETTER AS A RULE OF THUMB TO HAVE YOUR DATA COMING FROM THE db MATCH WHAT ANGULAR CREATES BUT THAT IS NOT ALWAYS SO...