3

I have created an application in AngularJS with a drop down with space in option using a filter. The application is working fine with the options in drop down with indentation space before the values but the problem is when a select an option which is having a space, the space is also shown in the view like as shown below

enter image description here

actually I want the indentation space within the drop-down options but only thing is that I don't want that space to be get displayed when selection shown above

can anyone please tell me some solution to prevent the space to display when selection

My code is as given below

JSFiddle

<select>
    <option ng-repeat="(key, value) in headers">{{value | space}}
    </option>
</select>
Alex Man
  • 4,746
  • 17
  • 93
  • 178

5 Answers5

3

This is as close as it gets without jquery, temporarily changing the view state of the option when it's chosen. If that doesn't satisfy you and you still want it to be shown indented when the dropdown menu is open, check out this question on how to detect the state of the select component and update the display function accordingly. Alternatively, you can create your own select directive and manage the details within that, but I doubt that's worth the trouble if you're not using it in many places.

var app = angular.module('myApp', []);

app.controller('ArrayController', function ($scope) {
    $scope.headers = [{
        value: 'value 1'
    }, {
        value: 'value 2',
        mainId: 12
    }, {
        value: 'value 3'
    }, {
        value: 'value 4',
        mainId: 14
    }, {
        value: 'value 5'
    }, {
        value: 'value 6',
        mainId: 18
    }];

    $scope.chosen = $scope.headers[0].value;

    $scope.display = function(header) {
        var chosenObject = _.find($scope.headers, {value: $scope.chosen});
        if (!_.isUndefined(header.mainId) && header !== chosenObject) {
            return '\u00A0\u00A0' + header.value;
        } else {
            return header.value;
        }
    }
});

HTML here:

<div ng-app='myApp' ng-controller="ArrayController">
    <br></br>
    SELECT:
    <select ng-model="chosen" ng-options="header.value as display(header) for header in headers">
    </select>
</div>

There's yet another alternative with CSS and ng-class, fiddle here:

var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
    $scope.headers = [{
        value: 'value 1'
    }, {
        value: 'value 2',
        mainId: 12
    }, {
        value: 'value 3'
    }, {
        value: 'value 4',
        mainId: 14
    }, {
        value: 'value 5'
    }, {
        value: 'value 6',
        mainId: 18
    }];

    $scope.chosen = $scope.headers[0].value;

    $scope.isIndented = function(header) {
        var chosenObject = _.find($scope.headers, {value: header});
        return !_.isUndefined(chosenObject.mainId);
    };
});

app.filter('space', function() {
  return function(text) {
       if(_.isUndefined(text.mainId))
       {
           console.log('entered mainId');
           return text.value;
       }
       else
       {
           console.log('entered');
           return '\u00A0\u00A0' + text.value;
       }
  };
});

HTML:

<div ng-app='myApp' ng-controller="ArrayController">
    <br></br>
    SELECT:
    <select ng-model="chosen" ng-options="header.value as (header | space) for header in headers" ng-class="{'indented-value': isIndented(chosen)}">
    </select>
</div>

CSS:

.indented-value {
    text-indent: -9px;
}
Community
  • 1
  • 1
