DEV Community

Cover image for Our first 'Hello World' with VanJS, the new Mithril...
artydev
artydev

Posted on • Edited on

1 1

Our first 'Hello World' with VanJS, the new Mithril...

Every UI framerwork deserves its 'counter' example...

SimpleCounter

import van from "https://vanjs.org/code/van-0.11.9.min.js"

const {button, div, h1} = van.tags

const points = van.state(0)

const inc = () => ++points.val 

function App () {
  return div (
    h1("Value : ", points),
    button({onclick : inc}, "INC") 
  )
}

van.add(app, App())
Enter fullscreen mode Exit fullscreen mode

In the following example, the state is represented by an object instead of a single value, read the doc for more informations.
Beware the 'actions' object is my own 'business' and has nothing to do with VanJS.

IncDec

import van from "https://vanjs.org/code/van-0.11.9.min.js"

const {button, div, h1} = van.tags

const State = van.state({
  value : 0
})

const actions = ((state) => {
  const s = state.val;
  return ({
    inc : () => {
      state.val = {...s, value : ++s.value}
    },
    dec : () => {
      state.val = {...s, value : --s.value}
    }    
  })
})(State)

function App (state) {
  return div (
    van.bind(state, (s) => h1("Value : ", s.value)),
    button({onclick : actions.inc}, "INC"),
    button({onclick : actions.dec}, "DEC") 
  )
}

van.add(app, App(State))

Enter fullscreen mode Exit fullscreen mode

And for the final : multiple counters :

MultipleCounters


import van from "https://vanjs.org/code/van-0.11.9.min.js"

const {button, div, h1} = van.tags

// I could have use an array of values...
// But I wanted to play with dynamic properties
const State = van.state({
  value0 : 0,
  value1 : 0,
  value2 : 0
})

const actions = ((state) => {
  const s = state.val;
  return ({
    inc : (index) => {
      state.val = {...s, [`value${index}`] : ++s[`value${index}`]}
    },
    dec : (index) => {
      state.val = {...s, [`value${index}`] : --s[`value${index}`]}
    }    
  })
})(State)

function Counter(state, index = 0) {
   return div (
    van.bind(state, (s) => h1("Value : ", s[`value${index}`])),
    button({onclick : () => actions.inc(index)}, "INC"),
    button({onclick : () => actions.dec(index)}, "DEC") 
  )
}

function App (state) {
  return div(
    [...Array(3)].map((_, index) => Counter(state, index))
  )
}

van.add(app, App(State))

Enter fullscreen mode Exit fullscreen mode

Here is an optimised version, thanks Tao OpimisedMC

import van from "https://vanjs.org/code/van-0.11.9.min.js"

const {button, div, h1} = van.tags

const State = {
  value0 : van.state(0),
  value1 : van.state(0),
  value2 : van.state(0),
  value3 : van.state(0),
}

const actions = ((state) => {
  return ({
    inc : (index) =>  ++(state[`value${index}`]).val ,
    dec : (index) =>  --(state[`value${index}`]).val
  })
})(State)


function Counter (state, index) {
  return div (
    h1("Counter_", index, " : ", state[`value${index}`]),
    button({onclick : () => actions.inc(index)}, "INC"),
    button({onclick : () => actions.dec(index)}, "DEC") 
  )  
}

function App (state) {
  return Object.keys(State)
    .map((_, index) => Counter(state, index) )
}

van.add(app, App(State))

Enter fullscreen mode Exit fullscreen mode

Image of Quadratic

AI, code, and data connections in a familiar spreadsheet UI

Simplify data analysis by connecting directly to your database or API, writing code, and using the latest LLMs.

Try Quadratic free

Top comments (6)

Collapse
 
efpage profile image
Eckehard

You can also enable a sequential workflow:

    const { button, div, pre, br } = van.tags
    const add = (x) => van.add(base, x)

    let base = div({ style: "border: 2px dashed red; padding: 5px; display: inline-block;" }, "This is a group", br())
    van.add(document.body, base)

    for (let i = 0; i < 10; i++) {
      add(button({ onclick: () => alert("Hello World") }, "This is button "+i))
      add(br())
    }

Enter fullscreen mode Exit fullscreen mode
Collapse
 
artydev profile image
artydev • Edited

Thank you Ekehard :-)

WF

Nice , I really like your 'mix' VanJS / DML :-)

Based on your tip mAdd:

const { button, h1, div, pre, br } = van.tags

const add = (base) => (elt) => van.add(base, elt)

const target = document.getElementById("app")

add (target) (
  div ( 
    div ( 
      button("A button appended to #app"),
      button("2nd")
    ),
    div ( 
      div(h1("Hello"))  
    )
  )
)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
efpage profile image
Eckehard

I think it should be possible to get the best of both worlds...

Thread Thread
 
artydev profile image
artydev

Sure, I think so.
What is really amazing, it is the size.

Don't hesitate to contact Tao, the author, he is a very nice guy too...

Collapse
 
tao_xin_23db52b1401921dcb profile image
Tao Xin (vanjs.org)

btw: it would be more efficient to use multiple primitive-valued state objects compared to using a single state object that contains everything. In other words, for your example, you can have a JavaScript object that contains multiple state-valued fields, instead of having a single state object with object-typed value.

Instead of

const State = van.state({
  value0 : 0,
  value1 : 0,
  value2 : 0
})
Enter fullscreen mode Exit fullscreen mode

you can have:

const State = {
  value0: van.state(0),
  value1: van.state(0),
  value2: van.state(0)
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
artydev profile image
artydev • Edited

Thank you for your advise Tao :-)

import van from "https://vanjs.org/code/van-0.11.9.min.js"

const {button, div, h1} = van.tags

const State = {
  value0 : van.state(0),
  value1 : van.state(0),
  value2 : van.state(0),
  value3 : van.state(0),
}

const actions = ((state) => {
  return ({
    inc : (index) =>  ++(state[`value${index}`]).val ,
    dec : (index) =>  --(state[`value${index}`]).val
  })
})(State)


function Counter (state, index) {
  return div (
    h1("Counter_", index, " : ", state[`value${index}`]),
    button({onclick : () => actions.inc(index)}, "INC"),
    button({onclick : () => actions.dec(index)}, "DEC") 
  )  
}

function App (state) {
  return Object.keys(State)
    .map((_, index) => Counter(state, index) )
}

van.add(app, App(State))
Enter fullscreen mode Exit fullscreen mode

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

DEV shines when you're signed in, unlocking a customized experience with features like dark mode!

Okay