Docs

Everything You Need to Know

Components

Template Literals

When you create a component, you usual will give it a render function to create content in your app. In order to do this, it needs a template. These are ES6 template literals. You can use a plain template literal (enclosed in back ticks) or a tagged template literal provided by ChocolateChip-UI: html``. The advantage of html`` is that it automatically escapes all data before rendering. This protects you from malicious script injection. It also handles map functions so you don't have to end them with join('') to prevent "," insertion.

Using JSX Instead of Template Literals

As of version 5.2.0 you can use JSX for templates instead of template literals. It's entirely up to your preference. Both are good choices. Read the documentation to learn more.

Passing Arguments to a Template

A template function expects an argument for the data that will be used in the template. Of course you can define a template that simply returns static markup as well. To interpolate any data, you use ${data}. Here we're expecting that the return method will have a parameter named data. You can use whatever parameter you want for your template:

// Define template function:
const myTemplate = (data) => html`
  <li>
    <h3>
      ${ data }
    </h3>
  </li>`
// Assign template to component:
const myComponent = new Component({
  element: '#myList',
  render: myTemplate,
})
          

We can also use ${} to loop over a piece of data, such as with map on an array:

// Define template function.
// person has array of friends:
const myTemplate = (person) => html`
  ${
    person.friends.map((friend) => `
      <li>
        ${ friend.name }: ${ friend.job }
      </li>`
    })
  }`
// Assign template to component:
const myComponent = new Component({
  element: '#myList',
  render: myTemplate,
})

Unescaping Data

By default, hmlt`` always escapes the data before rendering. This is to protect against malicitious script injection. If you want to allow data with markup to be rendered, you can tell html`` not to escape the data by putting an exclamation point before the dollar sign curly braces:

const person = {
  firstName: 'Joe',
  lastName: '<b>Bodoni</b>'
}
// Escaped data:
html`<p>${ person.firstName } ${person.lastName}</p>`
// Returns <p>Joe &lt;b&gt;Bodoni&lt;/b&gt;</p>

// Unescaped data,
// notice the "!" before the ${}:
 html`<p>!${ data }</p>`
// Returns <p>Joe <b>Bodoni</b></p>
          

Rendering data with markup is a common approach to having formatting in the final output. This is a bad choice. Allowing unescaped data into your app opens up possibilities for malicious hackers. It always best to keep the data simple and let markup in your template handle the formatting needs. Here's the above example redone without the security risk:

const person = {
  firstName: 'Joe',
  lastName: 'Bodoni'
}
// Escaped data:
html`<p>${ person.firstName } <b>${person.lastName}</b></p>`
// Returns <p>Joe <b>Bodoni</b></p>
          

Template Partials

Beause template literals are just JavaScript, you can easily define a helper function, such as a partial to use in your templates. This is useful where you have a piece of template that you need to reuse in different components. Below is a partial and its use. Notice that we have to put "!" before the partial function. This is because without this its template markup we be escaped, rendering it useless.

Escaping Data in a Partial

Since the partial will come through unescaped, you'll want to make sure to escape the data inside the partial. You can do that by passing the data in the partial to ChocolateChip-UI's $.escapeHTML() function inside the ${}:

/* Define template partial to use in component. */
const templatePartial = (somebody) => {
  if (somebody.friends && somebody.friends.length) {
    return html`
      <li>
        <div class='no-flex' style='max-width: 100px;'>
          <h3>Friends:</h3>
        </div>
        <div>
          <ol>
            ${
              somebody.friends.map((friend) => `<li>${ $.escapeHTML(friend.name) }: ${ $.escapeHTML(friend.job) }</li>`)
            }
          </ol>
        </div>
      </li>`
  } else {
    return '';
  }
};
const nestedTemplateComponent = new Component({
  element: '#nestedTemplate',
  template: (somebody) => html`
    <li>
      <aside>
        <img width='80' src='${ somebody.image }'>
      </aside>
      <div>
        <h3>${ somebody.name }</h3>
      </div>
    </li>
    !${templatePartial(somebody)}`
})

The html`` tag function also fixes a problem that template literals have when you use map on an array of data - it automatically removes the join comma that map injects so you don't have to. Notice the difference in the following examples:

// Map without join:
const test1 = ['one', 'two', 'three'].map(item => `<p>${ item }</p>`)
// returns: ["<p>one</p>", "<p>two</p>", "<p>three</p>"]

// Map with join:
const test2 = ['one', 'two', 'three'].map(item => `<p>${ item }</p>`).join('') 
// returns: "<p>one</p><p>two</p><p>three</p>"

// ChocolateChip-UI's html function:
const test3 = html`${['one', 'two', 'three'].map(item => `<p>${ item }</p>`)}`
// retruns: "<p>one</p><p>two</p><p>three</p>"

Capturing a Loop's Numerical Index

You can output sequential numbering in your template when the data is an array. You do this by providing a second argument to your template function. This will be the numerical index of the loop. Use that parameter to output the loop number value. Be aware that the loop sequence always starts with 0, so you may need to add 1 to get a human readable value:

// Use "idx" to capture loop numerical value:
const loopedTemplate = (item, idx) => html`
  <li>
    <h3>
      ${ idx + 1 }: ${ item.title }
    </h3>;
  </li>`

Formatting Output

You may need to format the data you are rendering in a component's template. ChocolateChip-UI provides a number of formatters to help you. These go right in the template where you want the data formated. ChocolateChip-UI has the following formatters:

  • formatNumber
  • sum
  • currency
  • formatTime
  • sortDate
  • sortNumbers
  • sortNumbersDescending

Please see temlates for more information about data formatters.

Using Template Helpers

Depending on your data, you may have the need to do some specialized formating of the data before outputing it. You can do this by definine a function that accepts the data and returns it transformed. Say you wanted a helper to make a name uppercase, you could write a helper function:

const upperCase = (data) => data.lastName.toUpperCase()

You could then use it like so:

const myComp = new Component({
  element: '#name',
  render: (data) => html`<li>${ upperCase(data) }</li>`
})

The above example is very simplified, but it is the technique that is important. You could write any type of function to transform data as needed.

More About ES6 Template Literals

You can learn more about template literals at the Mozilla site and at Exploring ES6.