Mithril.js: [rewrite] Correct way to update a child element based on parent

Created on 23 Jan 2017  Â·  4Comments  Â·  Source: MithrilJS/mithril.js

Description:

What is the correct way to update a child element based on parent?

Steps to Reproduce:

var parentModel = {
    childId: 1
}
var parent = {
    view: function(vnode) {
        return [
            m("h1", "Editor " + parentModel.childId),
            m("button", {onclick: function(){parentModel.childId++}}, "Next"),
            m(child, parentModel)
        ]
    }
}

/////////////////////////
var childModel = {
    id: 0
}
var child = {
    oninit: function(vnode) {
        childModel.id = vnode.attrs.childId
    },
    view: function(vnode) {
        return m("h2", "Editing " + childModel.id)
    }
}
m.mount(document.body, parent)

https://jsfiddle.net/volnei/8L123yxt/

Expected:

Child element updated

Actual:

Child element is not updated

Question

Most helpful comment

This is an anti pattern whereby you want to read directly from the attrs in the view, but instead you're assigning the value of a particular attribute to state in oninit and then referring to that cached value.

If you remove the oninit and simply reference the desired attribute in the view, you'll be fine:

var child = {
  view: function(vnode) {
    return m("h2", "Editing " + vnode.attrs.childId )
  }
}

Without knowing what the intent of the childModel object is, I'd recommend keeping it simple and avoid the indirection of assigning the value to an intermediary object in one place only to retrieve it later — in the absence of other requirements it just looks like an opportunity for bugs to arise — but if for some reason you really need to update an external model, you can make your code work by taking that same function currently bound to oninit and also binding it to onbeforeupdate

All 4 comments

You must also sync the models from the onbeforeupdate hook: https://jsfiddle.net/8L123yxt/4/

Since I working with a master/detail, can you say if this is the best way in terms of architecture?

This is an anti pattern whereby you want to read directly from the attrs in the view, but instead you're assigning the value of a particular attribute to state in oninit and then referring to that cached value.

If you remove the oninit and simply reference the desired attribute in the view, you'll be fine:

var child = {
  view: function(vnode) {
    return m("h2", "Editing " + vnode.attrs.childId )
  }
}

Without knowing what the intent of the childModel object is, I'd recommend keeping it simple and avoid the indirection of assigning the value to an intermediary object in one place only to retrieve it later — in the absence of other requirements it just looks like an opportunity for bugs to arise — but if for some reason you really need to update an external model, you can make your code work by taking that same function currently bound to oninit and also binding it to onbeforeupdate

I don't agree that it's an anti-pattern, per se, (@barneycarroll), but generally, you want to avoid persistent state where practical. Not only would that solve your problem here, but it's also helpful in general to avoid bugs and keep things more testable (stateless rendering is easy to test).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

raykyri picture raykyri  Â·  4Comments

josephys picture josephys  Â·  4Comments

barneycarroll picture barneycarroll  Â·  3Comments

StephanHoyer picture StephanHoyer  Â·  4Comments

dhinesh03 picture dhinesh03  Â·  4Comments