3

How do I access a virtual dom element to change its contents using Mithril? I am new to Mithril and still trying to figure things out. For example, I want to access the third div with id "three" and change it's contents to "Blue Jays" without touching any of the other div's.
Thanks.

<div id='main'>
    <div id='one'>Yankees</div><br>
    <div id='two'>Red Sox</div><br>
    <div id='three'>Orioles</div>
</div>

2 Answers2

1

In mithril, like in react/vue/angular, you dont act on the actual DOM directly. Instead, you define the outcome that you want, so for example, to render the DOM tree that you posted you would do something like this:

var my_view = {
  view: vnode => m('div#main', [
    m('div#one', 'Yankees'),
    m('div#two', 'Red Sox'),
    m('div#three', 'Orioles')
  ])
}
      
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>
<div id="root"></div>

the m(...) functions inside the array have a string as their second argument, that makes the output static, but we can change that to a variable:

var my_view = {
  oninit: vnode => vnode.state.fave_team = 'Orioles',

  view: vnode => m('div#main', [
    m('div#one', 'Yankees'),
    m('div#two', 'Red Sox'),
    m('div#three', vnode.state.fave_team)
  ])
}
  
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>

<div id="root">
</div>

In this case I used the state property of the vnode argument, but you can also use a third party state manager like flux or any other.

Now that we have it as a variable, it will show the current value on every call m.redraw(), most of the times we dont have to do this call ourselves, for example:

var my_view = {
  oninit: vnode => {
    vnode.state.fave_team = 'Orioles'
  },

  view: vnode => m('div#main', [
    m('div#one', 'Yankees'),
    m('div#two', 'Red Sox'),
    m('div#three', vnode.state.fave_team),
    m('button', { onclick: () => vnode.state.fave_team = 'Dodgers' }, 'Change')
  ])
}
  
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>
<div id="root"></div>

And thats it, any dynamic content in your DOM elements you set it as a variable/property in an object.

One of the beautiful things about mithril is that it doesnt force you to do things one specific way, so if you really want to work on the actual DOM node, there are lifecycle events that you can attach to any virtual node ("vnode")

Purefan
  • 1,498
  • 24
  • 44
0

You can easily capture the HTMLElement (i.e., HTMLInputElement) with the Mithril Lifecycle event of oncreate(). This is an actual example from my code (in TypeScript) where I need to hook up a few event listneres after the canvas element was created and its underlying DOM is available to me at "raw" HTML level. Once you get a hold of dom, then I manipulate that element directly. Many people think that why not use oninit(), but oninit() is before the generation of dom, so you will not get the element back at that stage.

Now, if you just do that, you will likely be posting another question - "Why the browser views not updating?" And that's because you do have to manually do a m.redraw() in your event handlers. Otherwise Mithril would not know when the view diffs to be computed.

   const canvas = m(`.row[tabIndex=${my.tabIndex}]`, {
            oncreate: (element: VnodeDOM<any, any>) => {
                const dom = element.dom;
                dom.addEventListener("wheel", my.eventWheel, false);
                dom.addEventListener("keydown", my.eventKeyDown, false);
            }
        },
Manabu Tokunaga
  • 956
  • 10
  • 19