Bravi
Bravi

Reputation: 773

Forcing a component to redraw from a different component in Mithril.js

I have 2 components - addProjectForm and listProjects. They are both nested components inside the root module. Whenever I add a project using the form, I want it to appear in the list straight away.

To achieve this, I had to pass down the controller instance to each component like this:

var RootComponent = {};

rootComponent.controller = function() {
     this.example = 'test variable';
}

rootComponent.view = function(ctrl) {
     return [
           m.component(addProjectForm, ctrl),
           m.component(listProjects, ctrl)
     ];
}

and then the listProjectscomponent for example, looks like this:

var listProjects = {
     controller: function(root) {
          this.root = root;
     },
     view: function(ctrl) {
          console.log(ctrl.root.example);
     }
};

So this way I keep calling methods on the top level, but I don't quite like passing down the controller instance like this. Is there any other way I should be doing it?

Upvotes: 1

Views: 1407

Answers (2)

Stephan Hoyer
Stephan Hoyer

Reputation: 4928

The problem you have is the difference between passing by reference or by value. In JS all primitive types are passed by value. Thats why you can't pass the string directly since it's cloned during pass. You have multiple options here:

You can use m.prop and just pass the variable down to the components, m.props stores the value in function that is always passed by reference.

var RootComponent = {};

rootComponent.controller = function() {
     this.example = m.prop('test variable');

}

rootComponent.view = function(ctrl) {
     return [
           m.component(addProjectForm, ctrl.example),
           m.component(listProjects, ctrl.example)
     ];
}

If the variable is an array, it will be passed by reference anyways.

Second option is to keep the list in the root context and add a callback to the second component.

var RootComponent = {};

rootComponent.controller = function() {
    var projects = this.projects = [];
    this.addProject = function(project) {
        projects.push(project);
    }

}

rootComponent.view = function(ctrl) {
    return [
        m.component(addProjectForm, {
            onsubmit: ctrl.addProject
        }),
        m.component(listProjects, ctrl.projects)
    ];
}

Upvotes: 0

dcochran
dcochran

Reputation: 1105

I think this is what you're looking for:

Mithril.js: Should two child components talk to each other through their parent's controller?

A newer way of solving this common problem is to use a Flux like architecture developed by Facebook:

https://facebook.github.io/flux/

Writing your own dispatcher is semi-trivial. Here's an example that someone else built alongside Mithril:

https://gist.github.com/MattMcFarland/25fb4f0241530d2f421a

The downside with this approach is it would be somewhat anti-Flux to use m.withAttr, as views aren't supposed to write directly to models in the dispatcher paradigm.

Upvotes: 0

Related Questions