Archive | Select2 RSS for this section

Fixing the Width of a Select 2 with a Long Value in a Bootstrap Form Group or Input Group

If you have a Select2 control within a form-group or input-group div in a Bootstrap UI, a long value can cause the Select2 to grow to become wider than its container. In this post, I’ll show how to fix the issue.

The Problem with Large Values

In this demo, I have a form with two columns of fields, each within a well (which makes the container size very clear).

Select2 Long Values - A

In one field, there is a very long value. This usually isn’t an issue when you have explicit control over the options, but if you have an application where a drop-down box’s choices come from a plain text field on other documents, it’s possible.

Select2 Long Values - B

When I select the long value, it limits the amount of text displayed in the box to what will fit on one line, but it expands the size of the Select2 outside of its container.

Select2 Long Values - C

If I remove the second column of fields and re-test, it looks like the Select2 was enlarged to be the same the size as the parent container, which is too big for the area that it’s supposed to be in.

Select2 Long Values - C2

Fixing with CSS

This is a known issue with Select2 inside of a form-group or input-group within Bootstrap.

Fortunately, there’s a simple CSS fix, adapted from this post on github

.form-group .select2-container {
  position: relative;
  z-index: 2;
  float: left;
  width: 100%;
  margin-bottom: 0;
  display: table;
  table-layout: fixed;
}

If you’re using an input-group instead of a form-group, then change the first line to this:

