JavaScript Why is m.module not causing my view to rerender in Mithril?

I thought that given an object with controller & view properties, when the controller's state changed (or an m.prop property was changed) it would rerender the template. This isn't happening in my case (I have to use redraw directly). What am I doing wrong here? ////////app.js

define([ 'mithril', 'propertyPane'],
  function(m, propertyPane){
    //div#properties exists
    m.module(document.getElementById('properties'),propertyPane);
});

///////propertyPane.js

define([ 'mithril', 'emitter'],
  function(m, emitter) {

    //mithril "namespace"
    var propertyPane = {};

    ///////////////////////
    //    Models         //
    ///////////////////////
    propertyPane.PropertyList = Array;

    propertyPane.Property = function(name, data) {
      //the following reflects the format of the data obects as sent by the event emitter
      this.name        = m.prop(name);
      this.value       = m.prop(data.value);
      this.type        = m.prop(data.valueType);
      this.visible     = m.prop(data.userVisible);
      this.editable    = m.prop(data.userEditable);
    };

    ///////////////////////
    //    Controller     //
    ///////////////////////
    propertyPane.controller = function() {

      this.properties = propertyPane.PropertyList();

      this.updatePropertyPane = function(sender) {
        //destroy current list
        this.properties.length = 0;

        for( var key in sender.currentItem.tag){
          this.properties.push(new propertyPane.Property(key, sender.currentItem.tag[key]));
        }
//>>>This is required to make the property pane to rerender:<<<
//      m.redraw(); //why?
//why doesn't redraw happen automatically (because I'm using m.module)??
      }.bind(this);

      //this reliably updates the the properties list
      //but rerender does not happen
      emitter.addCurrentItemChangedListener(this.updatePropertyPane);

    };

    ///////////////////////
    //    View           //
    ///////////////////////
    propertyPane.view = function(ctrl){
      return m('ul',
        ctrl.properties.map(function(property){
          return m('li', property.name() + ' ' + property.value());
        })
      );
    };

    return propertyPane;
});

I also tried adding a property called foo that updated in updatePropertyPane thus:

//in controller
this.foo = m.prop(Date.now());
//in updatePropertyPane
  this.foo(Date.now());
//in view
m('li', ...+this.foo()) //to make sure the view accesses this property.

That didn't work either.

Answer:1

Mithril automatically re-renders

  • After all event handlers, e.g. m(tag, {onclick:...}, foo), which have fired are terminated.
  • An AJAX request has terminated.
  • Routing occurs.

Data binding value changes themselves do not cause re-renders and there are several reasons for this. To be fair, most data changes in Mithril occur within event handlers or during AJAX processing.

You can however force a re-render on a value change by using a modified version of m.prop():

mprop: function(store, onchange) {
    var prop = function() {
        if (arguments.length) {
            store = arguments[0];
            if (typeof onchange == 'function') { onchange(store); }
        }
        return store;
    }
    prop.toJSON = function() { return store; }
    return prop;
}

this.name = mprop("John", function(value) {
    // value is the new value
    // do a m.redraw() rather than m.startComputation / m.endComputation
});

However you do it, you should prefer m.redraw() for async events over m.startComputation / m.endComputation. It redraws the view for the currently active module and its called internally by Mithril's auto-redrawing system.

Answer:2

I am building an image-upload feature into a web application and am using the following event handler: $('input:file').change(function(){ //handle input change }); I have discovered that the ...

I am building an image-upload feature into a web application and am using the following event handler: $('input:file').change(function(){ //handle input change }); I have discovered that the ...

Im using Jquery Isotope i have one item width greater than other div. All items align well but the items are not aligning properly under large width element. http://jsfiddle.net/S5vAG/1381/ <...

Im using Jquery Isotope i have one item width greater than other div. All items align well but the items are not aligning properly under large width element. http://jsfiddle.net/S5vAG/1381/ <...

I am extracting data from a database that I do not administer. It is a single list, and the important values are: Folder Name Index Integer UID (unique identification) String Filename I have ...

I am extracting data from a database that I do not administer. It is a single list, and the important values are: Folder Name Index Integer UID (unique identification) String Filename I have ...

I want to recognize "Str","Int","[Str]","[Int]","[[Str]]",... I thought I could do something like (Str|Int|\[\1\]) where \1 self references the group. I know from formal language theory that ...

I want to recognize "Str","Int","[Str]","[Int]","[[Str]]",... I thought I could do something like (Str|Int|\[\1\]) where \1 self references the group. I know from formal language theory that ...