'Getting a NodeList of the HTML tags in Mithril
Is there a way of having a NodeList of the HTML tags in Mithril? I need to get the width of the blocks. Something like that on vanilla js:
const blocks = Array.from(document.querySelectorAll('.blocks'));
const styles = blocks
.map((item) => item.getBoundingClientRect())
.map((item) => item.width);
const widthOfTheBlocks = styles.reduce((acc, curr) => acc + curr, 0) + 'px';
Solution 1:[1]
With typical DOM scripting, the DOM elements are pre-existing, and you would need to make sure they had identifiable selector (in this case the blocks
class), and then elsewhere use that selector to get a Javascript reference to them, with document.querySelectorAll
.
But with Mithril, you're declaring and referencing the DOM elements in the same place, so you don't need either of these methods: instead you attach a lifecycle method on the appropriate node and save the reference to a local variable.
The lifecycle methods expose a vnode
argument representing the virtual DOM entity: this contains a dom
property which exposes the rendered DOM element.
The essential mechanism to save a reference inside a component is as follows:
function MyComponent(){ // The component to contain the logic
let dom // The variable to store our DOM reference
return {
view : () =>
m('.MyElement', { // The virtual DOM element
oncreate(vnode){ // The `oncreate` lifecycle method to access the `vnode`
dom = vnode.dom // Save the dom reference to our variable
}
})
}
}
Below, I've written a little sandbox demo that uses your width calculation script in a slightly more complex scenario: Here there's a variable number of blocks, which are added to and removed over time; we declare a Set
to store them, and for each item we declare an oncreate
method to add
it to the set, and an onremove
to delete
it. I've used destructuring to extract the dom
reference straight from the methods; later, we use a slightly tweaked version of your width accumulation code, using the 2nd argument of Array.from
to extract the width
.
function Blocks(){
const blocks = new Set
return {
view: ({attrs: {count}}) => [
m('.container',
Array.from({length: count}, (_, index) =>
m('.block', {
oncreate({dom}){
blocks.add(dom)
},
onremove({dom}){
blocks.delete(dom)
},
}, index + 1)
),
),
m('button', {
onclick(){
const styles = Array.from(
blocks,
(item) => item.getBoundingClientRect().width
)
const widthOfTheBlocks = styles.reduce((acc, curr) => acc + curr, 0) + 'px';
alert(widthOfTheBlocks)
}
}, 'Alert width'),
]
}
}
m.mount(document.body, function App(){
let count = 1
return {
view: () => [
m('h1', 'Width reader'),
m('label',
'Number of blocks: ',
m('input[type=number][min=0][max=9][size=4]', {
value: count,
oninput(e){
count = e.target.value
},
}),
),
m(Blocks, {count}),
]
}
})
.container {
display: flex;
margin: 1em 0;
}
.block {
flex: 0 0 25%;
padding: 1em;
border: 1px solid;
}
<script src="https://unpkg.com/mithril/mithril.js"></script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Barney |