javascriptangularjsangularjs-ng-options

AngularJS - display a default option at the top of a dynamic select dropdown list?


Goal: Make a default <option> always appear at the top of a <select> dropdown when it's opened.

I'm halfway to my goal. We have a dropdown that populates depending on whether other elements are selected, and the 'Text' option correctly appears as the default. I've added orderBy: which sorts the list alphabetically by their label, which the first fix that we want. But we also want the 'Text' option to always appear at the top of the list when the dropdown is opened.

The HTML for this dropdown:

<select ng-options="t.id as t.label for t in currentOptions | orderBy:'label'" 
ng-model="rule.field" 
ng-change="updateOptions(rule, $index, true)" 
ng-init="updateOptions(rule, $index)" title="{{rule.label}}" 
class="form-control" style="width:100%" required></select>

The currentOptions array is similar to this:

currentOptions{"Text", "Banana", "Apple", "Notebook", "Coffee", "Zebra"}

When it first appears in the browser view, it shows Text in the clickable field, as it's in the [0] position in the array. When I open the dropdown, the visible list reads like this: "Apple" "Banana" "Coffee" "Notebook" "Text" "Zebra"

What we want is for the visible list to read like this: "Text" "Apple" "Banana" etc.


Solution

  • You can create a custom function to update the orderBy option based on the required logic. The custom function updateOptionOrder simply check if the current option label value is Text or not. If yes, then we just skip sorting and keep the current option at the top, else continue default sorting based on the label value.

    Demo:

    var app = angular.module('myApp', []);
    app.controller('AppCtrl', function($scope) {
      $scope.currentOptions = [
          {label:'Text', id:'1'},
          {label:'Banana', id:'2'},
          {label:'Apple', id:'3'},
          {label:'Notebook', id:'4'},
          {label:'Coffee', id:'5'}, {label:'Zebra', id:'6'}
        ];
        
      $scope.updateOptionOrder = function(v) {
        if(v.label == "Text"){
           return -1; // Skip this sort for "Text"
        }else{
           return v.label; // Continue sorting based on label
        }
      } 
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
    <div ng-app="myApp">
      <div ng-controller="AppCtrl">
        <select ng-options="t.id as t.label for t in currentOptions | orderBy:updateOptionOrder" class="form-control" style="width:50%" ng-model="field"></select>
        <hr>
        <p>{{field}}</p>
      </div>
    </div>