XPages and Me

My Journey into XPages Development

Dabbling in Bootstrap and Font Awesome Part 6-1: (re)Use Me!

Important: Please see this update regarding the column custom control

Now you got Bootstrap and / or Font Awesome set up for you XPages development environment and you are ready to develop some cool applications. However, you come to find out that developing while using the Bootstrap framework can be rather tedious. Bootstrap utilizes a grid system that allows you to put content pretty much anywhere on a web page, but it also means adding more divs for the rows and columns.

On top of that, to have just one field rendered Bootstrap style, it involves a lot: A div, label, field, help block etc. This kind of blows the quick development we are used to in XPages by drag-and-drop, out of the water.

I was looking for a way to make it easier and quicker again and, inspired by Mark Leusink’s post on a reusable field custom control for Bootstrap, I started to create all kinds of custom controls for all the different field types. Halfway thru creating them though I realized, that still doesn’t make it easier. Especially if you wanted to do something out of the ordinary with a field, you wouldn’t be able to use these custom controls, you’d have to create everything manually for this one field.

So, after some thinking, fiddling and trying out, I came up with a set of three reusable custom controls, to speed up the development process again:

A Row custom control

A Column custom control

A “Control wrapper” custom control

In this post, I will show you how to create them and the next post will be about, how to use them. So, lets get started:

Row Custom Control:

Create a new custom control and give it a name (I named mine ccSYS_Row). Add a XPages div to it. As it is not in the list of Container Controls, double-click on “Other…” and from the prompt, open the category “Container Controls”, select Div and click OK:

Image 7

Select the div and set the style class to “row”. Drag-and-drop an editable area into the div and remove the “Facet Name” and type a name into the field “Name” (I named mine “callbackRow”):

Image 11

Your source code should now look like this:

<?xml version='1.0' encoding='UTF-8'?>
<xp:view xmlns:xp='http://www.ibm.com/xsp/core'>
    <xp:div id='divRow' styleClass='row'>
        <xp:callback id='callbackRow'></xp:callback>
    </xp:div>
</xp:view>

From the custom control properties, select “Design Definition” and copy the following XSP markup into it:

<?xml version='1.0' encoding='UTF-8'?>
<xp:view xmlns:xp='http://www.ibm.com/xsp/core'>
    <xp:panel>
        Row <br></br>
        <xp:callback></xp:callback>
    </xp:panel>
</xp:view>

What this will do is, when you drag-and-drop the custom control, all you’ll see is the word “Row” and the editable area square, which will make your custom control easier to read and save space:

Image 1

Save and close your custom control

Column Custom Control:

Create another custom control and give it a name (I named mine ccSYS_Column). As with the row custom control, add a XPages div. Drag-and-drop an editable area into the div, Remove the “Facet Name” and type a name into the field “Name” (I named mine “callbackColumn”):

Image 12

Open the custom control’s “Property Definition” tab and add a new group named “columnWidth”:

Image 2

Select the first property of the group, rename it to “mobileDevice”. Type is “String” and as an editor, select “ComboBox”. In the parameter box, enter the values 1 – 12:

Image 3

Select the “Validation” tab and deactivate the option “Required Field”:

Image 4

Add three more properties to the group and name them “tabletDevice”, “desktopDevice” and “desktopDeviceLg” and apply the same settings we did for “mobileDevice”. Once you are done, it should look like this:

Image 5

Next, add another group and name it “columnOffset”. Add the same properties with the same settings as we did for the “columnWidth” group. Once you are done, your design properties should look like this:

Image 6

Now, select the div we added earlier and open then “Style” tab. Click on the blue diamond beside the field “Class” and in the prompt, enter the following JavaScript code:

//Declarations
    //String
    var sXSWidth:String = compositeData.columnWidth.mobileDevice;
    var sSMWidth:String = compositeData.columnWidth.tabletDevice;
    var sMDWidth:String = compositeData.columnWidth.desktopDevice;
    var sLGWidth:String = compositeData.columnWidth.desktopDeviceLg;
    
    var sXSOffset:String = compositeData.columnOffset.mobileDevice;
    var sSMOffset:String = compositeData.columnOffset.tabletDevice;
    var sMDOffset:String = compositeData.columnOffset.desktopDevice;
    var sLGOffset:String = compositeData.columnOffset.desktopDeviceLg;
    
    var sStyleClass:String = '';
    
