Docs

Everything You Need to Know

Tutorials

Migrating

Upgrading from version 4.x? Click here.

Coming from Version 3.x?

ChocolateChip-UI version 5 is based on ES6. It uses classes, spread operators, const/let, promises, etc. If you are not yet familiar with ES6, you will want to go and spend a day learning it before trying to grasp how this version differs from 3.x. You can also read the online book about ES6 by Dr. Axel Rauschmayer.

Although version 5 may seem very different from version 3 at first glance, it's a natural progression of concepts embodied in earlier versions of ChocolateChip-UI: layouts and styles to mimic native mobile UI, simple markup, templates for rendering data and widgets. Just take your time learning how version 5 works.

One of the big changes from version 3 to 5 is how layouts are created. In version 3, the user screen was created with a combination of a nav and article tag side by side. In version 5 screens are created using a ui-screen tag, and tha nav tag is included inside of it, instead of before it. After the nav tag is a section tag, which holds all the screen's content. To learn more about layouts, read their documentation.

Less Hand Written Markup

Version 3 relied heavily on a lot of hand written markup: navigation lists, tab bars, etc. In contrast, version 5 depends on html containers and render functions that create optimal markup dynamically. The render function is designed to create nodes, and finish painting and compositing very fast. We're talking micro seconds. For example, in version 3 you would manually code screens for navigation lists. In version 5 you would use routing and have only one screen that the navigation list goes to, using routing parameters to render the content of the destination screen.

Components

In version 3, you had to define a template using string concatenation and a custom template language. This was then passed to the $.template() function, which parsed it and returned a function. To this you would then have pass data and then append it to the document. So much work. Version 5 uses a class called Component. You create a new component instance, defining a render function that takes an ES6 template literal and data, which it can process and automatically insert into the designated container.

No Repeater!

Version 3 used $.template.repeater to output lists, etc. No need for such things in version 5. If your data is a single object, it will render just once. However, is your data is an array of objects, the component can see that and will automatically iterate over it and output all the objects for you. So much simpler. On top of that, a component can be bound to a State object. When state changes, perhaps through some user interaction, the component will update automatically.

Below is an example of a component:

// Markup in document for list:
<ul id='peopleList'></ul>

// JavaScript for component:
const list = new Component({
  element: '#peopleList',
  render: (person) => html`
    <li>
      <h3>${ person.firstName }</h3>
      <h4>${ person.lastName }</h4>
    </li>`
})
// And array of person objects for our component:
const people = [
  {
    firstName: 'Joe',
    lastName: 'Bodoni'
  },
  {
    firstName: 'Sarah',
    lastName: 'Calhoun'
  },
  {
    firstName: 'Tom',
    lastName: 'Ferguson'
  }
]
// Pass data to component to render to document:
list.render(people)

Below are two examples of components:

See the Pen Template with Object V5 by Robert Biggs (@rbiggs) on CodePen.


See the Pen Template with Array of Objects V5 by Robert Biggs (@rbiggs) on CodePen.

Components can also have events, called actions, and component specific styles. To learn more about components, check out the following documentation:

  1. Components: Tutorial
  2. Components: Intro
  3. Components: Use
  4. Components: Styles
  5. Components: API
  6. Templates: Intro
  7. Templates: Use

Widgets

Version 3 had an assortment of widgets such as Slide Out, Tab Bar, Paging, Toggle Panel, etc. In version 5 these are created using Es6 classes. Each widget has its own class. Depending on what the widget does, it may have a render function just like components. To learn more about widgets, pop over to the documentation for them.

Coming from Version 4.x?

If you're coming from version 4.x, think of version 5 as a refinement of what version 4 was doing. Although you could use ES6 with version 4, version 5 is itself written in ES6. We fully embrace the future of JavaScript and are excited about all the amazing features that have come and continue to come to this platform. As such, when you create a new project with version 5, you automatically get a project setup to use Rollup and Babel. This lets you use the latest and greatest features of JavaScript while supporting older phones.

Layout

Some tag names for layout and widgets have changed. This was to align with the recommended naming convention for the custom element specification. All custom tags now start with "ui-". So screen is ui-screen, switch is ui-switch, stepper is ui-stepper, scroll-panel is ui-scroll-panel, etc. Pop over to the documentation for widgets to learn more.

Weight Loss

One of the things we wanted to do with version 5 was reduce the footprint. For this end we looked at what we could live without. A lot of things were eliminated. We no longer automatically include polyfills for promises, fetch, etc. Providing polyfills are now your concern. Be aware that if you need to support Android Jellybean or Kitkat, you will need to include a polyfill for promises. You can include an promise polyfill in your project's js folder and put a script tag to import it before the script tag for chui.min.js. Version 5 does not include anything for Ajax type data acquisition. These days all modern mobile browsers on iOS and Android support fetch natively. However, if you need to support Android 4.x, you'll need to include a polyfill for it. You have two choices: fetch polyfill and unfetch, a minimal version of the fetch API. Whichever you chooose, put its script tag anywhere after the chui.min.js tag in your index.html file, but before the app.js script tag.

We also dropped quite a few of the jQuery compatible DOM methods. There are still a few, in case you need them. But, seriously, you shouldn't need them. Any kind of manipulation of the DOM should be done through components. So, next up are components.

Views vs Components