downhand
  • 395
  • 1
  • 9
  • 23
  • using filter is a clean way i guess.....also in your jsifddle which is given , on selecting the option the space is not shown, but the problem is on option selection the space is removing – Alex Man Mar 05 '15 at 10:02
  • Using filter doesn't work in my approach, because I need access to the chosen element. Otherwise instead of display(header) you can use (header | space) and it will display the text going through the filter. I already mentioned in the answer that it temporarily removes the indentation of the chosen element in the select list as well, and if that doesn't work for you, you should consider one of the more complicated alternatives I listed. Still, you will not get to display a text without indentation in the closed form and with indentation in the open form at the same time. – downhand Mar 05 '15 at 10:18
  • can we do any stuff using ng-class and ng-selected, mean on selecting can we remove the indentation using css – Alex Man Mar 05 '15 at 10:23
  • It is working in Chrome 41, that's where I wrote it. In Firefox 32 it works with -4px as the indent. Not sure about IE. I showed you how to handle the angular part, I believe you can work on the CSS details. – downhand Mar 05 '15 at 12:33
  • I went down this road before deleting my answer. Select and CSS don't go well together cross-browser, and there is no way to tell if the select is open or not in order to decide whether to trim the displayed model. I do not think this problem has a solution that involves using select. I think you are going to have to implement your own drop down that mimics the behavior of select. – Joe Enzminger Mar 05 '15 at 18:10
  • I have got an answer from Beppoz [JSFiddle](http://jsfiddle.net/o3odjmmb/) , Its a kind of hack but working in all browsers, what do you think and like to say on this stuff – Alex Man Mar 09 '15 at 15:33
3

Given your code, you can add one helper directive, to remove space in link function, once your option got selected.

As an example, add an id to your select, and directive

<select id="mySelect" option-without-space>
    <option ng-repeat="(key, value) in headers">{{value | space}}
    </option>
</select>

And directive might look like,

app.directive('optionWithoutSpace', () => {
        return {
            restrict: 'A',
            link: function(scope, elem, attributes) {

                var selectedOptionWithoutSpace = function () {
                    var selectedOption = $('#mySelect option:selected');

                    var optionText = selectedOption.text();

                    selectedOption.text(optionText.trim())

                    return false;
                };

                $(elem).on('change', selectedOptionWithoutSpace);

            }
        }
    })

This is with a little help of jQuery, but I assume it is not a big problem.

Here is a fiddle.

vtor
  • 8,989
  • 7
  • 51
  • 67
  • can you just provide me with a jsfiddle – Alex Man Mar 09 '15 at 14:28
  • see the thing is in your code when you select an option that is having the space, once selected it is removing the space permanently, after selection again if you see the drop down list that space is completely removed – Alex Man Mar 09 '15 at 14:41
  • its removing the space upon selection from the drop down list permanently – Alex Man Mar 09 '15 at 15:01
  • 1
    I have got an answer from Beppoz [JSFiddle](http://jsfiddle.net/o3odjmmb/) , Its a kind of hack but working in all browsers, what do you think and like to say on this stuff – Alex Man Mar 09 '15 at 15:33
  • Looks fine. As an alternative, I have updated my fiddle, so it behaves like you want now. Still the selected option will not be highlited, but you can achieve that via simple CSS (just take the selected option and change background-color). I am at work now, so couldn't add that trick, maybe will update later. – vtor Mar 10 '15 at 14:51
  • Ok, I updated now to final fiddle, take a look please. Also the selected option is highlited now. – vtor Mar 10 '15 at 19:02
  • In IE it is giving unexpected results.....when we select an option from the select box, it is duplicating the same option to the drop down list – Alex Man Mar 11 '15 at 05:12
3

First off, this was a great question. I've unfortunately spent way too much time trying to come up with a solution to this. I've tried everything from CSS, to using ngModelController $formatters, to the solution (which isn't optimal as you'll see) I've posted below. Note, I do not think my solution deserves to be selected as the answer. It just "sorta" works, but like other solutions, it has a fatal flaw.

However, since your question was:

can anyone please tell me some solution to prevent the space to display when selection

My official answer is:

No

There is no cross-browser way to get this working. No amount of CSS, jQuery, or Angular magic will make this work. While it may be disappointing, I think that is going to be the only correct answer to your question.

No one is going to be able to give you a solution that prevents the space from being displayed in the select box while maintaining it in the options that works reliably across browsers. Chrome and Firefox allow some amount of styling of elements in the select, options, and optgroup family, but nothing is consistent and works everywhere.

My best run at it is in this Plunk

It uses the fact that optgroup will do indentations for you, but it comes with terrible differences in how different browsers handle it. With some you can style away the problem, but others do not work (and never will). I'm posting it so maybe someone will be inspired and figure out a way to prove me wrong.

<body ng-app="app">
  <div ng-app='myApp' ng-controller="ArrayController">
    <div>{{selectedValue}}</div>

    SELECT:
    <select ng-model="selectedValue" >
      <option indented="item.mainId" ng-repeat="item in headers">{{item.value}}</option>
    </select>
  </div>
</body>

(function() {

  var app = angular.module('app', []);
  app.controller('ArrayController', function($scope, $timeout) {
    $scope.headers = [{
      value: 'value 1'
    }, {
      value: 'value 2',
      mainId: 12
    }, {
      value: 'value 3'
    }, {
      value: 'value 4',
      mainId: 14
    }, {
      value: 'value 5'
    }, {
      value: 'value 6',
      mainId: 18
    }];
  });

  app.directive('indented', function($parse) {
    return {
      link:function(scope, element, attr){
        if($parse(attr.indented)(scope)) {
          var opt = angular.element('<optgroup></optgroup>');
          element.after(opt).detach();
          opt.append(element);
        }
      }
    };
  });
})();

If you opened the question up and allowed the implementation of a directive that mimicked the behavior of select but was instead built with li elements, then this would be trivial. But you simply can't do it with select.

Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75
  • Thanks @JoeEnzminger for such a detailed answer – Alex Man Mar 09 '15 at 14:33
  • I have got an answer from Beppoz [JSFiddle](http://jsfiddle.net/o3odjmmb/) , Its a kind of hack but working in all browsers, what do you think and like to say on this stuff – Alex Man Mar 09 '15 at 15:32
  • I'd give him the bounty! That's as close as you are going to get. – Joe Enzminger Mar 09 '15 at 16:02
  • The only thing it doesn't do is show the currently selected item when you open the select - so I still think my answer is correct :). But it's clean and clever. – Joe Enzminger Mar 09 '15 at 16:04
3
<select ng-model="selectedValue" ng-change="selVal = selectedValue.trim(); selectedValue=selVal">
    <option ng-if="selVal">{{selVal}}</option>
    <option ng-repeat="(key, value) in headers" ng-if="selVal != value.value">
        {{value | space}}
    </option>
</select>
G-Host
  • 356
  • 2
  • 11
  • what's going on in this code, its shuffling the drop down list ....somewhat working but not proper...http://jsfiddle.net/0yyq1Lkn/ – Alex Man Mar 09 '15 at 14:53
  • It's not shuffled, selected element is evicted from the options, if you dont want it, leave the `ng-if="selVal != value.value"` and it's done. – G-Host Mar 09 '15 at 15:01
  • the above issue is happening only with chrome and firefox – Alex Man Mar 09 '15 at 15:12
  • Thi is the side effect, you can't have the option selected and in the same time the correct visualization. That's another variation of this code: `` When the option is selected, the indentation is lost – G-Host Mar 09 '15 at 15:18
  • you are somewhat near to the answer i want...but the above issue is troubling me – Alex Man Mar 09 '15 at 15:21
  • how about this one....some how i have got, http://jsfiddle.net/69cL37ft/ - I have hide the option – Alex Man Mar 09 '15 at 15:30
  • Yes, that's good, if you dont care the option displays as selected this is the best choice, you can play with some css style to trick with option selection! – G-Host Mar 09 '15 at 15:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72652/discussion-between-alex-man-and-beppoz). – Alex Man Mar 10 '15 at 09:01
  • I have posted my query in chat – Alex Man Mar 10 '15 at 12:42
  • This is my last try, I replied in chat too. Check this out http://jsfiddle.net/qxybezd3/11/ – G-Host Mar 11 '15 at 09:10
-1

Try this...

Change select box html following

<select ng-model="selectedOption" ng-options="item.value for item in headers"></select>


var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
    $scope.headers = [{
        value: 'value 1'
    }, {
        value:'value 2',
        mainId: 12
    }, {
        value: 'value 3'
    }, {
        value: 'value 4',
        mainId: 14
    }, {
        value: 'value 5'
    }, {
        value: 'value 6',
        mainId: 18
    }];
    $scope.selectedOption = $scope.headers[0]; //Add this line
});

app.filter('space', function() {
  return function(text) {
       if(_.isUndefined(text.mainId))
       {
           console.log('entered mainId');
           return text.value;
       }
       else
       {
           console.log('entered');
           return '\u00A0\u00A0' + text.value;
       }
  };
});
Deenadhayalan Manoharan
  • 5,436
  • 14
  • 30
  • 50