Permalink
Browse files

Add load and save events. [Ticket #2531207]

  • Loading branch information...
1 parent 9813f48 commit d89a7d2fca300684fcbe3426f41ed30d106d17ec @rgrove committed Oct 21, 2011
Showing with 277 additions and 16 deletions.
  1. +10 −0 src/app/HISTORY.md
  2. +78 −8 src/app/docs/model/index.mustache
  3. +95 −8 src/app/js/model.js
  4. +94 −0 src/app/tests/app-test.js
View
@@ -4,6 +4,16 @@ App Framework Change History
3.5.0
-----
+### Model
+
+* `load()` now fires a `load` event after the operation completes successfully,
+ or an `error` event on failure. The `load()` callback (if provided) will still
+ be called in both cases. [Ticket #2531207]
+
+* `save()` now fires a `save` event after the operation completes successfully,
+ or an `error` event on failure. The `save()` callback (if provided) will still
+ be called in both cases. [Ticket #2531207]
+
### ModelList
* Added a `filter()` method that returns a filtered array of models. [Ticket
@@ -272,28 +272,28 @@ Model instances provide the following events:
</td>
<td>
<dl>
- <dt><strong>changed (<em>Object</em>)</strong></dt>
+ <dt>`changed` (<em>Object</em>)</dt>
<dd>
<p>
Hash of change information for each attribute that changed. Keys are attribute names, values are objects with the following properties:
</p>
<dl style="margin-top: 1em;">
- <dt><strong>`newVal`</strong></dt>
+ <dt>`newVal`</dt>
<dd>
<p>
The new value of the attribute after it changed.
</p>
</dd>
- <dt><strong>`prevVal`</strong></dt>
+ <dt>`prevVal`</dt>
<dd>
<p>
The old value of the attribute before it changed.
</p>
</dd>
- <dt><strong>`src`</strong></dt>
+ <dt>`src`</dt>
<dd>
<p>
The source of the change, or `null` if no source was specified when the change was made.
@@ -318,28 +318,42 @@ Model instances provide the following events:
</td>
<td>
<dl>
- <dt><strong>error</strong></dt>
+ <dt>`error`</dt>
<dd>
<p>
Error message, object, or exception generated by the error. Calling `toString()` on this should result in a meaningful error message.
</p>
</dd>
- <dt><strong>src</strong></dt>
+ <dt>`src`</dt>
<dd>
<p>
Source of the error. May be one of the following default sources, or any custom error source used by your Model subclass):
</p>
<dl style="margin-top: 1em;">
- <dt><strong>`parse`</strong></dt>
+ <dt>`load`</dt>
+ <dd>
+ <p>
+ An error loading the model from a sync layer. The sync layer's response (if any) will be provided as the `response` property on the event facade.
+ </p>
+ </dd>
+
+ <dt>`parse`</dt>
<dd>
<p>
An error parsing a response from a sync layer.
</p>
</dd>
- <dt><strong>`validate`</strong></dt>
+ <dt>`save`</dt>
+ <dd>
+ <p>
+ An error saving the model to a sync layer. The sync layer's response (if any) will be provided as the `response` property on the event facade.
+ </p>
+ </dd>
+
+ <dt>`validate`</dt>
<dd>
<p>
The model failed to validate.
@@ -350,6 +364,58 @@ Model instances provide the following events:
</dl>
</td>
</tr>
+
+ <tr>
+ <td>`load`</td>
+ <td>
+ <p>
+ After model attributes are loaded from a sync layer.
+ </p>
+ </td>
+ <td>
+ <dl>
+ <dt>`parsed`</dt>
+ <dd>
+ <p>
+ The parsed version of the sync layer's response to the load request.
+ </p>
+ </dd>
+
+ <dt>`response`</dt>
+ <dd>
+ <p>
+ The sync layer's raw, unparsed response to the load request.
+ </p>
+ </dd>
+ </dl>
+ </td>
+ </tr>
+
+ <tr>
+ <td>`save`</td>
+ <td>
+ <p>
+ After model attributes are saved to a sync layer.
+ </p>
+ </td>
+ <td>
+ <dl>
+ <dt>`parsed`</dt>
+ <dd>
+ <p>
+ The parsed version of the sync layer's response to the save request.
+ </p>
+ </dd>
+
+ <dt>`response`</dt>
+ <dd>
+ <p>
+ The sync layer's raw, unparsed response to the save request.
+ </p>
+ </dd>
+ </dl>
+ </td>
+ </tr>
</tbody>
</table>
@@ -660,6 +726,10 @@ pie.save(function (err, response) {
```
<p>
+In addition to calling the specified callback (if any), the `load()` and `save()` methods will fire a `load` event and a `save` event respectively on success, or an `error` event on failure. See [[#Model Events]] for more details on these events.
+</p>
+
+<p>
Always use the `load()` or `save()` methods rather than calling `sync()` directly, since this ensures that the sync layer's response is passed through the `parse()` method and that the model's data is updated if necessary.
</p>
View
@@ -49,12 +49,45 @@ var GlobalEnv = YUI.namespace('Env.Model'),
@param {String} src Source of the error. May be one of the following (or any
custom error source defined by a Model subclass):
+ * `load`: An error loading the model from a sync layer. The sync layer's
+ response (if any) will be provided as the `response` property on the
+ event facade.
+
* `parse`: An error parsing a JSON response. The response in question will
be provided as the `response` property on the event facade.
+
+ * `save`: An error saving the model to a sync layer. The sync layer's
+ response (if any) will be provided as the `response` property on the
+ event facade.
+
* `validate`: The model failed to validate. The attributes being validated
will be provided as the `attributes` property on the event facade.
**/
- EVT_ERROR = 'error';
+ EVT_ERROR = 'error',
+
+ /**
+ Fired after model attributes are loaded from a sync layer.
+
+ @event load
+ @param {Object} parsed The parsed version of the sync layer's response to
+ the load request.
+ @param {any} response The sync layer's raw, unparsed response to the load
+ request.
+ @since 3.5.0
+ **/
+ EVT_LOAD = 'load',
+
+ /**
+ Fired after model attributes are saved to a sync layer.
+
+ @event save
+ @param {Object} [parsed] The parsed version of the sync layer's response to
+ the save request, if there was a response.
+ @param {any} [response] The sync layer's raw, unparsed response to the save
+ request, if there was one.
+ @since 3.5.0
+ **/
+ EVT_SAVE = 'save';
function Model() {
Model.superclass.constructor.apply(this, arguments);
@@ -299,6 +332,9 @@ Y.Model = Y.extend(Model, Y.Base, {
operation, which is an asynchronous action. Specify a _callback_ function to
be notified of success or failure.
+ A successful load operation will fire a `load` event, while an unsuccessful
+ load operation will fire an `error` event with the `src` value "load".
+
If the load operation succeeds and one or more of the loaded attributes
differ from this model's current attributes, a `change` event will be fired.
@@ -324,16 +360,41 @@ Y.Model = Y.extend(Model, Y.Base, {
options = {};
}
- this.sync('read', options, function (err, response) {
- if (!err) {
- self.setAttrs(self.parse(response), options);
+ options || (options = {});
+
+ self.sync('read', options, function (err, response) {
+ var facade = {
+ options : options,
+ response: response
+ },
+
+ parsed;
+
+ if (err) {
+ facade.error = err;
+ facade.src = 'load';
+
+ self.fire(EVT_ERROR, facade);
+ } else {
+ // Lazy publish.
+ if (!self._loadEvent) {
+ self._loadEvent = self.publish(EVT_LOAD, {
+ preventable: false
+ });
+ }
+
+ parsed = facade.parsed = self.parse(response);
+
+ self.setAttrs(parsed, options);
self.changed = {};
+
+ self.fire(EVT_LOAD, facade);
}
callback && callback.apply(null, arguments);
});
- return this;
+ return self;
},
/**
@@ -378,6 +439,9 @@ Y.Model = Y.extend(Model, Y.Base, {
operation, which is an asynchronous action. Specify a _callback_ function to
be notified of success or failure.
+ A successful load operation will fire a `load` event, while an unsuccessful
+ load operation will fire an `error` event with the `src` value "load".
+
If the save operation succeeds and one or more of the attributes returned in
the server's response differ from this model's current attributes, a
`change` event will be fired.
@@ -410,13 +474,36 @@ Y.Model = Y.extend(Model, Y.Base, {
return self;
}
+ options || (options = {});
+
self.sync(self.isNew() ? 'create' : 'update', options, function (err, response) {
- if (!err) {
+ var facade = {
+ options : options,
+ response: response
+ },
+
+ parsed;
+
+ if (err) {
+ facade.error = err;
+ facade.src = 'save';
+
+ self.fire(EVT_ERROR, facade);
+ } else {
+ // Lazy publish.
+ if (!self._loadEvent) {
+ self._loadEvent = self.publish(EVT_LOAD, {
+ preventable: false
+ });
+ }
+
if (response) {
- self.setAttrs(self.parse(response), options);
+ parsed = facade.parsed = self.parse(response);
+ self.setAttrs(parsed, options);
}
self.changed = {};
+ self.fire(EVT_SAVE, facade);
}
callback && callback.apply(null, arguments);
@@ -543,7 +630,7 @@ Y.Model = Y.extend(Model, Y.Base, {
@param {Object} [options] Sync options. It's up to the custom sync
implementation to determine what options it supports or requires, if any.
- @param {callback} [callback] Called when the sync operation finishes.
+ @param {Function} [callback] Called when the sync operation finishes.
@param {Error|null} callback.err If an error occurred, this parameter will
contain the error. If the sync operation succeeded, _err_ will be
falsy.
Oops, something went wrong.

0 comments on commit d89a7d2

Please sign in to comment.