//Determine style of the column
    //Extra small columns, for mobile devices
    if(sXSWidth != null){
        sStyleClass += ' col-xs-' + sXSWidth;
    }
    
    if(sXSOffset != null){
        sStyleClass += ' col-xs-offset-' + sXSOffset;
    }
    
    //Small columns, for tablets
    if(sSMWidth != null){
        sStyleClass += ' col-sm-' + sSMWidth;
    }
    
    if(sSMOffset != null){
        sStyleClass += ' col-sm-offset-' + sSMOffset;
    }
    
    //Medium columns, for desktops
    if(sMDWidth != null){
        sStyleClass += ' col-md-' + sMDWidth;
    }
    
    if(sMDOffset != null){
        sStyleClass += ' col-md-offset-' + sMDOffset;
    }
    
    //Large columns, for extra large desktops
    if(sLGWidth != null){
        sStyleClass += ' col-lg-' + sLGWidth;
    }
    
    if(sLGOffset != null){
        sStyleClass += ' col-lg-offset-' + sLGOffset;
    }
    
    return sStyleClass.trim()

So, what does this do? It will read the information you’ll set when using the column and based on your settings, applies the styles to the column. For further information on how the Bootstrap Grid System works, please have a look here.

Lastly, select “Design Definition” from the custom control properties and copy the following XSP markup into it:

<?xml version='1.0' encoding='UTF-8'?>
<xp:view xmlns:xp='http://www.ibm.com/xsp/core'>
    <xp:panel>
        Column <br></br>
        <xp:callback></xp:callback>
    </xp:panel>
</xp:view>

Save and close your custom control

Control Wrapper Custom Control:

Create another custom control (I named mine “ccSYS_ControlWrapper”), go to the “Property Definition” tab and add the following properties:

Name: Type: Editor: Parameters: Validation
labelText String -none- Required field: No
helpBlockText String -none- Required field: No
fieldID String -none- Required field: No
formGroupSize String ComboBox Large|form-group-lg
Small|form-group-sm
Required field: No

Select “Design Definition” and copy the following XSP markup into it:

<?xml version='1.0' encoding='UTF-8'?>
<xp:view xmlns:xp='http://www.ibm.com/xsp/core'>
    <xp:panel>
        Control Wrapper <br></br>
        <xp:callback></xp:callback>
    </xp:panel>
</xp:view>

Next, add a div to the custom control. Select the div and give it a name if you’d like (I named mine “divFormGroup”), open the Style tab and beside the field “Class” click on the blue diamond and select “Compute value…”. In the prompt, enter the following JavaScript code:

//Declarations
    //String
    var sFieldID:String = compositeData.fieldID;
    var sGroupSize:String = compositeData.formGroupSize;
    var sStyleClass:String = 'form-group';

//Check if a fromGroupSize was selected and if so, add additional style class to form-group
    if(sGroupSize != '' && sGroupSize != null){
        sStyleClass += ' ' + sGroupSize;
    }

//Check if the a fieldID was passed on. If so, we can check the fields validity and add error classes as needed.
    if(sFieldID != '' && sFieldID != null){
        sStyleClass += (getComponent(compositeData.fieldID).isValid() ? '' : ' has-error');
    }

//Apply Style
    return sStyleClass;

Click OK to save the code. The script will check the properties you pass along when you use the custom control. As a default, it will apply the style class “form-group” to the div. Then, if you selected any of the values for the property definition “fromGroupSize”, it will add this class to “form-group”. Next, it checks if you passed on a fieldID. If so and you did add some validation to this field (i.e. mandatory) and it comes back as not valid, it will add the class “has-error”.

Now drag-and-drop a label, editable area and a computed field into the div:

Image 13

Select the label, open the “All Properties” tab and under the section “basics” locate the property “for”, click on the blue diamond beside it and select “Compute value…”. In the prompt, select “Expression Language” from the language ComboBox and type in the following expression:

compositeData.fieldID

Enter a name for the label in the field “id” (I named mine “lblControl”), select the “loaded” property, click on the blue diamond and select “Compute value…”. In the prompt, select “Expression Language” from the language ComboBox, select “Compute on Page load” and type in the following expression:

!empty compositeData.labelText

This will make sure, the label will only be rendered if you actually passed on a value for the property definition “labelText”.

Under the section “data”, select the property “value”, click on the blue diamond beside it and select “Compute value…”. In the prompt, select “Expression Language” from the language ComboBox, select “Compute on Page load” and type in the following expression:

compositeData.labelText

Lastly, scroll down to the “styling” section and enter “control-label” into field “styleClass”.

After you are done, the all properties section should look something like this:

Image 8

