g1 is a micro-framework collection that makes it easy to write front-end data applications. It’s a humble alternative to Vue.js, AngularJS and React.

It not a framework – more a collection of tools that work together. Sort of like UNIX.

If you need a library to build data applications without a learning curve and low overhead, g1 may be for you.


You can add g1 and its dependencies with a single script tag:

<script src="https://cdn.jsdelivr.net/combine/npm/jquery,npm/lodash,npm/g1"></script>

or install it using:

yarn install jquery lodash g1
# ... OR ...
npm install jquery lodash g1

… and add this to your HTML file:

<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/lodash/lodash.min.js"></script>
<script src="node_modules/g1/dist/g1.min.js"></script>

Render templates

You can create dynamic content from data using templates. To create a template:

  1. Write HTML inside <template>..</template>.
  2. Embed JavaScript inside <% .. %> in the template
  3. Call $(el).template(data).

This renders your template with your data. For example:

<template class="example">
  <% list.forEach(function(item) { %>
    <div>item <%= item %></div>
  <% }) %>
  $('template.example').template({ list: [1, 2, 3] })

Templates use lodash, which is plain HTML and JavaScript. You don’t need to learn a new template language.

TODO: show a full-blown example of this.

URL-based state

Apps shows different content based on what the user requests. A good way to capture this is to store the requests in the URL. This lets the user bookmark the page and share the URL. This URL represents the state of the app.

For example, /view=sales&year=2019 may show the sales in year 2019.

Parse URLs

To parse a URL, use g1.url.parse:

var url = g1.url.parse(location.href)
url.searchKey == {"view": "sales", "year": "2019"}

This can affect what template to render, and what data to render. For example:

<template class="sales">Sales was <%- data %> in <%- q.year %>.</template>
<template class="profit">Profit was <%- data %> in <%- q.year %>.</template>
  var data = {
      sales: {2018: 250, 2019: 260},
      profit: {2018: 50, 2019: 60}
  var q = g1.url.parse(location.href).searchKey
  $('template.' + q.view).template({ data: data[q.view][q.year], q: q })

When the URL is ?view=sales&year=2019, it renders “Sales was 260 in 2019.” When the URL is ?view=profit&year=2018, it renders “Profit was 50 in 2018.”

TODO: show a full-blown example of this.

Change URL state

To change the state, we change the query. For example:

We can do this using <a href="?view=sales&year=2019">. But we usually change only some of the keys at a time (e.g. change year to 2019 without changing view.)

$().urlfilter() makes this easier. <a class="urlfilter" href="?year=2019"> changes just the year to 2019, and keeps other keys constant.

  <li><a class="urlfilter" href="?view=sales">Set ?view=sales, keep the rest</a></li>
  <li><a class="urlfilter" href="?view=profit">Set ?view=profit, keep the rest</a></li>
  <li><a class="urlfilter" href="?year=2018">Set ?year=2018, keep the rest</a></li>
  $('body').urlfilter()         // activates URL filtering on the entire page

TODO: show a full-blown example of this.

Single page apps

Changing the URL reloads the page. To build single page apps that don’t reload, you can store the state in the location hash, like /#?view=sales&year=2019.

To make $().urlfilter() update the hash (instead of the query), use $('body').urlfilter({target: '#'}).

To listen to hash change events, use $(window).urlchange(). For example:

    .on('#?view', function (e, view) { console.log('view is', view) })
    .on('#?year', function (e, year) { console.log('year is', year) })
    .on('#', function (e, url) { console.log('hash is', url) })

TODO: show a full-blown example of this.

Virtual DOM

Normally, re-rendering a template deletes the content and re-creates the DOM elements. But if you use <template data-engine="vdom">, it only updates changed elements. This has 3 advantages:

TODO: show a full-blown example of this.





You can import either g1.min.js – which has all of these functions – or one of the individual libraries below:

mapviewer.min.js is not part of g1.min.js.

For debugging, use dist/g1.js – an un-minified version.