Bootstrap Logo Twitter Bootstrap is a popular CSS & JavaScript library for rapid web-development, encompassing CSS and JavaScript.

This article shows how easy it is to incorporate Bootstrap into BedSheet web applications using Duvet.

Contents:

Bootstrap

A standard snippet of Bootstrap javascript looks like:

$("#element").carousel();

It looks innocuous but let's dissect it...

  • $("#element") calls jQuery, returning a DOM element,
  • .carousel() calls a Bootstrap plugin that's been registered with jQuery.

This means before our line of Javascript will work, both jQuery and the Bootstrap javascript library have to have been loaded - and in that order too!

Damn, it's getting complicated! But fear not, to the rescue there is...

RequireJS

RequireJS is the new black for defining and loading JavaScript in web applications. It looks after your javascript dependencies, ensuring they are loaded in the correct order and available to your scripts. This article on How To Use Bootstrap 3 With RequireJS does a great job at explaining how to use RequiresJS to do just that.

Hand crafting RequireJS configuration shims is not everyone's cup of tea, so for automating the process in a BedSheet web application, there is...

Duvet

The Duvet library from Alien-Factory wraps RequireJS, giving it a simple Fantom API.

Configuration

Duvet is an IoC library for use with BedSheet web applications. Like most IoC applications, you configure it via your AppModule class. Below we configure Duvet to use jQuery and Bootstrap:

select all
using afDuvet

@Contribute { serviceType=ScriptModules# }
Void contributeScriptModules(Configuration config) {
    jquery := ScriptModule("jquery")
        .atUrl(`//code.jquery.com/jquery-2.1.1.min.js`)

    bootstrap := ScriptModule("bootstrap")
        .atUrl(`//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js`)
        .requires("jquery")

    config.add(jquery)
    config.add(bootstrap)
}

The above contribute method adds two ScriptModules to Duvet, one for jQuery and one for Bootstrap.

Note how we've used CDNs for the main download URLs. This makes everything even easier to set up! We could have used client URLs for the scripts, but then we'd have to host the scripts ourselves and configure BedSheet's FileHandler service.

In fact, it's not a bad idea to configure a client URL as a fallback. Then, should the CDN go down RequireJS should use the fallback URL as a backup.

ScriptModule("jquery").atUrl(...).fallbackToUrl(...)

Also note how we've specified the bootstrap script module requires (or depends on) the jquery script module. This means that whenever we reference the bootstrap module, RequireJS will ensure jQuery has been loaded first.

But note that simply configuring Duvet won't add Bootstrap to our web pages. For that we need to inject some javascript...

HTML Injection

We use the bootstrap and jquery modules by injecting Javascript into our page via the HtmlInjector service:

htmlInjector.injectRequireScript(
    ["bootstrap":"bs", "jquery":"\$"],
    "\$("#element").carousel();"
)

This generates the following markup in the webpage:

<script type="text/javascript">
  require(["bootstrap", "jquery"], function (bs, $) {
     $("#element").carousel();
  });
</script>

We specify a dependency on bootstrap even though we don't use the bs variable because we need it to be loaded before the script executes.

Note that Duvet injects code at the bottom of the HTML page by default, so we don't have to wait for a DOM ready function.

As the main feature of Bootstrap is the CSS framework it'd be good to reference that in the web page. To do so, just use HtmlInjector again to inject the stylesheet. Using the CDN again, the code looks like:

htmlInjector.injectStylesheet
    .fromExternalUrl(`//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css`)

Or if we host the CSS ourselves we can use a client URL:

htmlInjector.injectStylesheet.fromClientUrl(`/css/bootstrap-3.3.1.min.css`)

And that's it! Have fun!


Discuss