parent
75626b30db
commit
6042b001f0
8 changed files with 203 additions and 1 deletions
20
docs/api.md
20
docs/api.md
|
|
@ -143,6 +143,26 @@ m.mount(document.body, Component)
|
|||
|
||||
---
|
||||
|
||||
#### m.prop(initial) - [docs](prop.md)
|
||||
|
||||
```javascript
|
||||
var Component = {
|
||||
oninit: function(vnode) {
|
||||
vnode.state.current = m.prop("")
|
||||
},
|
||||
view: function(vnode) {
|
||||
return m("input", {
|
||||
oninput: function(ev) { vnode.state.current.set(ev.target.value) },
|
||||
value: vnode.state.current.get(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(document.body, Component)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### m.trust(htmlString) - [docs](trust.md)
|
||||
|
||||
```javascript
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
- API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097))
|
||||
- render/core: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122))
|
||||
- render/core: revamp the core diff engine, and introduce a longest-increasing-subsequence-based logic to minimize DOM operations when re-ordering keyed nodes.
|
||||
- API: Introduction of `m.prop()` ([#2268](https://github.com/MithrilJS/mithril.js/pull/2268))
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
- [m.parseQueryString](parseQueryString.md)
|
||||
- [m.buildQueryString](buildQueryString.md)
|
||||
- [m.withAttr](withAttr.md)
|
||||
- [m.prop](prop.md)
|
||||
- [m.trust](trust.md)
|
||||
- [m.fragment](fragment.md)
|
||||
- [m.redraw](redraw.md)
|
||||
|
|
|
|||
152
docs/prop.md
Normal file
152
docs/prop.md
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# prop(attrName, callback)
|
||||
|
||||
- [Description](#description)
|
||||
- [Signature](#signature)
|
||||
- [How it works](#how-it-works)
|
||||
- [Sending through requests](#sending-through-requests)
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
Returns a simple getter/setter object.
|
||||
|
||||
```javascript
|
||||
var name = m.prop("John")
|
||||
|
||||
var oldName = name.get() // First, it's set to "John"
|
||||
name.set("Mary") // Set the value to "Mary"
|
||||
var newName = name.get() // Now it's "Mary", not "John"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Signature
|
||||
|
||||
`prop = m.prop(initial?)`
|
||||
|
||||
Argument | Type | Required | Description
|
||||
----------- | ------ | -------- | ---
|
||||
`initial` | `any` | No | The prop's initial value
|
||||
**returns** | `Prop` | | A prop
|
||||
|
||||
`value = prop.get()`
|
||||
|
||||
Argument | Type | Required | Description
|
||||
----------- | ----- | -------- | ---
|
||||
**returns** | `any` | | The prop's current value
|
||||
|
||||
`newValue = prop.set(newValue)`
|
||||
|
||||
Argument | Type | Required | Description
|
||||
----------- | ----- | -------- | ---
|
||||
`newValue` | `any` | Yes | The value to set the prop to
|
||||
**returns** | `any` | | The value you just set the prop to, for convenience
|
||||
|
||||
[How to read signatures](signatures.md)
|
||||
|
||||
---
|
||||
|
||||
### How it works
|
||||
|
||||
The `m.prop` method creates a prop, a getter/setter object wrapping a single mutable reference. You can get the current value with `prop.get()` and set it with `prop.set(value)`. Unlike [streams](stream.md), you can't observe them, so you can't do as much with them.
|
||||
|
||||
In conjunction with [`m.withAttr`](withAttr.md), you can emulate two-way binding pretty easily.
|
||||
|
||||
```javascript
|
||||
var Component = {
|
||||
oninit: function(vnode) {
|
||||
vnode.state.current = m.prop("")
|
||||
},
|
||||
view: function(vnode) {
|
||||
return m("input", {
|
||||
oninput: m.withAttr("value", vnode.state.current.set),
|
||||
value: vnode.state.current.get(),
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
They're also useful for making simpler models.
|
||||
|
||||
```javascript
|
||||
// With props
|
||||
var Auth = {
|
||||
username: m.prop(""),
|
||||
password: m.prop(""),
|
||||
canSubmit: function() {
|
||||
return Auth.username.get() !== "" && Auth.password.get() !== ""
|
||||
},
|
||||
login: function() {
|
||||
// ...
|
||||
},
|
||||
}
|
||||
|
||||
// Without props
|
||||
var Auth = {
|
||||
username: "",
|
||||
password: "",
|
||||
setUsername: function(value) {
|
||||
Auth.username = value
|
||||
}
|
||||
setPassword: function(value) {
|
||||
Auth.password = value
|
||||
}
|
||||
canSubmit: function() {
|
||||
return Auth.username !== "" && Auth.password !== ""
|
||||
},
|
||||
login: function() {
|
||||
// ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Sending through requests
|
||||
|
||||
For convenience, props define `.toJSON` as an alias for `.get`. This is so you can send them through `m.request` without serializing them manually.
|
||||
|
||||
We could also take this model and simplify it:
|
||||
|
||||
```javascript
|
||||
// How it's loaded
|
||||
User.load = function(id) {
|
||||
return m.request({
|
||||
method: "GET",
|
||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + id,
|
||||
withCredentials: true,
|
||||
})
|
||||
.then(function(result) {
|
||||
User.current = {
|
||||
id: result.id,
|
||||
firstName: m.prop(result.firstName),
|
||||
lastName: m.prop(result.lastName),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Original
|
||||
User.save = function(user) {
|
||||
return m.request({
|
||||
method: "PUT",
|
||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + user.id,
|
||||
data: {
|
||||
id: user.id,
|
||||
firstName: user.firstName.get(),
|
||||
lastName: user.lastName.get(),
|
||||
},
|
||||
withCredentials: true,
|
||||
})
|
||||
}
|
||||
|
||||
// Simplified
|
||||
User.save = function(user) {
|
||||
return m.request({
|
||||
method: "PUT",
|
||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + user.id,
|
||||
data: user,
|
||||
withCredentials: true,
|
||||
})
|
||||
}
|
||||
```
|
||||
1
index.js
1
index.js
|
|
@ -9,6 +9,7 @@ requestService.setCompletionCallback(redrawService.redraw)
|
|||
m.mount = require("./mount")
|
||||
m.route = require("./route")
|
||||
m.withAttr = require("./util/withAttr")
|
||||
m.prop = require("./util/prop")
|
||||
m.render = require("./render").render
|
||||
m.redraw = redrawService.redraw
|
||||
m.request = requestService.request
|
||||
|
|
|
|||
9
util/prop.js
Normal file
9
util/prop.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
"use strict"
|
||||
|
||||
module.exports = function (store) {
|
||||
return {
|
||||
get: function() { return store },
|
||||
toJSON: function() { return store },
|
||||
set: function(value) { return store = value }
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,10 @@
|
|||
<script src="../../ospec/ospec.js"></script>
|
||||
|
||||
<script src="../../util/withAttr.js"></script>
|
||||
<script src="../../util/prop.js"></script>
|
||||
<script src="test-withAttr.js"></script>
|
||||
|
||||
<script src="test-prop.js"></script>
|
||||
|
||||
<script>require("../../ospec/ospec").run()</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
16
util/tests/test-prop.js
Normal file
16
util/tests/test-prop.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
"use strict"
|
||||
|
||||
var o = require("../../ospec/ospec")
|
||||
var prop = require("../../util/prop")
|
||||
|
||||
o.spec("prop", function() {
|
||||
o("works", function() {
|
||||
var p = prop(1)
|
||||
|
||||
o(p.get()).equals(1)
|
||||
o(p.toJSON()).equals(1)
|
||||
o(p.set(2)).equals(2)
|
||||
o(p.get()).equals(2)
|
||||
o(p.toJSON()).equals(2)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue