add support for controller.prototype.onunload
This commit is contained in:
parent
762eeb7e31
commit
b23ffd1aee
7 changed files with 86 additions and 6 deletions
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
[v0.1.13](/mithril/archive/v0.1.13) - maintenance
|
[v0.1.13](/mithril/archive/v0.1.13) - maintenance
|
||||||
|
|
||||||
|
### News:
|
||||||
|
|
||||||
|
- m.module now runs clean-up code in root module controllers that implement an `onunload` instance method [82](https://github.com/lhorie/mithril.js/issues/82)
|
||||||
|
|
||||||
### Bug Fixes:
|
### Bug Fixes:
|
||||||
|
|
||||||
- Removing CSS rules now diffs correctly [#79](https://github.com/lhorie/mithril.js/issues/79)
|
- Removing CSS rules now diffs correctly [#79](https://github.com/lhorie/mithril.js/issues/79)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"version": "$version",
|
"version": "$version",
|
||||||
"author": "Leo Horie <leohorie@hotmail.com>",
|
"author": "Leo Horie <leohorie@hotmail.com>",
|
||||||
"repository": {"type": "git", "url": "https://github.com/lhorie/mithril"},
|
"repository": {"type": "git", "url": "https://github.com/lhorie/mithril"},
|
||||||
"main": "mithril.min.js",
|
"main": "mithril.js",
|
||||||
"licenses": [{"type": "MIT", "url": "http://opensource.org/licenses/MIT"}],
|
"licenses": [{"type": "MIT", "url": "http://opensource.org/licenses/MIT"}],
|
||||||
"files": ["mithril.min.js", "mithril.min.map", "mithril.js"]
|
"files": ["mithril.min.js", "mithril.min.map", "mithril.js"]
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +103,32 @@ yields:
|
||||||
</body>
|
</body>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Unloading modules
|
||||||
|
|
||||||
|
If a module's controller implements an instance method called `onunload`, this method will be called when a new `m.module` call updates the root DOM element tied to the module in question.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var module1 = {};
|
||||||
|
module1.controller = function() {
|
||||||
|
this.onunload = function() {
|
||||||
|
console.log("unloading module 1");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
module1.view = function() {};
|
||||||
|
|
||||||
|
m.module(document, module1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var module2 = {};
|
||||||
|
module2.controller = function() {};
|
||||||
|
module1.view = function() {};
|
||||||
|
|
||||||
|
m.module(document, module2); // logs "unloading module 1"
|
||||||
|
```
|
||||||
|
|
||||||
|
This mechanism is useful to clear timers and unsubscribe event handlers. If you have a hierarchy of components, you can recursively call `onunload` on all the components in the tree or use a [pubsub](http://microjs.com/#pubsub) library to unload specific components on demand.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Signature
|
### Signature
|
||||||
|
|
@ -113,7 +139,8 @@ yields:
|
||||||
void module(DOMElement rootElement, Module module)
|
void module(DOMElement rootElement, Module module)
|
||||||
|
|
||||||
where:
|
where:
|
||||||
Module :: Object { void controller(), void view(Object controllerInstance) }
|
Module :: Object { Controller, void view(Object controllerInstance) }
|
||||||
|
Controller :: void controller() | void controller() { prototype: void unload() }
|
||||||
```
|
```
|
||||||
|
|
||||||
- **DOMElement rootElement**
|
- **DOMElement rootElement**
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
Redraws the view for the currently active module. Use [`m.module()`](mithril.module) to activate a module.
|
Redraws the view for the currently active module. Use [`m.module()`](mithril.module) to activate a module.
|
||||||
|
|
||||||
This method is called internally by Mithril's auto-redrawing system and is only documented for completeness; usually you should avoid calling it manually unless you explicitly want a multi-pass redraw cycle. One case where `m.redraw` may be useful is to force a manual redraw after background requests (see the `background` option in [`m.request`](mithril.request.md).
|
This method is called internally by Mithril's auto-redrawing system. Usually you don't need to call it manually unless you are doing recurring asynchronous operations (i.e. using `setInterval`) or if you want to decouple slow running background requests from the rendering context (see the `background` option in [`m.request`](mithril.request.md).
|
||||||
|
|
||||||
A multi-pass redraw cycle is usually only useful if you need non-trivial UI metrics measurements. A multi-pass cycle may span multiple browser repaints and therefore could cause flash of unbehaviored content (FOUC) and performance degradation.
|
|
||||||
|
|
||||||
By default, if you're using either [`m.route`](mithril.route.md) or [`m.module`](mithril.module.md), `m.redraw()` is called automatically by Mithril's auto-redrawing system once the controller finishes executing.
|
By default, if you're using either [`m.route`](mithril.route.md) or [`m.module`](mithril.module.md), `m.redraw()` is called automatically by Mithril's auto-redrawing system once the controller finishes executing.
|
||||||
|
|
||||||
`m.redraw` is also called automatically on event handlers defined in virtual elements.
|
`m.redraw` is also called automatically on event handlers defined in virtual elements.
|
||||||
|
|
||||||
|
Note that calling this method will not do anything if a module was not activated via either [`m.module()`](mithril.module) or [`m.route()`](mithril.route). This means that `m.redraw` doesn't do anything when instantiating controllers and rendering views via `m.render` manually.
|
||||||
|
|
||||||
If there are pending [`m.request`](mithril.request.md) calls in either a controller constructor or event handler, the auto-redrawing system waits for all the AJAX requests to complete before calling `m.redraw`.
|
If there are pending [`m.request`](mithril.request.md) calls in either a controller constructor or event handler, the auto-redrawing system waits for all the AJAX requests to complete before calling `m.redraw`.
|
||||||
|
|
||||||
This method may also be called manually from within a controller if more granular updates to the view are needed, however doing so is generally not recommended, as it may degrade performance. Model classes should never call this method.
|
This method may also be called manually from within a controller if more granular updates to the view are needed, however doing so is generally not recommended, as it may degrade performance. Model classes should never call this method.
|
||||||
|
|
||||||
If you are developing an asynchronous model-level service and finding that Mithril is not redrawing the view after your code runs, you should use [`m.startComputation` and `m.endComputation`](mithril.computation.md) to integrate with Mithril's auto-redrawing system instead.
|
If you are developing an asynchronous model-level service and finding that Mithril is not redrawing the view after your code runs, you should use [`m.startComputation` and `m.endComputation`](mithril.computation.md) to integrate with Mithril's auto-redrawing system instead.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,34 @@ m.route.param("date") === "archive/2014"
|
||||||
//the routes should be flipped around to get `m.route.param("year") == "2014"`
|
//the routes should be flipped around to get `m.route.param("year") == "2014"`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Running clean up code on route change
|
||||||
|
|
||||||
|
If a module's controller implements an instance method called `onunload`, this method will be called when a route changes.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var home = {};
|
||||||
|
home.controller = function() {
|
||||||
|
this.onunload = function() {
|
||||||
|
console.log("unloading home module");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var dashboard = {};
|
||||||
|
dashboard.controller = function() {};
|
||||||
|
dashboard.view = function() {};
|
||||||
|
|
||||||
|
//go to the default route (home)
|
||||||
|
m.route(document.body, "/", {
|
||||||
|
"/": home,
|
||||||
|
"/dashboard": dashboard,
|
||||||
|
});
|
||||||
|
|
||||||
|
//re-route to dashboard
|
||||||
|
m.route("/dashboard"); // logs "unloading home"
|
||||||
|
```
|
||||||
|
|
||||||
|
This mechanism is useful to clear timers and unsubscribe event handlers. If you have a hierarchy of components, you can recursively call `unload` on all the components in the tree or use a [pubsub](http://microjs.com/#pubsub) library to unload specific components on demand.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### Signature
|
#### Signature
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ Mithril = m = new function app(window) {
|
||||||
if (index < 0) index = roots.length
|
if (index < 0) index = roots.length
|
||||||
roots[index] = root
|
roots[index] = root
|
||||||
modules[index] = module
|
modules[index] = module
|
||||||
|
if (controllers[index] && typeof controllers[index].onunload == "function") controllers[index].onunload()
|
||||||
controllers[index] = new module.controller
|
controllers[index] = new module.controller
|
||||||
m.endComputation()
|
m.endComputation()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,7 @@ function testMithril(mock) {
|
||||||
return valueBefore1 === "UL" && valueAfter1 === "" && valueBefore2 === "" && valueAfter2 === "UL"
|
return valueBefore1 === "UL" && valueAfter1 === "" && valueBefore2 === "" && valueAfter2 === "UL"
|
||||||
})
|
})
|
||||||
test(function() {
|
test(function() {
|
||||||
|
//https://github.com/lhorie/mithril.js/issues/79
|
||||||
var root = mock.document.createElement("div")
|
var root = mock.document.createElement("div")
|
||||||
m.render(root, m("div", {style: {background: "red"}}))
|
m.render(root, m("div", {style: {background: "red"}}))
|
||||||
var valueBefore = root.childNodes[0].style.background
|
var valueBefore = root.childNodes[0].style.background
|
||||||
|
|
@ -357,6 +358,25 @@ function testMithril(mock) {
|
||||||
m.render(root, m("div[style='background:red']"))
|
m.render(root, m("div[style='background:red']"))
|
||||||
return root.childNodes[0].style === "background:red"
|
return root.childNodes[0].style === "background:red"
|
||||||
})
|
})
|
||||||
|
test(function() {
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
m.render(root, m("div", {style: {background: "red"}}))
|
||||||
|
var valueBefore = root.childNodes[0].style.background
|
||||||
|
m.render(root, m("div", {}))
|
||||||
|
var valueAfter = root.childNodes[0].style.background
|
||||||
|
return valueBefore === "red" && valueAfter === undefined
|
||||||
|
})
|
||||||
|
test(function() {
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
var module = {}, unloaded = false
|
||||||
|
module.controller = function() {
|
||||||
|
this.onunload = function() {unloaded = true}
|
||||||
|
}
|
||||||
|
module.view = function() {}
|
||||||
|
m.module(root, module)
|
||||||
|
m.module(root, {controller: function() {}, view: function() {}})
|
||||||
|
return unloaded === true
|
||||||
|
})
|
||||||
//end m.render
|
//end m.render
|
||||||
|
|
||||||
//m.redraw
|
//m.redraw
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue