Search code examples
angularjsselectlodashangular-ngmodelangular-filters

Angular 1.x: Using select & ng-options with a custom filter


preface

I have written a custom filter that excludes currently selected options from the list of available options for several <select> inputs.

codepen - http://codepen.io/jusopi/pen/XdjNWa?editors=1010

template implementation

<select class="form-control" ng-model="vc.cols[0].attr" 
    ng-options="opt.attr as opt.name for opt in vc.opts | excludedAttrs:vc.cols">

filter

.filter('excludedAttrs', function () {
    return function (opts, cols) {
        return _.differenceWith(opts, cols, function (opt, col) {
            return opt.attr === col.attr;
        });
    };
})

the problem

I'm not sure if it's my misunderstanding of Lodash's differenceWith (API docs) or if there is some subtly in using filters with a <select> over other inputs.

As I understand differenceWith, it's meant to compare 2 arrays and utilizes a comparator function that returns true if they are to be excluded. The filter actually works, but why is it not rendering the ng-model default value properly or the selected value?


Solution

  • The problem with the select not showing the currently selected ng-model was because the actual <option/> was not present in the ng-options due to the filter excluding it in the collection.

    In order to fix this, I needed to exclude the currently selected value (i.e. the ng-model from being ... well, from being excluded. Basically I had to add it back into the filtered ng-options.

    codepen - http://codepen.io/jusopi/pen/XdjNWa?editors=1010

    template implementation

    <select ng-model="vc.cols[0].attr" 
        ng-options="opt.attr as opt.name for opt in vc.opts | excludedAttrs:vc.cols:0">
    

    fixed filter

    .filter('excludedAttrs', function () {
        return function (opts, cols, i) {
    
            // fix
            cols = _.without(cols, cols[i]);
            // end fix
    
            return _.differenceWith(opts, cols, function (opt, col) {
                return opt.attr === col.attr;
            });
        };
    })