Search code examples
cyclejs

How to integrate HTML frameworks with Cycle.js?


I was wondering what are the practices to integrate HTML frameworks (bootstrap, uikit) with Cycle.js?

I can see two different approaches:

  1. Have a fairly bulky static HTML that adds all the relevant menus, gadgets, ... of your page, which also loads the cycle app.

  2. Have a minimal HTML file that just loads the cycle app and the cycle app then does everything.

I am currently using solution 1, but I can see it not scaling with more complex pages (as these would make lots of changes to the HTML structure of the page, anyway).

But, in the case of solution 2, what is then the best way of using template frameworks from the cycles programmatic API?


Solution

  • What I'm doing I think is more of a combination of 1. and 2. in your question. All the markup is in a HTML file but it's not static. It's a model that the snabbdom-template module uses to dynamically populate with custom data then returned to CycleJS for rendering into the DOM.

    main.js

    const xs = require('xstream').default
    const run = require('@cycle/run').run
    const makeDOMDriver = require('@cycle/dom').makeDOMDriver
    const st = require('snabbdom-template')
    
    const fs = require('fs')
    const template = fs.readFileSync('template.html', 'utf-8')
    
    function main(sources) {
      return {
        DOM: xs.of(['one','two','three','four'])                    // mock data
          .map(list =>
            st(template, {                                          // call snabbdom-template
              'div#message': {class: 'myclass', '_html': 'Ready.'}, // link selectors and data
              '#mapme': {_map: {'li': list}}
            })
          )
      }
    }
    
    run(main, {
      DOM: makeDOMDriver('#main-container')
    })
    

    Given index.html

    <html>
      <body>
        <div id="main-container"></div>
        <script src="bundle.js"></script>
      </body>
    </html>
    

    ...and template.html

    <div id="message">message goes here</div>
    <ul id="mapme">
      <li>a</li>
      <li>b</li>
      <li>c</li>
    </ul>
    

    ...produces something like

    <html>
      <body>
        <div id="main-container">
          <div id="message" class="myclass">Ready.</div>
          <ul id="mapme">
            <li>one</li>
            <li>two</li>
            <li>three</li>
            <li>four</li>
          </ul>
        </div>
        <script src="bundle.js"></script>
      </body>
    </html>
    

    To run this example create the main.js, index.html, and template.html files, then in your terminal...

    npm i xstream @cycle/run @cycle/dom snabbdom-template brfs
    browserify -t brfs main.js > bundle.js
    open index.html
    

    .


    And here's a UIkit example:

    function main(sources) {
      return {
        DOM: xs.of([ 
          ['one',   'testing 1'],
          ['two',   'testing 2'],
          ['three', 'testing 3'],
          ['four',  'testing 4']
        ])
          .map(function (list) {
            return st(template, {
              '#mapme': {_map: {'li': list.map(function (item, ii) {
                const ret = {'h3.uk-accordion-title': item[0], 'div.uk-accordion-content p': item[1]}
                if ( 0 === ii ) { ret['li'] = {class: 'uk-open'} }
                return ret
              })}}
            })
          })
      }
    }
    

    Given template.html

    <ul uk-accordion id="mapme">
        <li>
            <h3 class="uk-accordion-title">Item 1</h3>
            <div class="uk-accordion-content">
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
            </div>
        </li>
        <li>
            <h3 class="uk-accordion-title">Item 2</h3>
            <div class="uk-accordion-content">
                <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor reprehenderit.</p>
            </div>
        </li>
        <li>
            <h3 class="uk-accordion-title">Item 3</h3>
            <div class="uk-accordion-content">
                <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat proident.</p>
            </div>
        </li>
    </ul>
    

    ...produces something like

    <html>
      <body>
        <div id="main-container">
          <ul uk-accordion id="mapme">
            <li class="uk-open">
              <h3 class="uk-accordion-title">one</h3>
              <div class="uk-accordion-content">
                <p>testing 1</p>
              </div>
            </li>
            <li>
              <h3 class="uk-accordion-title">two</h3>
              <div class="uk-accordion-content">
                <p>testing 2</p>
              </div>
            </li>
            <li>
              <h3 class="uk-accordion-title">three</h3>
              <div class="uk-accordion-content">
                <p>testing 3</p>
              </div>
            </li>
            <li>
              <h3 class="uk-accordion-title">four</h3>
              <div class="uk-accordion-content">
                <p>testing 4</p>
              </div>
            </li>
          </ul>
        </div>
        <script src="bundle.js"></script>
      </body>
    </html>
    

    Which displays like

    UIkit example

    Try an online example here.