Ognjen Regoje bio photo

Ognjen Regoje
But you can call me Oggy


I make things that run on the web (mostly).
More ABOUT me and my PROJECTS.

me@ognjen.io LinkedIn

Evolution of templates in JS

#technical

The early days

In the beginning there was the all-powerful onclick:

<button onclick="javascript: increment()">Increment</button>
<div id="count">0</div>
<script type="text/javascript">
  var count = 0;
  var el = document.getElementById("count");
  function increment(){
    count++;
    el.innerHTML = count;
  }
</script>

End the obtrusiveness

But then as we evolved, we thought: “How barbaric”. So, we decided that JavaScript needed to not be obtrusive, it needed to be unobtrusive. And lord jQuery would help us with that.

<button class="incrementer-buttom" data-target="#count">Increment</button>
<div id="count">0</div>
<script type="text/javascript">
  var count = 0;
  $("body").on("click", ".incrementer-button", function(){
    count++;
    $($(this).data("target")).html(count);
  });
</script>

We might even do some append or replaceWith.

And we were unobtrusive and all was good.

The logic and template schism

Still we evolved and thought: “How primitive”. So, we decided that the logic and the templates need to be separate. And we bowed our Backbone.

<script type="text/template" id="counter-template">
  <div id="incrementer">
    <button class="incrementer-buttom">Increment</button>
    <div><%= count%></div>
  </div>
</script>
<script type="text/javascript">
app.CounterView = Backbone.View.extend({
  template: _.template($('#counter-template').html()),
  events: {
    'click .incrementer-button': 'increment'
  },
  initialize: function () {
    this.listenTo(this.model, 'change', this.render);
  },
  render: function () {
    this.$el.html(this.template(this.model.toJSON()));
  },
  increment: function () {
    this.modal.save({
      count: this.get('count')++
    });
  }
});
</script>

And we had models and collections and separation of duties and all was good.

The binding

And yet the spark of change was there and we evolved yet again and thought: “How simplistic”. So, we decided that we needed to have our data bound. And we had a new Vue.

<div id="incrementer">
  <button class="incrementer-buttom" @click.stop.prevent="count++">Increment</button>
  <div>{ {count} }</div> <!-- Extra space because of Jekyll templating-->
</div>
<script type="text/javascript">
  app.CounterView = new Vue({
    el: '#incrementer',
    data: {
      count: 0
    }
  });
</script>

And the data was bound and all was good.

And then we went full circle

And then we evolved yet again. Or did we?

<div id="incrementer"></div>

<script type="text/javascript">
  var Incrementer = React.createClass({
    getInitialState: function () {
      return {
        count: 0
      };
    },
    increment: function (event) {
      this.setState({count: this.state.count++});
    },
    render: function () {
      return (
        <div>
          <button className="incrementer-button" onClick={increment}>Increment</button>
          <div>{this.state.count}</div>
        </div>
      );
    },
  });

  React.render(
    <Incrementer/>,
    document.getElementsByClassName('incrementer')[0]
  );
</script>

Wait, we are obtrusive, and we’re basically concating so we don’t have templates, the responsibilties are all mixed up, we technically do have data bound but so did Backbone…

Go back, go back!

It reminds me of this:

Evolution of templates in JS

Image from TeePublic