Select the editable area, remove the value from the field “Facet name” and type a name into the “Name” (I named mine “callbackControl”). The editable area should now look like this:

Image 9

Select the computed field, open the “All Properties” tab and under the section “basics” locate the property “escape” and make sure it is set to “true”. Enter a name for the computed field in the field “id” (I named mine “idTxtHelpBlock”), select the “loaded” property, click on the blue diamond and select “Compute value…”. In the prompt, select “Expression Language” from the language ComboBox, select “Compute on Page load” and type in the following expression:

!empty compositeData.helpBlockText

This will make sure, the computed field will only be loaded if you actually passed on a value for the property definition “helpBlockText”.

Next, under the section “data”, select the property “value”, click on the blue diamond beside it and select “Compute value…”.

In the prompt, select “Expression Language” from the language ComboBox, select “Compute on Page load” and type in the following expression:

compositeData.helpBlockText

Lastly, under the section “styling”, select the property “style-class” and type “help-block” into it.

After you are done, the all properties section should look something like this:

Image 10

Save and close the custom control

Now you’ve got all the tools at hand to quickly develop applications with bootstrap. In the next post, I will show you how to use them.

Advertisements

11 responses to “Dabbling in Bootstrap and Font Awesome Part 6-1: (re)Use Me!

  1. DavidLeedy (@DavidLeedy) August 10, 2014 at 8:46 pm

    Please make videos and come on NotesIn9.
    Please make videos and come on NotesIn9.
    Please make videos and come on NotesIn9.
    Please make videos and come on NotesIn9.
    🙂

    P.S. The next Ni9 will likely be making a bootstrap custom control for progress bars.

  2. Ursus Schneider August 25, 2014 at 9:20 am

    I followed your instructions to the tee and must say well done – any idea when you are going to create your “using” post?

    • Daniel Friedrich August 25, 2014 at 1:33 pm

      Hello Ursus, thank you for your comment, glad it works for you. I am currently working on a video to be published on Ni9 for the second part that will explain a little bit how the Bootstrap grid works and then show, how to use the Custom Controls.

      Hopefully, I’ll have it done by next weekend.

      • Ursus Schneider August 25, 2014 at 3:44 pm

        Hi Daniel – Thank you very much – am looking forward to the video :o) Keep up the good work!

  3. Pingback: Dabbling in Bootstrap and Font Awesome Part 6-2: (re)Use Me! | XPages and Me

  4. Csaba Kiss December 9, 2014 at 1:52 am

    Daniel,
    How would you style your bootstrapRow custom control? Would you add a new property?

    • Csaba Kiss December 9, 2014 at 1:59 am

      Let me ask another way? How would you add another class to the bootstrapRow custom control?

      • Csaba Kiss December 9, 2014 at 6:06 am

        I think I will just answer my own question. Instead of modifying the bootstrap row class with a custom css, I will just wrap the particular row in a div and modify that with css styling

    • Daniel Friedrich December 9, 2014 at 2:11 pm

      Hello Csaba,

      the only thing I would change for the row and column Bootstrap classes, is may be the padding.

      Other than that, I wouldn’t recommend changing anything else in these classes, as they are the backbone of Bootstrap, allowing it to rearrange the rows and columns if the screen size changes.

      Bootstrap’s rows and columns are really just used to arrange your UI, they don’t do much else.

  5. Don Mottolo March 16, 2015 at 2:10 pm

    I’m looking at the best way to integrate Bootstrap and Domino, and am thinking that it might make sense to use the latest Extension Library (which has Bootstrap4XPages ) to take care of much of it (like renderers for standard XPages controls), but also create custom row and column controls (to use for page layouts where you don’t want to use the Application Layout control). Any thoughts? Pros & cons?

    • Daniel Friedrich March 16, 2015 at 2:35 pm

      Hello Don,

      that does make sense. As I mentioned before, the reason I am not using the bootstrap4XPages extension library is, it gives me greater freedom of applying the latest releases of Bootstrap, Bootstrap Date Picker, Font Awesome, Select2 etc.

      All the required css and js files are in one web resources database and I reference them in my themes. I don’t have to rely on the Domino admins to install the extension library packages on all the production servers (of which we have quiet a few). All that is needed is to replace the design of the web resources database and replication takes care of the rest.

      I don’t think there are really big pros and cons, just what works best for you, your situation and environment.

      One con doing it my way would be, that the developers have a bit of a learning curve regarding Bootstrap, but that is not necessarily a bad thing.

      I hope my answer makes sense.

      Let me know if you have any other question :o)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: