Mithril.js: Mithril 1.0 app architecture

Created on 12 Dec 2016  ยท  10Comments  ยท  Source: MithrilJS/mithril.js

Description:

How to do this in the new mihtirl 1.0?

var Course = function(data) {
    data = data || {}
    this._id = m.prop(data._id || "");
    this.slug = m.prop(data.slug || "");
    this.name = m.prop(data.name || "");
}

var ComposeCreate = {}
ComposeCreate.controller = function(){
      var course = m.prop(new Course())
    var create = function(){
        return new Course({_id : "123213123", slug: "slug", name: "coursename"})                       
    }
    return {
        course: course,
        create: create
    }
}

ComposeCreate.view = function(controller){
    var course = controller.course()
    return m(".card-block", [
    m(".form-group",[
      m("label",{for: "course-name"}, "Nome"),
      m("input.form-control", {type: "text", id: "course-name", oninput: m.withAttr("value", course.name), value: course.name()})
    ]),
    m(".form-group",[
      m("label",{for: "course-slug"}, "URL"),
      m("input.form-control", {type: "text", id: "course-slug", oninput: m.withAttr("value", course.slug), value: course.slug()})
    ]),
    m("button[type=button].btn.btn-primary", {onclick: controller.create}, "Cadastrar")
  ])
}   

m.render(document.body, ComposeCreate)
Question

Most helpful comment

Mithril 1.0 decided that props could become much more powerful, but also that 0.2 props weren't all that essential and are โ€” as @pygy demonstrates โ€” trivially replaced with anonymous functions.

The new documentation is here: https://github.com/lhorie/mithril.js/blob/rewrite/docs/stream.md

There are plenty of new abilities, but the essentials are the same: you can use them exactly like 0.2 props.


@volnei one of the reasons I think it's good to get rid of the old props from core is that it is deceptive in its functionality: all it really does is allow passing primitive values (numbers, booleans, strings) from component to component without wrapping them in an object (wrapping them in a function instead) and making assignment 8 characters longer, interpolation 2 characters longer and assignment between 6 and 13 characters shorter depending on whether you can use arrow functions.

Your code falls into the 'over eager prop' anti-pattern: there is no benefit to wrapping the Course constructor in a prop โ€” it is immediately unwrapped at the start of the view. This is a persistent dilemma faced by Mithril 0.2 users: which of my model references should be props? The truth is that 0.2 props don't actually introduce any extra functionality and are never essential โ€” only ever potentially convenient. I feel the best approach to using props is always to write without them, and then introduce them if they make your code less cumbersome.

A prop is useful if:

  • You need to send a primitive value from one function to another but don't want to wrap it in a function (surprisingly uncommon)
  • You will write to the prop as often as you will read from it in the source โ€” eg a data point which is used exclusively as a dynamic input value
  • You dislike anonymous functions in views (surprisingly common)

All 10 comments


var ComposeCreate = {}

ComposeCreate.oninit = function(vnode) {
  vnode.state.course = m.prop(new Course())
  vnode.state.create = function() { ... }
}

ComposeCreate.view = function(vnode) {
  var course = vnode.state.course()
  return m(.......
}

m.prop() is not available on 1.0. You will want to require("mithril/stream") for that.

Thanks for reply @Papipo and @HendrikRoth.

This code works perfectly, but, is this de correct way? Since prop is no more part of core, there any other way?

Tks

No new mechanism. We may want to provide an out of core, legacy prop module that behaves like the old one, to ease porting, but I don't think it has ever been discussed. @lhorie?

Otherwise, you can replace the props with bare JS values, and use anonimous functions as setters:

var Course = function(data) {
    data = data || {}
    this._id = data._id || "";
    this.slug = data.slug || "";
    this.name = data.name || "";
}

var ComposeCreate = {}
ComposeCreate.controller = function(){
    var course = new Course()

    var create = function(){
        return new Course({_id : "123213123", slug: "slug", name: "coursename"})                       
    }
    return {
        course: course,
        create: create
    }
}

ComposeCreate.view = function(controller){
    var course = controller.course
    return m(".card-block", [
    m(".form-group",[
      m("label",{for: "course-name"}, "Nome"),
      m("input.form-control", {type: "text", id: "course-name", oninput: m.withAttr("value", function(name) {course.name = name), value: course.name})
    ]), //snip
    m("button[type=button].btn.btn-primary", {onclick: function(){controller.course = controller.create()}}, "Cadastrar")
  ])
}   

Mithril 1.0 decided that props could become much more powerful, but also that 0.2 props weren't all that essential and are โ€” as @pygy demonstrates โ€” trivially replaced with anonymous functions.

The new documentation is here: https://github.com/lhorie/mithril.js/blob/rewrite/docs/stream.md

There are plenty of new abilities, but the essentials are the same: you can use them exactly like 0.2 props.


@volnei one of the reasons I think it's good to get rid of the old props from core is that it is deceptive in its functionality: all it really does is allow passing primitive values (numbers, booleans, strings) from component to component without wrapping them in an object (wrapping them in a function instead) and making assignment 8 characters longer, interpolation 2 characters longer and assignment between 6 and 13 characters shorter depending on whether you can use arrow functions.

Your code falls into the 'over eager prop' anti-pattern: there is no benefit to wrapping the Course constructor in a prop โ€” it is immediately unwrapped at the start of the view. This is a persistent dilemma faced by Mithril 0.2 users: which of my model references should be props? The truth is that 0.2 props don't actually introduce any extra functionality and are never essential โ€” only ever potentially convenient. I feel the best approach to using props is always to write without them, and then introduce them if they make your code less cumbersome.

A prop is useful if:

  • You need to send a primitive value from one function to another but don't want to wrap it in a function (surprisingly uncommon)
  • You will write to the prop as often as you will read from it in the source โ€” eg a data point which is used exclusively as a dynamic input value
  • You dislike anonymous functions in views (surprisingly common)

@barneycarroll ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘

I agree! Thanks for explanation

The truth is that 0.2 props don't actually introduce any extra functionality and are never essential โ€” only ever potentially convenient

:clap: :+1: :clap: :+1: :clap: :+1: :clap: :+1: :clap: :+1: :clap: :+1: :clap: :+1:

I'm trying to test a simple example using this post (without m.prop) as reference but no success.

var Course = function(data) {
  data = data || { name: "" } 
  this.name = data.name
}
var Component = {}
Component.controller = function() {
  var course = new Course()
  return {
    course: course
  }
}
Component.view = function(ctrl) {
  var course = ctrl.course
  return m("div", [
    m("input", {type: "text", oninput: m.withAttr("value", function(name) { course.name = name }), value: course.name}),
    m("p", course.name) //this never show in view 
  ])
}
m.render(document.body, Component) 

http://codepen.io/marciomunhoz/pen/WoXJeV?editors=0010

Can you tell me what's wrong?

Thanks!

@marciomunhoz change m.render(document.body, Component) to m.mount(document.body, Component)

@iamjohnlong ๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘ tks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

millken picture millken  ยท  4Comments

barneycarroll picture barneycarroll  ยท  3Comments

raykyri picture raykyri  ยท  4Comments

pygy picture pygy  ยท  3Comments

hadihammurabi picture hadihammurabi  ยท  4Comments