mithril-vndb/docs/prop.md
spacejack a147023f4e Docs - prioritize closure components for state (#2292)
* Emphasize closure components in components.md

* Use closure components for all stateful component examples

* Add change-log entry

* Edits and separate sections for closure, class & POJO state
2018-11-13 01:04:04 -05:00

3.3 KiB

prop(attrName, callback)


Description

Returns a simple getter/setter object.

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


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, you can't observe them, so you can't do as much with them.

In conjunction with m.withAttr, you can emulate two-way binding pretty easily.

function Component() {
	var current = m.prop("")
	return {
		view: function(vnode) {
			return m("input", {
				oninput: m.withAttr("value", current.set),
				value: current.get(),
			})
		}
	}
}

They're also useful for making simpler models.

// 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:

// 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,
	})
}