These are chat archives for mithriljs/mithril.js

26th
Sep 2015
Pablo Macias
@jpablom
Sep 26 2015 00:07
how can launch a m.redraw from a config of mithril element?
Arthur Clemens
@ArthurClemens
Sep 26 2015 00:18
@jpablom What are you trying to do with the redraw?
Rodrigo Alvarez
@Papipo
Sep 26 2015 00:21
is there a way to run some code when the app has rendered for the first time?
right now I am using a config attr on an arbitrary view element
but there might be something specific for this task
I just want to initialize some third party code that needs DOM rendered
Arthur Clemens
@ArthurClemens
Sep 26 2015 00:22
you can use the config of the outermost element
Rodrigo Alvarez
@Papipo
Sep 26 2015 00:22
yep, that's what I am doing
I'll stick to that, although there is a tiny ugly bit, I can't access the lib from config in inner elements
so, instead what I will do is create a function that lazily initialises the library
then redefines itself to return it
Vadim Yermolin
@vadimyer
Sep 26 2015 03:50
Sup there. What's more practically better to learn nowadays, mithril or vue? I heard vue is getting popular and at least you can find some more information about it, however I'm very concerned about performance, mithril's performance looks quite a lot better than any other framework. BTW I'm totally new to the world of JS frameworks, can't decide what pattern MVC/MVVM should I choose. At first sight, vue looks cool (no templates - the template is "right in the page").
Lim H.
@limdauto
Sep 26 2015 06:09
This message was deleted
This message was deleted
This message was deleted
This message was deleted
Mithril's author once wrote a comparison here
Lim H.
@limdauto
Sep 26 2015 06:16
I personally dislike using markup language for flow control & application logic though. That's why I love the m() function so so much
Isiah Meadows
@isiahmeadows
Sep 26 2015 07:05

@limdauto That is a little out of date, as well as the TodoMVC perf comparison (sadly).

@vadimyer

I would say Mithril.

Vue uses the usual MVC architecture, with the templates and data for the views stored in multiple places. Vue also seems to rely on a ton of config and state, which generally doesn't scale very well (that's why Facebook and Google mostly just use it internally, and why Angular 2 is hardly compatible with Angular 1).

Mithril uses a slightly different MVC architecture, providing a view and controller, leaving it up to the programmer for managing state. It relies on immutable data and virtual DOM templates written in JS for the views. The controller is instantiated automatically when the component is first created (it won't render the component if the initial state hasn't changed).

Here's a (untested) comparison of the two, borrowed from one of Vue's own examples. I'm using ES6 in each of these, although in Vue's example, ES5 was used.

Shared CSS

#demo {
  font-family: 'Helvetica', Arial, sans-serif;
}
a {
  text-decoration: none;
  color: #f66;
}
li {
  line-height: 1.5em;
  margin-bottom: 20px;
}
.author, .date {
  font-weight: bold;
}

Vue

<!-- view template -->
<div id="demo">
  <h1>Latest Vue.js Commits</h1>
  <template v-repeat="b:branches">
    <input type="radio"
      name="branch"
      id="{{*b}}"
      value="{{*b}}"
      v-model="currentBranch">
    <label for="{{*b}}">{{*b}}</label>
  </template>
  <p>yyx990803/vue@{{currentBranch}}</p>
  <ul>
    <li v-repeat="commits">
      <a href="{{html_url}}" target="_blank" class="commit">{{sha.slice(0, 7)}}</a>
      - <span class="message">{{commit.message | truncate}}</span><br>
      by <span class="author">{{commit.author.name}}</span>
      at <span class="date">{{commit.author.date | formatDate}}</span>
    </li>
  </ul>
</div>
// JS
const apiURL = 'https://api.github.com/repos/yyx990803/vue/commits?per_page=3&sha='

const demo = new Vue({
  el: '#demo',

  data: {
    branches: ['master', 'dev'],
    currentBranch: 'master',
    commits: null
  },

  created() {
    this.fetchData()
    this.$watch('currentBranch', () => this.fetchData())
  },

  filters: {
    truncate(v) {
      const newline = v.indexOf('\n')
      return newline > 0 ? v.slice(0, newline) : v
    },

    formatDate(v) {
      return v.replace(/T|Z/g, ' ')
    },
  },

  methods: {
    fetchData() {
      const xhr = new XMLHttpRequest()
      xhr.open('GET', apiURL + this.currentBranch)
      xhr.onload = () => { this.commits = JSON.parse(xhr.responseText) }
      xhr.send()
    },
  },
})

Mithril

// Just JS
const branches = ['master', 'dev']
const url = 'https://api.github.com/repos/yyx990803/vue/commits?per_page=3&sha='

