Update mithril.component.md
- The term *rollback* should be explained or replaced - caveat #3/#4: Should *root element* be changed to *top-most element* so as not to be confused with the element the component is mounted on ?
This commit is contained in:
parent
62e38287f7
commit
9c6cbab43e
1 changed files with 30 additions and 25 deletions
|
|
@ -5,7 +5,7 @@
|
|||
- [Rendering components](#rendering-components)
|
||||
- [Optional controller](#optional-controller)
|
||||
- [Controller as a class constructor](#controller-as-a-class-constructor)
|
||||
- [Notes on the view function](#notes on the view function)
|
||||
- [Notes on the view function](#notes-on-the-view-function)
|
||||
- [Parameterized components](#parameterized-components)
|
||||
- [Nesting components](#nesting-components)
|
||||
- [Dealing with state](#dealing-with-state)
|
||||
|
|
@ -16,8 +16,9 @@
|
|||
- [Unloading components](#unloading-components)
|
||||
- [Nested asynchronous components](#nested-asynchronous-components)
|
||||
- [Limitations and caveats](#limitations-and-caveats)
|
||||
- [Opting out of auto-redrawing](#opting-out-of-auto-redrawing)
|
||||
- [Signature](#signature)
|
||||
- [Opting out of the auto redrawing system](#opting-out-of-the-auto-redrawing-system)
|
||||
- [Signature](#signature)
|
||||
|
||||
---
|
||||
|
||||
Components are building blocks for Mithril applications. They allow developers to encapsulate functionality into reusable units.
|
||||
|
|
@ -109,7 +110,7 @@ The `controller` function is called *once* when the component is rendered. Subse
|
|||
|
||||
#### Optional controller
|
||||
|
||||
The `controller` function is optional and defaults to an empty function: //controller: function() {}
|
||||
The `controller` function is optional and defaults to an empty function `controller: function() {}`
|
||||
|
||||
```javascript
|
||||
//a component without a controller
|
||||
|
|
@ -347,7 +348,7 @@ var MyComponent = {
|
|||
};
|
||||
```
|
||||
|
||||
However, it's recommended that you aggregate all of your requests in a single place instead of scattering them across multiple components. Aggregating requests in a top-level component makes it easier to replay the request chain (for example, you may need to fetch an updated list of items after you've saved something related to it) and it ensures the entire data set is loaded in memory before drilling down into the components (thus preventing the need for redundant AJAX calls for sibling components that need the same data). Be sure to read the [Application Architecture section](components.md#application-architecture-with-components) to learn more about organizing componentized code.
|
||||
However, it's recommended that you aggregate all of your requests in a single place instead of scattering them across multiple components. Aggregating requests in a top-level component makes it easier to replay the request chain (for example, fetching an updated list of items after you've saved something that changes that list), and it ensures the entire data set is loaded in memory before drilling down into nested components, avoiding redundant AJAX calls for sibling components that need the same data. Be sure to read the [Application Architecture section](components.md#application-architecture-with-components) to learn more about organizing componentized code.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -373,13 +374,24 @@ m.render(document.body, ProjectList({key: people[1].id, value: people[1]})
|
|||
|
||||
In the example above, since the key is different, the ProjectList component is recreated from scratch. As a result, the controller runs again, the DOM is re-generated, and any applicable 3rd party plugins in configs are re-initialized.
|
||||
|
||||
Remember that the rules for keys apply for components the same way they do for regular elements: it is not allowed to have duplicate keys as children of the same parent, and they must be either strings or numbers (or something with a `.toString()` implementation that makes the entity locally uniquely identifiable when serialized). You can learn more about keys [here](mithril.md#dealing-with-focus)
|
||||
Remember that the rules for keys apply for components the same way they do for regular elements: it is not allowed to have duplicate keys on children of the same parent, and they must be either strings or numbers (or something with a `.toString()` implementation that makes the entity uniquely identifiable in the local scope when serialized). You can learn more about keys [here](mithril.md#dealing-with-focus)
|
||||
|
||||
---
|
||||
|
||||
### Unloading components
|
||||
|
||||
If a component's controller contains an function called `onunload`, it will be called when a new `m.mount` call updates the root DOM element tied to the component in question, or when a route changes (if you are using [`m.route`](mithril.route.md)).
|
||||
If a component's controller contains the function `onunload`, it will be called under two circumstances:
|
||||
|
||||
- when a new call to `m.mount` updates the root DOM element of the component in question
|
||||
- when a route changes (if you are using [`m.route`](mithril.route.md)).
|
||||
|
||||
To unload a component without loading another component, you can simply call `m.mount` with a `null` as the component parameter:
|
||||
|
||||
```javascript
|
||||
m.mount(rootElement, null);
|
||||
```
|
||||
|
||||
Often, you will want to do some work before the component is unloaded (i.e. clear timers or unsubscribe event handlers).
|
||||
|
||||
```javascript
|
||||
var MyComponent = {
|
||||
|
|
@ -395,9 +407,9 @@ var MyComponent = {
|
|||
};
|
||||
};
|
||||
|
||||
m.mount(document, MyComponent);
|
||||
|
||||
m.mount(document.body, MyComponent);
|
||||
|
||||
//...
|
||||
|
||||
var AnotherComponent = {
|
||||
view: function() {
|
||||
|
|
@ -405,12 +417,11 @@ var AnotherComponent = {
|
|||
}
|
||||
};
|
||||
|
||||
m.mount(document, AnotherComponent); // logs "unloading my component"
|
||||
// mount on the same DOM element, replacing MyComponent
|
||||
m.mount(document.body, AnotherComponent); // logs "unloading my component"
|
||||
```
|
||||
|
||||
This mechanism is useful to clear timers and unsubscribe event handlers.
|
||||
|
||||
You can also use this event to prevent a component from being unloaded in the context of a route change (e.g. to alert a user to save their changes before navigating away from a page)
|
||||
You can also use the `onunload` function to PREVENT a component from being unloaded in the context of a route change (i.e. to alert a user to save their changes before navigating away from a page)
|
||||
|
||||
```javascript
|
||||
var component = {
|
||||
|
|
@ -432,12 +443,6 @@ var component = {
|
|||
|
||||
Normally, calling `m.mount` will return the controller instance for that component, but there's one corner case: if `e.preventDefault()` is called from a controller's `onunload` method, then the `m.mount` call will not instantiate the new controller, and will return `undefined`.
|
||||
|
||||
To unload a component without loading another component, you can simply call `m.mount` with a `null` as the component parameter:
|
||||
|
||||
```javascript
|
||||
m.mount(rootElement, null);
|
||||
```
|
||||
|
||||
Mithril does not hook into the browser's `onbeforeunload` event. To prevent unloading when attempting to navigate away from a page, you can check the return value of `m.mount`
|
||||
|
||||
```javascript
|
||||
|
|
@ -449,7 +454,7 @@ window.onbeforeunload = function() {
|
|||
}
|
||||
```
|
||||
|
||||
Components that are nested in other components can also call `onunload` and its `e.preventDefault()` like top-level components. The `onunload` event is called if an instantiated component is removed from a virtual element tree via a redraw.
|
||||
Components that are nested inside other components can also call `onunload` and its `e.preventDefault()` like top-level components. The `onunload` event is called if an instantiated component is removed from a virtual element tree via a redraw.
|
||||
|
||||
In the example below, clicking the button triggers the component's `onunload` event and logs "unloaded!".
|
||||
|
||||
|
|
@ -482,19 +487,19 @@ var MyComponent = {
|
|||
m.mount(document.body, MyApp)
|
||||
```
|
||||
|
||||
Calling `e.preventDefault()` from a component's `onunload` aborts route changes, but it does not abort, rollback or affect the current redraw in any way.
|
||||
Calling `e.preventDefault()` from a component's `onunload` function aborts route changes, but it does not abort rollback or affect the current redraw in any way.
|
||||
|
||||
---
|
||||
|
||||
### Nested asynchronous components
|
||||
|
||||
Since controllers can call model methods, it's possible for nested components to encapsulate asynchronous behavior. When components aren't nested, Mithril waits for all asynchronous tasks to complete, but when nesting components, a component's parent view renders before the component completes its asynchronous tasks (because the existence of the component only becomes known to the diff engine at the time when the template is rendered).
|
||||
Since controllers can call model methods, it's possible for nested components to encapsulate asynchronous behavior. When components aren't nested, Mithril waits for all asynchronous tasks to complete, but when components are nested, a component's parent view renders before the component completes its asynchronous tasks. The existence of the component only becomes known to the diff engine at the time when the template is rendered.
|
||||
|
||||
When a component has asynchronous payloads and they are queued by the [auto-redrawing system](auto-redrawing.md), its view is NOT rendered until all asynchronous operations complete. When the component's asynchronous operations complete, another redraw is triggered and the entire template tree is evaluated again. This means that the virtual dom tree may take two or more redraws (depending on how many nested asynchronous components there are) to be fully rendered.
|
||||
|
||||
There are [different ways to organize components](components.md#application-architecture-with-components) that can side-step the need for multiple redraws. Regardless, you could also force multiple redraws to happen by using the [`background`](mithril.request.md#rendering-before-web-service-requests-finish) and `initialValue` options in `m.request`, or by manually calling [`m.redraw()`](mithril.redraw.md).
|
||||
|
||||
If a component A contains another component B that calls asynchronous services, then when component A is rendered, a `<placeholder>` tag is rendered in place of component B until B's asynchronous services resolve. Once they do, the placeholder is replaced with component B's view.
|
||||
If a component A contains another component B that calls asynchronous services, when component A is rendered, a `<placeholder>` tag is rendered in place of component B until B's asynchronous services resolve. Once resolved, the placeholder is replaced with component B's view.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -563,11 +568,11 @@ where:
|
|||
|
||||
- **Component component**
|
||||
|
||||
A component is supposed to be an Object with two keys: `controller` and `view`. Each of those should point to a Javascript function
|
||||
A component is supposed to be an Object with two keys: `controller` and `view`. Each of these should point to a Javascript function. If a contoller is not specified, Mithril will automatically create an empty controller function.
|
||||
|
||||
- **Object attributes**
|
||||
|
||||
A key/value map of attributes that gets bound as an argument to the `controller` and `view` functions of the component.
|
||||
A key/value map of attributes that gets bound as an argument to both the `controller` and `view` functions of the component.
|
||||
|
||||
- **any... args**
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue