diff --git a/README.md b/README.md index 0aada168..8509dccd 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,13 @@ app.PageList = function() { //controller app.controller = function() { - this.pages = app.PageList(); - - this.rotate = function() { - this.pages().push(this.pages().shift()) - }.bind(this) + var pages = app.PageList(); + return { + pages: pages, + rotate: function() { + pages().push(pages().shift()); + } + } }; //view @@ -57,10 +59,11 @@ app.view = function(ctrl) { ctrl.pages().map(function(page) { return m("a", {href: page.url}, page.title); }), - m("a", {onclick: ctrl.rotate}, "Rotate links") + m("button", {onclick: ctrl.rotate}, "Rotate links") ]; }; + //initialize m.module(document.getElementById("example"), app); ``` @@ -70,5 +73,5 @@ m.module(document.getElementById("example"), app); ### Learn more - [Tutorial](http://lhorie.github.io/mithril/getting-started.html) -- [Differences from Other MVC Frameworks](http://lhorie.github.io/mithril/comparison.html) +- [Differences from Other Frameworks](http://lhorie.github.io/mithril/comparison.html) - [Benchmarks](http://lhorie.github.io/mithril/benchmarks.html) \ No newline at end of file diff --git a/docs/change-log.md b/docs/change-log.md index 733e1329..5ba8cbe5 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -2,6 +2,14 @@ [v0.1.23](/mithril/archive/v0.1.23) - maintenance +### News: + +- There's now support for extended custom elements (e.g. `m("button[is=my-button]")`) +- `m.request` now supports a `initialValue` option to help prevent type errors in views when using the `background` option + +### Bug Fixes: + +- docs now have anchor links for easier navigation - fixed a bunch of IE8 issues [#298](https://github.com/lhorie/mithril.js/issues/298) - fixed handling of `method` option in JSONP mode [#292](https://github.com/lhorie/mithril.js/issues/292) - fixed source map files diff --git a/docs/comparison.md b/docs/comparison.md index e2f50687..cf9d4d03 100644 --- a/docs/comparison.md +++ b/docs/comparison.md @@ -1,6 +1,6 @@ ## How is Mithril Different from Other Frameworks -There are a lot of different Javascript MVC frameworks and evaluating their merits and shortcomings can be a daunting task. +There are a lot of different Javascript frameworks and evaluating their merits and shortcomings can be a daunting task. This page aims to provide a comparison between Mithril and some of the most widely used frameworks, as well as some of the younger, but relevant ones. @@ -104,7 +104,7 @@ Ember is also more opinionated in terms of how application architecture should l ### React -React is a templating engine developed by Facebook. It's relevant for comparison because it uses the same architecture as Mithril's templating engine: i.e. it acknowledges that DOM operations are the bottleneck of templating systems, and implements a virtual DOM tree which keeps track of changes and only applies diffs to the real DOM where needed. +React is a component engine developed by Facebook. It's relevant for comparison because it uses the same architecture as Mithril's templating engine: i.e. it acknowledges that DOM operations are the bottleneck of templating systems, and implements a virtual DOM tree which keeps track of changes and only applies diffs to the real DOM where needed. The most visible difference between React and Mithril is that React's *JSX* syntax does not run natively in the browser, whereas Mithril's uncompiled templates do. Both can be compiled, but React's compiled code still has function calls for each virtual DOM element; Mithril templates compile into static Javascript data structures. diff --git a/docs/layout/index.html b/docs/layout/index.html index db5ac699..21b13509 100644 --- a/docs/layout/index.html +++ b/docs/layout/index.html @@ -77,19 +77,22 @@

Sample code

//namespace
+var app = {};
+
 //model
-var PageList = function() {
+app.PageList = function() {
 	return m.request({method: "GET", url: "pages.json"});
 };
 
 //controller
-var app = {};
 app.controller = function() {
-	this.pages = app.PageList();
-	
-	this.rotate = function() {
-		this.pages().push(this.pages().shift())
-	}.bind(this)
+	var pages = app.PageList();
+	return {
+		pages: pages,
+		rotate: function() {
+			pages().push(pages().shift());
+		}
+	}
 };
 
 //view
@@ -98,7 +101,7 @@ app.view = function(ctrl) {
 		ctrl.pages().map(function(page) {
 			return m("a", {href: page.url}, page.title);
 		}),
-		m("a", {onclick: ctrl.rotate}, "Rotate links")
+		m("button", {onclick: ctrl.rotate}, "Rotate links")
 	];
 };
 
@@ -121,11 +124,13 @@ app.PageList = function() {
 
 //controller
 app.controller = function() {
-	this.pages = app.PageList();
-	
-	this.rotate = function() {
-		this.pages().push(this.pages().shift())
-	}.bind(this)
+	var pages = app.PageList();
+	return {
+		pages: pages,
+		rotate: function() {
+			pages().push(pages().shift());
+		}
+	}
 };
 
 //view
diff --git a/docs/mithril.request.md b/docs/mithril.request.md
index be435f21..3d4aa162 100644
--- a/docs/mithril.request.md
+++ b/docs/mithril.request.md
@@ -17,6 +17,7 @@
 - [Configuring the underlying XMLHttpRequest](#configuring-the-underlying-xmlhttprequest)
 - [Aborting a request](#aborting-a-request)
 - [Using JSON-P](#using-json-p)
+- [Rendering before web service requests finish](#rendering-before-web-service-requests-finish)
 - [Signature](#signature)
 
 ---
@@ -383,6 +384,35 @@ m.request({
 
 ---
 
+### Rendering before web service requests finish
+
+By default, Mithril waits for web service requests to complete before attempting a redraw. This ensures that data being accessed in the view isn't nullable as a result of asynchronous data not being available yet.
+
+However, sometimes we do want to be able to redraw before a web service request completes, either because one web service out of many is slow, or because we don't need its response in order to redraw.
+
+Setting the `background` option to `true` prevents a request from affecting redrawing. This means it's possible for a view to attempt to use data before it is available. You can specify an initial value for the `m.request` getter-setter in order to avoid having to write defensive code against potential null reference exceptions:
+
+```javascript
+var demo = {}
+
+demo.controller = function() {
+	return {
+		users: m.request({method: "GET", url: "/api/user", background: true, initialValue: []})
+	}
+}
+
+//in the view
+demo.view = function(ctrl) {
+	//This view gets rendered before the request above completes
+	//Calling .map doesn't throw an error because we defined the initial value to be an empty array, instead of undefined
+	return ctrl.users().map(function() {
+		return m("div", user.name)
+	})
+}
+```
+
+---
+
 ### Signature
 
 [How to read signatures](how-to-read-signatures.md)
@@ -401,6 +431,7 @@ where:
 		[String password,]
 		[Object data,]
 		[Boolean background,]
+		[any initialValue,]
 		[any unwrapSuccess(any data),]
 		[any unwrapError(any data),]
 		[String serialize(any dataToSerialize),]
@@ -454,10 +485,32 @@ where:
 		In order to force a redraw after a background request, use [`m.redraw`](mithril.redraw.md)
 		
 		```javascript
-		m.request({method: "GET", url: "/foo", background: true})
-			.then(m.redraw); //force redraw
+		var demo = {}
+		
+		demo.controller = function() {
+			return {
+				users: m.request({method: "GET", url: "/api/user", background: true, initialValue: []}).then(function(value) {
+					//force redraw
+					m.redraw()
+					return value
+				})
+			}
+		}
+		
+		demo.view = function(ctrl) {
+			//this view renders twice (once immediately, and once after the request above completes)
+			return ctrl.users.map(function(user) {
+				return m("div", user.name)
+			})
+		}
 		```
 		
+		It's recommended that you always set an `initialValue` when setting the `background` option to true.
+		
+	-	**any initialValue** (optional)
+	
+		The value that populates the returned getter-setter before the request completes. This is useful when using the `background` option, in order to avoid the need for null checks in views that may be attempting to access the returned getter-setter before the asynchronous request resolves.
+		
 	-	**any unwrapSuccess(any data)** (optional)
 
 		A preprocessor function to unwrap the data from a success response in case the response contains metadata wrapping the data.
diff --git a/docs/practices.md b/docs/practices.md
index 51ba55e9..fa2a7266 100644
--- a/docs/practices.md
+++ b/docs/practices.md
@@ -18,7 +18,7 @@ Because Mithril encourages all entity logic to be done in the model layer, it's
 
 Models are also responsible for centralizing tasks such as filtering of entity lists and validation routines, so that access to these methods is available across the application.
 
-DOM manipulation should be done in the view via [`m()` and `config`](mithril). Controllers may explicitly call [`m.redraw`](mithril.redraw.md), but, if possible, it's preferable to abstract this into a service which integrates with Mithril's auto-redrawing system (see [`m.startComputation` / `m.endComputation`](mithril.computation.md)).
+DOM manipulation should be done in the view via [`m()` and `config`](mithril). Controllers may explicitly call [`m.redraw`](mithril.redraw.md), but, if possible, it's preferable to abstract this into a service which integrates with Mithril's auto-redrawing system (see [`m.startComputation` / `m.endComputation`](mithril.computation.md)). You should avoid instantiating controller classes from views.
 
 ---