function truncate(v) {
  var newline = v.indexOf('\n')
  return newline > 0 ? v.slice(0, newline) : v
}

function formatDate(v) {
  return v.replace(/T|Z/g, ' ')
}

m.mount(document.getElementById("demo"), {
    controller() {
        this.commits = m.prop()
        this.current = m.prop()
        this.get('master')
    },

    get(branch) {
        m.request({type: 'json', url: url + this.current(branch)})
        .then(this.commits)
    },

    view() {
        return m('div', [
            m('h1', 'Latest Vue.js Commits'),
            branches.map(b => [
                m(`input[type="radio",name="branch",id="${b}",value="${b}"]`, {onclick: () => this.get(b)}),
                m(`label[for="${b}"]`),
            ]),
            m('p', 'yyx990803/vue@', this.current())
            m('ul', this.commits().map(({html_url, sha, commit}) => m('li', [
                m(`a.commit[target="_blank",href="${html_url}"]`, sha.slice(0, 7)),
                ' - ', m('span.message', truncate(commit.message)),
                ' by ', m('span.author', commit.author.name),
                ' at ', m('span.date', formatDate(commit.author.date)),
            ]))),
        ])
    },
})
Isiah Meadows
@isiahmeadows
Sep 26 2015 07:31
The above almost directly translates to React. (Well...except for the fact I felt separating a few things out would make it a little more readable, given JSX is a little verbose IMHO.)
const branches = ['master', 'dev']
const url = 'https://api.github.com/repos/yyx990803/vue/commits?per_page=3&sha='

function truncate(v) {
  var newline = v.indexOf('\n')
  return newline > 0 ? v.slice(0, newline) : v
}

function formatDate(v) {
  return v.replace(/T|Z/g, ' ')
}

class Commit extends React.Component {
    render() {
        const {html_url, commit, sha} = this.props
        return (
            <li>
                <a class="commit" target="_blank" href={html_url}>{sha.slice(0, 7)}</a>
                - <span class="message">{truncate(commit.message)}</span>
                by <span class="author">{commit.author.name}</span>
                at <span class="date">{formatDate(commit.author.date)}</span>
            </li>
        )
    }
}

class BranchLabel extends React.Component {
    render() {
        const {branch, host} = this.props
        return (
            <div>
                <input type="radio" name="branch" id={branch} value={branch}
                    onclick={() => host.get(branch)} />
                <label for={b} />
            </div>
        )
    }
}

class Demo extends React.Component {
    constructor(props) {
        super(props)
        this.state = {commits: [], current: "master"}
    }

    get(branch) {
        this.setState({current: branch})
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url + this.current)
        xhr.onload = () => {
            this.setState({commits: JSON.parse(xhr.responseText)})
        }
        xhr.send()
    }

    render() {
        return (
            <div>
                <h1>Latest Vue.js Commits</h1>
                {branches.map(b => <BranchLabel host={this} branch={b} />)}
                <p>yyx990803/vue@{this.state.current}</p>
                // The object spread here from ES7 simplifies things.
                <ul>{this.state.commits.map(c => <Commit {...c} />)}</ul>
            </div>
        )
    }
}

React.render(<Demo />)
Rodrigo Alvarez
@Papipo
Sep 26 2015 08:28
Mithril all the way
Vadim Yermolin
@vadimyer
Sep 26 2015 09:14
@impinball Thanks for the explanation.
Isiah Meadows
@isiahmeadows
Sep 26 2015 09:20
@vadimyer Welcome
And that's why I like Mithril. About the same lines of JS, and no secondary HTML file.
Rodrigo Alvarez
@Papipo
Sep 26 2015 11:12
I have a weird issue here. On a config attr I try to fetch an element by id and I get null
the thing is that it's in the DOM
Ketan Padegaonkar
@ketan
Sep 26 2015 11:13
@Papipo - can you show some (example) code?
Rodrigo Alvarez
@Papipo
Sep 26 2015 11:17
mmm, I might have found the issue
Rodrigo Alvarez
@Papipo
Sep 26 2015 12:08
when a config callback is fired, any nested elements won't be ready, right?
Arthur Clemens
@ArthurClemens
Sep 26 2015 12:10
they should be, because they are parsed inside out
the outer element is the last to be processed
Rodrigo Alvarez
@Papipo
Sep 26 2015 12:11
that's what I thought, but the element is not there
not in the first call
in the second call it is
which, btw, I'm not sure why it's being called twice
:D
Rodrigo Alvarez
@Papipo
Sep 26 2015 12:21
My problem is somewhere else, I need to clean this up