MithrilJS / mithril.js

A JavaScript Framework for Building Brilliant Applications
https://mithril.js.org
MIT License
13.99k stars 926 forks source link

Mithril 1.0 app architecture #1478

Closed volnei closed 7 years ago

volnei commented 7 years ago

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)
HendrikRoth commented 7 years ago

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(.......
}
Papipo commented 7 years ago

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

volnei commented 7 years ago

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

pygy commented 7 years ago

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")
  ])
}   
barneycarroll commented 7 years ago

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:

volnei commented 7 years ago

@barneycarroll 👏 👏 👏 👏 👏

I agree! Thanks for explanation

tivac commented 7 years ago

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:

marciomunhoz commented 7 years ago

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!

iamjohnlong commented 7 years ago

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

marciomunhoz commented 7 years ago

@iamjohnlong 👍👍👍👍 tks!