Archive | December 2013

Resizing a Bootstrap 3 Modal

The Twitter Bootstrap modal is a very slick dialog that you can easily use within XPages. In this post, I’ll show how to increase the size of modals globally. I’ll also show how to re-center the modal if you resize the body with CSS.

Resizing a Modal

The bootstrap modal uses the class modal-dialog. By default, it is 600px wide.

To widen it, use CSS to increase the width.

.modal-dialog {
  width: 900px;
}

This updates the modal size and allows it to be centered properly when launched.

However, if you increase the size on the modal content area or body, it will not re-center properly. (This may happen if you don’t want to globally resize all modals or if you have a reusable control for modals, but your content changes and you want to re-size some instances.)

.modal-content {
  width: 900px;
}

If you display this modal, you’ll notice that it’s no longer centered.

Modal_NotCentered

Centering a Modal with the Body Resized

In order to center it, you can add another line of CSS to set a negative value for the left margin.

Since the modal is automatically centered based on a width of 600px, you want to move it back to the left by half of the additional width.

Left Margin = (600px – [New Width]) / 2

In this example, the new width is 900px, so the left margin is (600-900)/2 = -150px

Here’s the updated CSS:

.modal-content {
  width: 900px;
  margin-left: -150px;
}

Now the modal will be centered.

Modal_Centered

Advertisements

Conditionally Render an Event Handler

One of the great features of XPages is that so many properties can be computed dynamically. One such property that you may not have realized is that you can even dynamically determine whether to render event handlers. In this post, I’ll show you how.

I first used this feature when using a repeat control to generate a link for every letter in the alphabet in order to jump to a specific place in a view. However, I wanted to disable the letters where there was no matching data, so I didn’t want the click to send a server request in that case.

To show it more clearly here, I’ll demonstrate a simpler example.

This code shows a repeat control that will display a link for the letters A through J. A click on any link will run client-side JavaScript to pop up an alert to display that letter.

<xp:repeat id="repeat1" rows="30" indexVar="rptIndex" var="rptVar">
  <xp:this.value>
    <![CDATA[#{javascript:return ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];}]]>
  </xp:this.value>
  <xp:link escape="true" text="#{javascript:return rptVar;}" id="link1">
    <xp:eventHandler event="onclick" submit="false">
      <xp:this.script>
        <![CDATA[alert('#{javascript:rptVar}');]]>
      </xp:this.script>
    </xp:eventHandler>
  </xp:link>
     
</xp:repeat>

If you switch to the page source and click on the tag, you’ll find a rendered property. Just add logic there to conditionally determine whether to render the event handler.

In this example, I’m checking the repeat index and only rendering event handlers for even-numbered entries in the repeat control (0, 2, 4, 6, 8, etc.)

Blog_ConditionalEventHandler

This code shows the repeat control with the added rendered condition on the event handler.

<xp:repeat id="repeat1" rows="30" indexVar="rptIndex" var="rptVar">
  <xp:this.value>
    <![CDATA[#{javascript:return ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];}]]>
  </xp:this.value>
  <xp:link escape="true" text="#{javascript:return rptVar;}" id="link1">
    <xp:eventHandler event="onclick" submit="false">
      <xp:this.script>
        <![CDATA[alert('#{javascript:rptVar}');]]>
      </xp:this.script>
      <xp:this.rendered>
        <![CDATA[#{javascript:return rptIndex % 2 == 0;}]]>
      </xp:this.rendered>
    </xp:eventHandler>
  </xp:link>
     
</xp:repeat>

Now, the odd-numbered links will not do anything when clicked, because their event handler is not rendered.

Published in The VIEW: Article on Reusable Message Display Control for XPages

The first article of a two-part series by myself and the estimable Troy Reimer has been published in The VIEW. (Subscription Required)

Reusable and Consistent Message Displays in XPages Part 1: Inline Messages

The goal is to provide an easy way to display consistent messages to the user with a single line of code, but to style them and fit inline them within the application in a way that looks much better than, say, a client-side JavaScript popup. This article shows how you can easily display all 4 types of OneUI-styled messages (Confirmation, Error, Warning, Info) at any time and from any page in the application.

Part 2 will demonstrate reusable message controls that function as dialogs — one with OneUI styling and one with a Twitter Bootstrap modal.

Abstract

The separation of client-side and server-side logic in XPages (read: web) applications increases the complexity of communicating consistently with users. In this series, we demonstrate several implementations of reusable message controls that save development time by being easy to implement and help improve the user experience by providing consistently formatted inline messages. Options include OneUI and Twitter Bootstrap styling as well as client-side and/or server-side triggers, so you can choose what works best for your application.

JavaScript Tip: Checking Multiple Cases in a Switch Statement

I recently worked on a JavaScript function that used a switch statement to branch the logic based on a certain value, but each action applied to multiple different cases. It would be overkill to repeat the same logic in multiple case statements. Fortunately, JavaScript can handle this, although the structure of the code might not be what you’d expect.

My instinct is to try something like this:

switch (myVariable)
{
  case "A", "B", "C":
    // Do something
    break;
  case "D", "E":
    // Do something else
    break;
  default: 
    // Default case
    break;
}

But that doesn’t work.

The correct syntax makes use of the ‘fall-through’ behavior of the JavaScript switch statement. Once it matches a case, it will keep executing code until it either hits a break statement or the end of the switch.

This code will do the trick:

switch (myVariable)
{
  case "A":
  case "B":
  case "C": 
    // Do something
    break;
  case "D":
  case "E":
    // Do something else
    break;
  default: 
    // Default case
    break;
}

In this example, if the value of myVariable is A, B, or C, it will execute the code under case "C":.

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.

Set the Bootstrap class for all multiline text fields and labels in XPages with a Theme

In my last post, I showed how to automatically set the class name to pick up Bootstrap styling on all text fields in an XPages application via the theme. In this post, I’ll show how to set the class name on multiline fields and field labels as well.

If I update the form from the last post to include a multiline edit box, it will look this (if I already have the code from the last post included in the theme):

BootstrapTextArea_Labels_Before

The multiline edit box doesn’t match and the field labels also aren’t picking up Bootstrap styling.

This code in the theme will update the multiline edit box controls to pick up the required form-control class:

<!-- Set all multiline inputs to Bootstrap styling -->
<control>
  <name>InputField.TextArea</name>
  <property mode="concat">
    <name>styleClass</name>
    <value>form-control</value>
  </property>
</control>

This code will automatically provide the class to all field labels via the theme:

<!-- Set all labels to Bootstrap styling -->
<control>
  <name>Text.Label</name>
  <property mode="concat">
    <name>styleClass</name>
    <value>control-label</value>
  </property>
</control>

Now, everything on the form is picking up the correct styling:

BootstrapTextArea_Labels_After