chifer
chifer

Reputation: 683

Mithril components - bounded controllers

I have a mithril component with an controller which is already bounded to an context, if I use m.component(), mithril disregards the bounded controller and supplies the view with an default empty controller

UserWidget = function(){
  this.allUsers =  User.load();
  this['header'] = {      
    'controller' : function(users){
      this.users = users;
    }.bind(this, this.allUsers),
    'view' : function(ctrl) {
      console.log('ctrl', ctrl)
      if (ctrl.users()) {
        return m('.user', ctrl.users()[0].name());
      }
    }
  }
}

//initialize
m.module(document.body, m(new UserWidget().header));

However if I pass view/controller via m.module everything works as expected

m.module(document.body, new UserWidget().header);

https://jsfiddle.net/chifer/mwddffy4/2/

Is it a caveat that component controllers should be unbounded and passed params via the m.component call? or is this a bug?

Upvotes: 2

Views: 348

Answers (1)

Barney
Barney

Reputation: 16456

Is it a caveat that component controllers should be unbounded and passed params via the m.component call?

Yes. Controllers are invoked as constructors with the new keyword, which means this (and arguments passed in) cannot be bound to it.

Your code can be simplified by avoiding this and binding internally:

UserWidget = function(){
  var users =  User.load();

  return {
    'view' : function() {
      if (users())
        return m('.user', users()[0].name());
    }
  }
}

//initialize
m.module(document.body, m(UserWidget()));

Fiddle here.

But in practice, this code is replicating the functionality that's already built in to controllers — to quote from the Mithril API documentation for components:

The optional controller function creates an object that may be used in the following recommended ways:

[...]

  • It can store contextual data returned from model methods (i.e. a promise from a request).
  • It can hold a reference to a view model.

Basically, your original application code involves a constructor that makes a request and stores a reference to the returned promise, and this is exactly what controllers are for. So you can avoid writing any intermediary functions or constructors of your own and bake all that functionality into the component structure itself:

UserWidget = {
  'controller' : function(){
    this.users = User.load();
  },
  'view' : function(ctrl) {
    if (ctrl.users())
      return m('.user', ctrl.users()[0].name());
  }
}

//initialize
m.module(document.body, UserWidget);

Fiddle here.

Upvotes: 1

Related Questions