# Migrating from `v0.2.x` to `v1.x`

`v1.x` is largely API-compatible with `v0.2.x`, but there are a few breaking changes.

- [`m.component` removed](#mcomponent-removed)
- [`config` function](#config-function)
- [Cancelling redraw from event handlers](#cancelling-redraw-from-event-handlers)
- [Component `controller` function](#component-controller-function)
- [Component arguments](#component-arguments)
- [`view()` parameters](#view-parameters)
- [Passing components to `m()`](#passing-components-to-m)
- [Passing vnodes to `m.mount()` and `m.route()`](#passing-vnodes-to-mmount-and-mroute)
- [`m.route.mode`](#mroutemode)
- [`m.route` and anchor tags](#mroute-and-anchor-tags)
- [Reading/writing the current route](#readingwriting-the-current-route)
- [Accessing route params](#accessing-route-params)
- [`m.request`](#mrequest)
- [`xlink` namespace required](#xlink-namespace-required)

## `m.component` removed

In `v0.2.x` components could be created using either `m(component)` or `m.component(component)`. `v1.x` only supports `m(component)`.

### `v0.2.x`

```js
// These are equivalent
m.component(component);
m(component);
```

### `v1.x`

```js
m(component);
```

## `config` function

In `v0.2.x` mithril provided a single lifecycle method, `config`. `v1.x` provides much more fine-grained control over the lifecycle of a vnode.

### `v0.2.x`

```javascript
m("div", {
    config : function(element, isInitialized) {
        // runs on each redraw
        // isInitialized is a boolean representing if the node has been added to the DOM
    }
});
```

### `v1.x`

More documentation on these new methods is available in [lifecycle-methods.md](lifecycle-methods.md).

```javascript
m("div", {
    // Called before the DOM node is created
    oninit : function(vnode) { /*...*/ },
    // Called after the DOM node is created
    oncreate : function(vnode) { /*...*/ },
    // Called before the node is updated, return false to cancel
    onbeforeupdate : function(vnode, old) { /*...*/ },
    // Called after the node is updated
    onupdate : function(vnode) { /*...*/ },
    // Called before the node is removed, call done() when ready for the node to be removed from the DOM
    onbeforeremove : function(vnode, done) { /*...*/ },
    // Called before the node is removed, but after onbeforeremove calls done()
    onremove : function(vnode) { /*...*/ }
});
```

If available the DOM-Element of the vnode can be accessed at `vnode.dom`.

## Cancelling redraw from event handlers

`m.mount()` and `m.route()` still automatically redraw after a DOM event handler runs. Cancelling these redraws from within your event handlers is now done by setting the `redraw` property on the passed-in event object to `false`.

### `v0.2.x`

```javascript
m("div", {
    onclick : function(e) {
        m.redraw.strategy("none");
    }
})
```

### `v1.x`

```javascript
m("div", {
    onclick : function(e) {
        e.redraw = false;
    }
})
```

## Component `controller` function

In `v1.x` there is no more `controller` property in components, use `oninit` instead.

### `v0.2.x`

```javascript
m.mount(document.body, {
    controller : function() {
        var ctrl = this;

        ctrl.fooga = 1;
    },

    view : function(ctrl) {
        return m("p", ctrl.fooga);
    }
});
```

### `v1.x`

```javascript
m.mount(document.body, {
    oninit : function(vnode) {
        vnode.state.fooga = 1;
    },

    view : function(vnode) {
        return m("p", vnode.state.fooga);
    }
});

// OR

m.mount(document.body, {
    oninit : function(vnode) {
        var ctrl = this;  // this is bound to vnode.state by default

        ctrl.fooga = 1;
    },

    view : function(vnode) {
        var ctrl = this; // this is bound to vnode.state by default

        return m("p", ctrl.fooga);
    }
});
```

## Component arguments

Arguments to a component in `v1.x` must be an object, simple values like `String`/`Number`/`Boolean` will be treated as text children. Arguments are accessed within the component by reading them from the `vnode.attrs` object.

### `v0.2.x`

```javascript
var component = {
    controller : function(options) {
        // options.fooga === 1
    },

    view : function(ctrl, options) {
        // options.fooga == 1
    }
};

m("div", m.component(component, { fooga : 1 }));
```

### `v1.x`

```javascript
var component = {
    oninit : function(vnode) {
        // vnode.attrs.fooga === 1
    },

    view : function(vnode) {
        // vnode.attrs.fooga == 1
    }
};

m("div", m(component, { fooga : 1 }));
```

## `view()` parameters

In `v0.2.x` view functions are passed a reference to the `controller` instance and (optionally) any options passed to the component. In `v1.x` they are passed **only** the `vnode`, exactly like the `controller` function.

### `v0.2.x`

```javascript
m.mount(document.body, {
    controller : function() {},

    view : function(ctrl, options) {
        // ...
    }
});
```

### `v1.x`

```javascript
m.mount(document.body, {
    oninit : function(vnode) {
        // ...
    },
    
    view : function(vnode) {
        // Use vnode.state instead of ctrl
        // Use vnode.attrs instead of options
    }
});
```

## Passing components to `m()`

In `v0.2.x` you could pass components as the second argument of `m()` w/o any wrapping required. To help with consistency in `v1.x` they must always be wrapped with a `m()` invocation.

### `v0.2.x`

```javascript
m("div", component);
```

### `v1.x`

```javascript
m("div", m(component));
```

## Passing vnodes to `m.mount()` and `m.route()`

In `v0.2.x`, `m.mount(element, component)` tolerated [vnodes](vnodes.md) as second arguments instead of [components](components.md) (even though it wasn't documented). Likewise, `m.route(element, defaultRoute, routes)` accepted vnodes as values in the `routes` object.

In `v1.x`, components are required instead in both cases.

### `v0.2.x`

```javascript
m.mount(element, m('i', 'hello'));
m.mount(element, m(Component, attrs));

m.route(element, '/', {
    '/': m('b', 'bye')
})
```

### `v1.x`

```javascript
m.mount(element, {view: function () {return m('i', 'hello')}});
m.mount(element, {view: function () {return m(Component, attrs)}});

m.route(element, '/', {
    '/': {view: function () {return m('b', 'bye')}}
})
```

## `m.route.mode`

In `v0.2.x` the routing mode could be set by assigning a string of `"pathname"`, `"hash"`, or `"search"` to `m.route.mode`. In `v.1.x` it is replaced by `m.route.prefix(prefix)` where `prefix` can be `#`, `?`, or an empty string (for "pathname" mode). The new API also supports hashbang (`#!`), which is the default, and it supports non-root pathnames and arbitrary mode variations such as querybang (`?!`)

### `v0.2.x`

```js
m.route.mode = "pathname";
m.route.mode = "search";
```

### `v1.x`

```js
m.route.prefix("");
m.route.prefix("?");
```

## `m.route()` and anchor tags

Handling clicks on anchor tags via the mithril router is similar to `v0.2.x` but uses a new lifecycle method and API.

### `v0.2.x`

```javascript
// When clicked this link will load the "/path" route instead of navigating
m("a", {
    href   : "/path",
    config : m.route
})
```

### `v1.x`

```javascript
// When clicked this link will load the "/path" route instead of navigating
m("a", {
    href     : "/path",
    oncreate : m.route.link
})
```

## Reading/writing the current route

In `v0.2.x` all interaction w/ the current route happened via `m.route()`. In `v1.x` this has been broken out into two functions.

### `v0.2.x`

```javascript
// Getting the current route
m.route()

// Setting a new route
m.route("/other/route");
```

### `v1.x`

```javascript
// Getting the current route
m.route.get();

// Setting a new route
m.route.set("/other/route");
```

## Accessing route params

In `v0.2.x` reading route params was all handled through the `m.route.param()` method. In `v1.x` any route params are passed as the `attrs` object on the vnode passed as the first argument to lifecycle methods/`view`.

### `v0.2.x`

```javascript
m.route(document.body, "/booga", {
    "/:attr" : {
        view : function() {
            m.route.param("attr"); // "booga"
        }
    }
});
```

### `v1.x`

```javascript
m.route(document.body, "/booga", {
    "/:attr" : {
        oninit : function(vnode) {
            vnode.attrs.attr; // "booga"
        },
        view : function(vnode) {
            vnode.attrs.attr; // "booga"
        }
    }
});
```

## m.request

[m.request](request.md) now returns an [m.prop stream](prop.md) instead of a promise. The main difference is you'll have to use `.run` to get similar functionality as a promise's `.then`:

### `v0.2.x`

```js
m.request({ method: 'GET', url: 'https://api.github.com/' })
    .then(function (responseBody) {
        return m.request({ method: 'GET', url: responseBody.emojis_url });
    })
    .then(function (emojis) {
        console.log("+1 url:", emojis['+1']);
    });
```

### `v1.x`

```js
m.request({ method: 'GET', url: 'https://api.github.com/' })
    .run(function (responseBody) {
        return m.request({ method: 'GET', url: responseBody.emojis_url });
    })
    .run(function (emojis) {
        console.log("+1 url:", emojis['+1']);
    });
```

The equivalent of `m.sync` is now `m.prop.merge`:

### `v0.2.x`

```js
m.sync([
    m.request({ method: 'GET', url: 'https://api.github.com/users/lhorie' }),
    m.request({ method: 'GET', url: 'https://api.github.com/users/isiahmeadows' }),
])
    .then(function (users) {
        console.log("Contributors:", users[0].name, "and", users[1].name);
    });
```

### `v1.x`

```js
m.prop.merge([
    m.request({ method: 'GET', url: 'https://api.github.com/users/lhorie' }),
    m.request({ method: 'GET', url: 'https://api.github.com/users/isiahmeadows' }),
])
    .run(function (users) {
        console.log("Contributors:", users[0].name, "and", users[1].name);
    });
```

Additionally, if the `extract` option is passed to `m.request` the return value of the provided function will be passed to the [m.prop stream](prop.md) directly, and any `deserialize` callback is ignored.

## `xlink` namespace required

In `v0.2.x` when generating SVGs using `m()` the `xlink` namespace would automatically be added on certain attributes. For consistency in `v1.x` if you want to namespace an attribute you must do it yourself.

### `v0.2.x`

```js
m("svg",
    // the `href` attribute is namespaced automatically
	m("image[href='image.gif']")
)
```

### `v1.x`

```js
m("svg",
    // User-specified namespace on the `href` attribute
	m("image[xlink:href='image.gif']")
)
```
