Make your dizmos ready for dizmoLive using the Model-View-Controller pattern

We briefly touched on the Model-View-Controller pattern (MVC pattern) in our previous tutorial about How to write a to-do dizmo with backbone.js. The basic idea for this tutorial is to decouple the view (representation) of the data from the data itself:

  • The model takes care of the data.
  • The view takes the data and renders it to the screen
  • The controller orchestrates everything

Dizmos actually follow the MV* pattern, since it really does not require a controller.

Most views are a representation of data. Usually, you would update the view manually after the data changes, because in general, the data changes due to something in the view updating it.

But what if the data changes without a user interaction like in dizmoLive? Or what if you could make sure that every time the data changes, the view is automatically updated? That way, if you add or remove an item to the data, you don’t have to take care of updating the view manually.

dizmoLive

MV* is essential to use when you write a dizmo that is to work with dizmoLive. Only persisted data of a dizmo is replicated over dizmoLive. This means, the state or any other information of a dizmo is only shared across dizmoLive, when it was stored in the dizmo data tree. Assume your dizmo has an input field where users can enter data. By default, the content of the input field will not be shared across dizmoLive as explained above. With dizmoLive however, a user interaction on one side updates the data, which is then replicated to the other side. The change in the data is then reflected in the view, without any user interaction. Let’s implement an example dizmo to show how MV* works in practice.

Start by creating a new dizmo project by:

$ grace new

Name your project “MVCExample” and use the following parameters when asked by grace:

Name: MVCExample
type: dizmo
skeleton: joose

index.html

Next we edit the file index.html to add a slider and an input field. The value of the slider is linked to the input field i.e. when the slider changes, the input field is updated, and vice-versa. Remove the existing html code between div id="front"> and </div>:

<div id="front">
    <div class="center">
        <p>Hello World</p>
    </div>
</div>

and replace it with the two new elements:

<div class="my-slider-div" data-type="dizmo-slider" ></div>
               <br>
               <input class="inputfield" type="text" data-type="dizmo-input">

main.js

Now, we add the function that will be called when the user changes the slider position. The only thing it does is to save the current slider position to the data storage. Add the function to the methods of the MVCExample class:

// on every change of the slider, update the data
onSliderValueChanged: function(val) {
     MVCExample.Dizmo.save('value',val);
}

Also, add the changeValue function to the same place to update the slide and the input field with the data that was saved:

// change both the value of the inputfield and the slider
changeValue: function(val) {
     DizmoElements('.inputfield').val(val);
     DizmoElements('.my-slider-div').dslider('value',val);
}

Note: If the two elements were not linked as in our example, you would add two functions that update the elements.

In the existing initEvents method, we also need to initialize the slider and let it know which function to call when the slider position changes (the one we just wrote above):

DizmoElements('.my-slider-div').dslider({
      max: 100,
      min: 0,
      step: 1,
      onSliderMoved: function(val) {
          // console.log("move " + val);
          self.onSliderValueChanged(val);
      }
  });

DizmoElements('.my-slider-div').dslider('update');

Also add the function that will be called when the content of the inputfield changes (if a keypress is detected). Every time the keycode 13 is detected (Enter), the current value of the input field is saved to data storage.

// on every change of the inputfield, update the data
DizmoElements('.inputfield').keypress(function(e) {
                if (e.which == 13) {
                    var value = parseInt(DizmoElements('.inputfield').val());
                    if (value <= 100 && value >= 0) {
                         MVCExample.Dizmo.save('value', value);
                    }
                }
            });

Subscriptions

With subscriptions, as soon data in the storage is changed, a function is called (as opposed to a method that checks continuously if the data has changed). The dizmo API supports subscriptions. In our dizmo, we’ll update the slider and the inputfield as soon as we detect a change of the saved data.

We have now decoupled the view and the data from each other. Which means, when sharing the example dizmo through dizmoLive, a slider position change saves the data, which is then replicated to the other dizmoLive partner. And there, the subscription is called and updates the slider position … nifty!

// subscriptions
MVCExample.Dizmo.subscribe('value', function(value) {
    self.changeValue(value);
});
MVCExample shared over dizmoLive dizmo - Decouple view of data

MVCExample shared over dizmoLive

Get the source code

You can find the source code on Github.

git clone git@github.com:dizmo/MVCExample.git

Leave a Reply

Your email address will not be published. Required fields are marked *