Whereas in version 4 you used Views with Models to output data to the document, in version 5 you will use Components and State objects. These are very similar. First lets look at what changed between Views and Components. Components are ES6 classes, so you need to use the new keyword to make a new component. Whereas Views have a template property that holds a string template, Components have a render function that returns an ES6 template literal. This means that the special delimiters that View templates used are gone. Instead you'll use the ES6 template literal interpolation delimiters. Also, with template literals there is no need to escape new lines with back slashes. Below is a version 4 View:

// version 4 View:
  var luminariesView = $.View({
  element: '#repeaterWithImages', 
  model: LuminariesModel,
  name: 'luminariesView',
  variable: 'person',
  template: 
  "<li class='comp'>\
    <img data-src='{= person.image }'>\
    <div>\
      <h3>\
        {= person.firstName } {= person.lastName }\
      </h3>\
    </div>\
  </li>",
  events: [
    {
      element: 'li',
      event: 'tap',
      callback: function() {
        console.log($(this).text());
      }
    }
  ]
});

In version 5, because we are using ES6 template literals, there is no need for variable property. Also no need for a name for a component. And instead of model, we use the state property. Events are now call actions. Here's the same View rewritten as a component in version 5:

// version 5 Component:
  const luminariesComponent = new Component({
  element: '#repeaterWithImages', 
  state: luminariesState,
  render: (person) => html`
    <li class='comp'>
      <img src='${ person.image }'>
      <div>
        <h3>
          ${ person.firstName } ${ person.lastName }
        </h3>
      </div>
    </li>`,
  actions: [
    {
      element: 'li',
      event: 'tap',
      callback: function() {
        console.log($(this).text());
      }
    }
  ]
});

As you can see, components are very similar to version 4's views. Their API and code surface has been greatly simpified, making components easier for use to maintain. Also using ES6 template literals are a basis for how data gets rendered to the DOM has given us a huge increase in speed. DOM renders can sometimes be completed in as little as 10 milliseconds.

There's no need for startIndexFrom or $.index in version 5 because you can capture the loop index directly in the component's render function:

// Loop over array:
const peopleComponent = new Component({
  element: '#peopleList',
  // Use "idx" to capture the loop index
  // and output it in the template:
  render (person, idx) => html`
    <li>
      <h3>${ idx + 1 }: ${ $.view.index }: Name: ${ data.name.first } ${ data.name.last }</h3>
    </li>`
})

Version 4 you have to set a view's safeHTML to true so that the view renders markup in its data. Version 5 also escapes data by default, but has no safeHTML property. Instead you put an exclamation point directly in front of a dolar sign curly brace delimiter:

const peopleComponent = new Component({
  element: '#peopleList',
  // Render any markup in data using "!":
  render (person) => html`
    <li>
      <h3>Name: !${ data.name.first } !${ data.name.last }</h3>
    </li>`
})

Because components use a function to render templates based on ES6 tempate literals, version 5 has no need for version 4's $.defineHelper() method. You can simply define a helper method and invoke it in the component's template. You can also easily create template partials to use in a component. Pop over to the documentation for components to learn more about template helpers and read about partials too.

From View to Component

Although similar, components are less complicated. Version 4 views have the following initialization options:

  1. element
  2. variable
  3. data
  4. model
  5. template
  6. safeHTML
  7. startIndexFrom
  8. events
  9. styles

In contrast, version 5 components have the following initialization options:

  1. element
  2. state
  3. render
  4. actions
  5. styles

Version 4 view objects have the following functions:

  1. render()
  2. empty()
  3. resetIndex()
  4. startIndexFrom(number)
  5. getTemplate()
  6. setTemplate(template)
  7. isRendered()
  8. isEmpty()
  9. getElement()
  10. setElement(element)
  11. addEvent(events, replace)
  12. setModel(myModel)
  13. unbindModel(myModel)
  14. off(event, element, callback)
  15. safeHTML(true/false)
  16. isEscapingHTML()
  17. getData()
  18. setData()
  19. mount()

In contrast, version 5 component instances have the following methods:

  1. render()
  2. empty()
  3. setTemplate(template)
  4. setState(state)
  5. mount()

As you can see, components are so much simpler and straightforward than views. Converting apps from version 4 to version 5 is not that hard. We converted our reference apps in a few hours.

Widgets

All the widgers from version 4 are still there, and they to a ton of bug fixes. Their functionality has not changed much. Widgets have all been converted to ES6 classes, so you create a new one using the new keyword. Some widgets also make use of a render function, just like components. Pop over to the documentation on widgets to see what has changed. Pay attention to how version 5 widgets are initilized. Heads up: editale lists are different. You can now tap and hold to drag a movable list item to a new location in the list.

Models vs State

Version 4 has $.Model, but version 5 has an ES6 class State. Version 5's State class creates data abstraction objects that are very similar to version 4 Models. The conversion to State class fixed some subtle bugs that Models suffered from. State also has a simpler, cleaner and easier to maitain API. Whereas Models have methods such as stop() and start(), version 5 State has a paused property. Setting it to true stops the State from updating bound components when the State's data is modified. Setting the paused property to false, will allow the State object to update the bound components next time its data is changed. You can force bound components to update by executing renderComponents() on the State instance:

// Create a state object:
const peopleState = new State([
  {
    name: 'Joe Bodoni'
  }
])
// Bind component to the State object:
const peopleComponent = new Component({
  element: '#peopleList',
  state: peopleState,
  render: (person) => html`
    
  • ${ person.name }
  • ` }) // Pause the state object: peopleState.paused = true // Add data to peopleState: peopleState.push({ name: 'Jane Doe' }) // Unpause State object: peopleState.paused = false // Update component: peopleState.renderComponents()

    Pop over to the documentation for State to learn how to use it.