text: uis.directive('uiSelectSingle', ['$timeout','$compile', function($timeout, $compile) {
    return {
      restrict: 'EA',
      require: ['^uiSelect', '^ngModel'],
      link: function(scope, element, attrs, ctrls) {
  
        var $select = ctrls[0];
        var ngModel = ctrls[1];
  
        //From view --> model
        ngModel.$parsers.unshift(function (inputValue) {
          // Keep original value for undefined and null
          if (isNil(inputValue)) {
            return inputValue;
          }
  
          // Allow the null value to be considered a valid model value
          if (inputValue.$$null) {
            return inputValue[$select.itemProperty];
          }
  
          var locals = {};
          locals[$select.parserResult.itemName] = inputValue;
          return $select.parserResult.modelMapper(scope, locals);
        });
  
        //From model --> view
        ngModel.$formatters.unshift(function (inputValue) {
          // Keep original value for undefined and null
          if (isNil(inputValue)) {
            return inputValue;
          }
  
          var data = $select.parserResult && $select.parserResult.source (scope, { $select : {search:''}}), //Overwrite $search
              locals = {},
              result;
          if (data){
            var checkFnSingle = function(d){
              locals[$select.parserResult.itemName] = d;
              result = $select.parserResult.modelMapper(scope, locals);
              return result === inputValue;
            };
            //If possible pass same object stored in $select.selected
            if ($select.selected && checkFnSingle($select.selected)) {
              return $select.selected;
            }
            for (var i = data.length - 1; i >= 0; i--) {
              if (checkFnSingle(data[i])) return data[i];
            }
          }
          return inputValue;
        });
  
        //Update viewValue if model change
        scope.$watch('$select.selected', function(newValue) {
          if (ngModel.$viewValue !== newValue) {
            ngModel.$setViewValue(newValue);
          }
        });
  
        ngModel.$render = function() {
          $select.selected = ngModel.$viewValue;
        };
  
        scope.$on('uis:select', function (event, item) {
          $select.selected = item;
          var locals = {};
          locals[$select.parserResult.itemName] = item;
  
          $timeout(function() {
            $select.onSelectCallback(scope, {
              $item: item,
              $model: isNil(item) ? item : $select.parserResult.modelMapper(scope, locals)
            });
          });
        });
  
        scope.$on('uis:close', function (event, skipFocusser) {
          $timeout(function(){
            if (!skipFocusser) $select.focusser[0].focus();
          },0,false);
        });
  
        //Idea from: https://github.com/ivaynberg/select2/blob/79b5bf6db918d7560bdd959109b7bcfb47edaf43/select2.js#L1954
        var focusser = angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' id='{{ $select.focusserId }}' aria-label='{{ $select.focusserTitle }}' aria-haspopup='true' role='button' />");
        $compile(focusser)(scope);
        $select.focusser = focusser;
  
        // Move focuser out of <ui-select> because append-to-body="true" will move the focusser out of :tabbable order.
        element.parent().parent().prepend(focusser);
  
        scope.$on('$destroy', function() {
          if ($select.focusser) {
            $select.focusser.remove();
          }
        });
  
        focusser.on("focus", function(){
          scope.$evalAsync(function(){
            $select.focus = true;
          });
        });
  
        focusser.on("blur", function(){
          scope.$evalAsync(function(){
            $select.focus = false;
          });
        });
  
        focusser.on("keydown", function(e){
          if (e.which === KEY.BACKSPACE && $select.backspaceReset !== false) {
            $select.select($select.nullValue);
            $select.cancelEvent(e);
            scope.$apply();
            return;
          }
  
          if (e.which === KEY.TAB) {
            $select.tabNavigate(e.shiftKey);
            $select.cancelEvent(e);
            return;
          }
  
          if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
            return;
          }
  
          if (e.which == KEY.DOWN  || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){
            $select.cancelEvent(e);
            $select.activate();
          }
  
          scope.$digest();
        });
  
        focusser.on("keyup input", function(e){
          if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER || e.which === KEY.BACKSPACE) {
            return;
          }
  
          $select.activate(focusser.val()); //User pressed some regular key, so we pass it to the search input
          focusser.val('');
          scope.$digest();
        });
      }
    };
  }]);
  