.input-group .select2-container {

Select2 Long Values - D

Advertisements

Updating Select2 Styling to Match Bootstrap Fields

Select2 is an awesome jQuery plugin to enhance the functionality of combo boxes. But if you implement it in an application with a Bootstrap UI, you’ll notice that the styling is not consistent. In this post, I’ll show how to make the styling of Select2 fields consistent with other fields on the form.

Bootstrap Default Styling

Here’s an example of a simple Bootstrap form, including two combo box fields. The styling is very consistent across all of the fields.

Select2 A - Default Drop-Down

Select2 Default Styling

Once I implement Select2 and add the code to initialize combo boxes as Select2 fields, they styling changes. The width and internal padding and line spacing are not consistent with other bootstrap fields. (Click image to enlarge in order to see the difference more clearly.)

Select2 B - Default Select2 Style

Consistent Styling

Fortunately, by inspecting a standard bootstrap field either in the bootstrap CSS or in the browser’s developer tools, I can see the styles in use and replicate them for a more consistent look.

Select2 C - Consistent Select2 Style

Here is the CSS required to make it happen:

.select2-container {
  width:100%;	
}

.select2-container a.select2-choice {
  font-size: 14px;
  height: 38px;
  padding: 8px 12px;
  line-height: 1.42857;
}

.select2-container .select2-choice .select2-arrow {
  padding-top:6px;
}

The first rule makes the field width use 100% of the size of its container, as bootstrap fields do.

The second set of rules sets the font and field styling to make them consistent.

The third rule vertically centers the drop-down arrow for the larger field.

Formatting Select2 Options in Angular

One of the great features of Select2 is that you can format the choices beyond just a list of text values. In this post, I’ll show how you can format the display of values in a Select2 in Angular.

Before we dig in…

These examples were adapted from an XPages application that uses Angular, but there’s nothing related to XPages in the code shown here. (In reality, you’d likely call an XPages REST service to dynamically populate the list of choices, but it’s not necessary in these examples.)

If you’ve used a Select2 in any other context, then the solution here may not be surprising. If you haven’t, then you’ll see how Select2 choices can be formatted.

The examples in this post use the ui-select2 for Angular. (There’s a note at the top of the page that says this control has been deprecated in favor of a newer version.) The code needs to be added to the application, but that is outside of the scope of this post.

Getting up to Speed on Angular

If you don’t have any background in Angular, the angularjs.org tutorial is a great place to start.

Also check out Marky Roden’s great series on using Angular in XPages.

Basic Select2

These examples will all create a Select2 control in Angular that will display a list of fruit and allow the user to choose one.

Here is the basic Select2:

Angular Select2 1a

Once a value is selected, it is shown in the field and separately below the Select2.

Angular Select2 1b

The basic HTML for the template is as follows:

<select ui-select2="select2Config" ng-model="fruit"
        data-placeholder="Select a fruit..." style="min-width:150px">
    <option value=""></option>
    <option ng-repeat="option in options" value="{{option}}">{{option}}</option>
</select>

<br><br>
Selected Value: {{fruit}}

Lines 1-2 start the select tag.

  • The ui-select2 attribute references the configuration object in the Angular controller that sets properties for the control.
  • The ng-model attribute defines that the selected value will be bound to a “field” (if you will) named fruit in the model.
  • The data-placeholder attribute sets the placeholder text when no value has been selected.
  • The style attribute sets a minimum width for the control. (This is not necessary)

Line 3 includes an empty value at the start of the list.

Line 4 uses an ng-repeat directive to build the list of options to choose from. The options list is set in the controller (code shown below).

Line 8 is simply displays the selected value. It is not necessary, but it shows off the two-way binding feature of Angular.

The controller used with the template on this page is as follows:

//Select2 controller - basic
MyAppControllers.controller('select2Ctrl_basic', ['$scope', '$http', '$routeParams',
  function ($scope, $http, $routeParams) {
    $scope.options = ['apple', 'banana', 'grape', 'lime', 'orange'];
  }
]);

That’s it! All I did was define the controller and define an options property in the scope and set it to an array. The template reads the array and generates an option for each value in the array.

Text Formatting

In this example, I’ll show how to change the color of each option based on the value. We’ll use the same HTML template for the Select2.

Angular Select2 2

Here’s the controller for this example:

MyAppControllers.controller('select2Ctrl_formatted', ['$scope', '$http', '$routeParams',
  function ($scope, $http, $routeParams) {
    $scope.options = ['apple', 'banana', 'grape', 'lime', 'orange'];
    
    // Format the control to display a span with the text changed to the color of the fruit
    $scope.format = function (data) {
      var fontColor = 'black';
        	
      switch (data.id) {
        case 'apple':
          fontColor = 'DarkRed';
          break;
        case 'banana':
          fontColor = 'Gold';
          break;
        case 'grape':
          fontColor = 'Purple';
          break;
        case 'lime':
          fontColor = 'LimeGreen';
          break;
        case 'orange':
          fontColor = 'Orange';
          break;
      }
        	
      return  "<span style='color:" + fontColor + "'>" + data.text + "</span>";
    };

    $scope.select2Config = {
      formatResult: $scope.format,
      formatSelection: $scope.format
    };

}]);

In this controller, lines 6-28 create a function that is used to format the options in the list. The function accepts a data object that is the current option in the select2. (The function will be called once for each option as the list is built.) The data object contains a text property that is the actual display value for that option.

Lines 9-25 define a switch statement that sets the fontColor variable based on the fruit.

Line 27 is the key — it returns a span that includes a style attribute to set the font color and display the option.

Lines 30-33 define the configuration object used for the Select2. (This is specified in the ui-select2 attribute of the HTML template.) It tells the control to format each selection and the result using the format() function defined in the controller.

The difference between formatSelection and formatResult

The formatSelection function formats the values in the drop-down list. The formatResult function formats the selected value, shown at the top of the list when the rest of the list is dropped-down. (The example below shows ‘orange’ selected.)

Angular Select2 3

You can use different formatting functions, but it seems common to use the same formatting function for both.

Adding an Image

In this example, I’ll show how to display an image next to each option, based on the value. We’ll use the same HTML template for the Select2.

Angular Select2 4

Here’s the controller for this example:

MyAppControllers.controller('select2Ctrl_image', ['$scope', '$http', '$routeParams',
  function ($scope, $http, $routeParams) {

    $scope.options = ['apple', 'banana', 'grape', 'lime', 'orange'];

    // Format the control to display an image corresponding with the name of the fruit
    $scope.format = function (data) {
      	
      var url = '';
        	
      switch (data.text) {
        case 'apple':
          url = 'apple.png';
          break;
        case 'banana':
          url = 'banana.png';
          break;
        case 'grape':
          url = 'grapes.gif';
          break;
        case 'lime':
          url = 'lime.png';
          break;
        case 'orange':
          url = 'orange.png';
          break;
      }
        	
      return  "<img src='" + url +"' />&nbsp;&nbsp;" + data.text;
    };           
        
    $scope.select2Config = {
      formatResult: $scope.format,
      formatSelection: $scope.format
    };

}]);

This is very similar to the last example, with the exception that it determines the url and returns an img tag to display next to the text value. This adds a very nice touch to the UI of the control. (Note: The images referenced in this example are all icons that I added to the NSF as image resources.)

Triggering a Partial Refresh when a Select2 Value is Changed in XPages

In my last post, I showed how to add Bootstrap error styling to a Select2. As I’ve continued to work with Select2, I came across another challenge — triggering a partial refresh when a Select2 value is changed — because standard component events aren’t executed on a Select2.

This issue is because a component is converted to a Select2 after the page loads. It takes your combobox or listbox and converts it to a div surrounding the entire field, a div for the search, and an unordered list of elements to display in the drop-down. Any event handler code that you entered on the combobox or listbox will no longer be associated with the field because it’s been replaced with the Select2 UI elements.

It is common to update a part of a page based on a value selected in any variation of a list field, so, fortunately, this issues can be worked around by using event delegation to trigger a client-side JavaScript function when the Select2 is changed.

Take this example of converting a field (with a class name of “mySelect2”) to a Select2:

$(".mySelect2").select2({
  placeholder: "Select the value..."
});

To trigger a partial refresh when the value is changed, add this code on the client load or document ready event after the previous code to enable the Select2:

	
$(".mySelect2").on("change", function(e) { 
  XSP.partialRefreshPost("#{id:myPanel}");
})

The code will watch for any change on the Select2 and it will trigger a partial refresh via client-side JavaScript. (See Mark Roden’s post on jQuery event delegation for a good explanation of jQuery event delegation.)

It must trigger a partialRefreshPost (rather than a partialRefreshGet) because it has to send the new value to the server. For the same reason, the field must be within the partial refresh target area.

You can only write client-side JavaScript code here, but if you have a larger piece of server-side JavaScript or Java code that needs to be executed, you could put that code on a hidden button (it must be rendered, but could be hidden from the screen with CSS) and trigger a click() event on that button with client-side JavaScript.

_

Adding Bootstrap Error Styling to a Select2

In this excellent post, Mark Leusink shows how to create a reusable control that makes it easier to create Bootstrap-styled fields with labels and field validation. While using a similar concept — computing the class of the div around a field based on whether there’s an error in the field — I found that Select2 fields need a little bit of extra work to display with the error styling.

Boostrap looks for an error class in the div surrounding a field and label and it styles them accordingly. See Mark’s post for a more detailed explanation.

This works well in general, but Select2 fields are different, because they are generated on the front end as the page is loaded. The same thing happens with dojo-enabled fields (date and time pickers, etc) — the lose some styling that you try to define when they’re rendered on the page.

Adding the error class to the div around a Select2 will not cause it to pick up error styling. However, with a little CSS, you can easily update a Select2 field to be highlighted in red if the surrounding div contains the error class.

/* Styling for Select2 with error */
div.has-error ul.select2-choices {
  border-color: rgb(185, 74, 72) !important;
}

This looks for a div with the error class (which is has-error in Bootstrap 3) and then locates a ul with the class select2-choices within that div. I just found this by looking at the generated html and trying classes on different elements until it worked.

The CSS sets the border color to the same color that it sets other error fields. I found that by flagging a field as an error and checking the styles that it picked up.

The good news is that these 3 lines of CSS will do the trick for any instance of a Select2 that’s contained in a div that’s flagged as an error.

Note

I’m using Bootstrap 3, so the class names are a little different than on Mark’s page, but the concept remains the same.