Skip to content

Commit

Permalink
Minor updates (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
snewcomer authored Feb 24, 2019
1 parent 2a88c46 commit eb2455c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ember install ember-changeset
## Updates

We have released `v2.0.0-beta`. This includes a solution for deeply nested sets with one big caveat. Some history - Post v1.3.0, there was an elegant solution proposed and implemented for deeply nested sets - e.g. `changeset.set('profile.name', 'myname')`. However, this caused many issues and was reverted in v2.0.0-beta. Since `ember-changeset` relies on [Proxy](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy) like behaviour, we are able to trap `changeset.set(...` and properly handle nested sets. This, however, is a problem in templates where `mut changeset.profile.name` is implicitly `set(changeset, 'profile.name')`, thus subverting our trap. This is the caveat with the v2.0.0-beta release. Although it is an improvement over v1.3.0 and should be 1-1 behaviour if you are setting at a single level - e.g. `mut changeset.name` -, nested setters don't have an ideal solution. So we are releasing v2.0.0-beta with this caveat and adding a `changeset-set` template helper. This is a work in progress.
We have released `v2.0.0`. This includes a solution for deeply nested sets with one big caveat. Some history - Post v1.3.0, there was an elegant solution proposed and implemented for deeply nested sets - e.g. `changeset.set('profile.name', 'myname')`. However, this caused many issues and was reverted in v2.0.0-beta. Since `ember-changeset` relies on [Proxy](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy) like behaviour, we are able to trap `changeset.set(...` and properly handle nested sets. This, however, is a problem in templates where `mut changeset.profile.name` is implicitly `set(changeset, 'profile.name')`, thus subverting our trap. This is the caveat with the v2.0.0 release. Although it is an improvement over v1.3.0 and should be 1-1 behaviour if you are setting at a single level - e.g. `mut changeset.name` -, nested setters don't have an ideal solution. So we are releasing v2.0.0 with this caveat and adding a `changeset-set` template helper. This is a work in progress.

## Philosophy

Expand Down Expand Up @@ -123,7 +123,7 @@ In the above example, when the input changes, only the changeset's internal valu
On rollback, all changes are dropped and the underlying Object is left untouched.

## Changeset template helper
`ember-changeset` overrides `set` in order to handle deeply nested setters. `mut` is simply an alias for `set(changeset`, thus we provide a `changeset-set` template helper.
`ember-changeset` overrides `set` in order to handle deeply nested setters. `mut` is simply an alias for `set(changeset`, thus we provide a `changeset-set` template helper if you are dealing with nested setters.

```hbs
<form>
Expand Down Expand Up @@ -936,14 +936,14 @@ export default Component.extend({

## Running

* `ember server`
* `ember serve`
* Visit your app at http://localhost:4200.

## Running Tests

* `npm test` (Runs `ember try:testall` to test your addon against multiple Ember versions)
* `ember test`
* `ember test --server`
* `ember test --serve`

## Building

Expand Down
36 changes: 31 additions & 5 deletions addon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export function changeset(

/**
* Stores change on the changeset.
*
* @method setUnknownProperty
*/
setUnknownProperty<T> (
key: string,
Expand Down Expand Up @@ -176,6 +178,8 @@ export function changeset(
* })
* .execute(); // execute the changes
* ```
*
* @method prepare
*/
prepare(
prepareChangesFn: PrepareChangesFn
Expand All @@ -198,6 +202,8 @@ export function changeset(

/**
* Executes the changeset if in a valid state.
*
* @method execute
*/
execute(): ChangesetDef {
if (get(this, 'isValid') && get(this, 'isDirty')) {
Expand All @@ -212,6 +218,7 @@ export function changeset(
/**
* Executes the changeset and saves the underlying content.
*
* @method save
* @param {Object} options optional object to pass to content save method
*/
save(
Expand All @@ -222,15 +229,14 @@ export function changeset(
this.execute();

if (typeof content.save === 'function') {
let result: any | Promise<any> = content.save(options);
savePromise = result;
savePromise = content.save(options);
} else if (typeof get(content, 'save') === 'function') {
// we might be getting this off a proxy object. For example, when a
// belongsTo relationship (a proxy on the parent model)
// another way would be content(belongsTo).content.save
let result: Function | undefined = get(content, 'save');
if (result) {
savePromise = result(options);
let saveFunc: Function | undefined = get(content, 'save');
if (saveFunc) {
savePromise = saveFunc(options);
}
}

Expand All @@ -256,6 +262,8 @@ export function changeset(
* user.get('firstName'); // "Jimmy"
* user.get('lastName'); // "Fallon"
* ```
*
* @method merge
*/
merge(
changeset: ChangesetDef
Expand Down Expand Up @@ -288,6 +296,8 @@ export function changeset(
/**
* Returns the changeset to its pristine state, and discards changes and
* errors.
*
* @method rollback
*/
rollback(): ChangesetDef {
// Get keys before reset.
Expand All @@ -308,6 +318,7 @@ export function changeset(
*
* @public
* @chainable
* @method rollbackInvalid
* @param {String} key optional key to rollback invalid values
* @return {Changeset}
*/
Expand Down Expand Up @@ -338,6 +349,7 @@ export function changeset(
*
* @public
* @chainable
* @method rollbackProperty
* @param {String} key key to delete off of changes and errors
* @return {Changeset}
*/
Expand All @@ -353,6 +365,8 @@ export function changeset(
* If no key is passed into this method, it will validate all fields on the
* validationMap and set errors accordingly. Will throw an error if no
* validationMap is present.
*
* @method validate
*/
validate(
key: string | undefined
Expand All @@ -375,6 +389,8 @@ export function changeset(
/**
* Manually add an error to the changeset. If there is an existing
* error or change for `key`, it will be overwritten.
*
* @method addError
*/
addError<T> (
key: string,
Expand Down Expand Up @@ -404,6 +420,8 @@ export function changeset(

/**
* Manually push multiple errors to the changeset as an array.
*
* @method pushErrors
*/
pushErrors(
key: keyof ChangesetDef,
Expand All @@ -430,6 +448,8 @@ export function changeset(

/**
* Creates a snapshot of the changeset's errors and changes.
*
* @method snapshot
*/
snapshot(): Snapshot {
let changes: Changes = get(this, CHANGES);
Expand All @@ -452,6 +472,8 @@ export function changeset(
/**
* Restores a snapshot of changes and errors. This overrides existing
* changes and errors.
*
* @method restore
*/
restore({ changes, errors }: Snapshot): ChangesetDef {
validateNestedObj('snapshot.changes', changes);
Expand Down Expand Up @@ -479,6 +501,8 @@ export function changeset(
* Unlike `Ecto.Changeset.cast`, `cast` will take allowed keys and
* remove unwanted keys off of the changeset. For example, this method
* can be used to only allow specified changes through prior to saving.
*
* @method cast
*/
cast(allowed: string[] = []): ChangesetDef {
let changes: Changes = get(this, CHANGES);
Expand All @@ -497,6 +521,8 @@ export function changeset(
/**
* Checks to see if async validator for a given key has not resolved.
* If no key is provided it will check to see if any async validator is running.
*
* @method isValidating
*/
isValidating(key: string | void): boolean {
let runningValidations: RunningValidations = get(this, RUNNING_VALIDATIONS);
Expand Down
12 changes: 8 additions & 4 deletions tests/unit/changeset-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,8 @@ module('Unit | Utility | changeset', function(hooks) {
});

test('#save handles rejected proxy content', function(assert) {
assert.expect(1);

let done = assert.async();
let dummyChangeset = new Changeset(dummyModel);

Expand All @@ -790,12 +792,14 @@ module('Unit | Utility | changeset', function(hooks) {
});
});

run(() => {
dummyChangeset.save().catch((error) => {
dummyChangeset.save()
.then(() => {
assert.ok(false, 'WAT?!');
})
.catch((error) => {
assert.equal(error.message, 'some ember data error');
})
.finally(() => done());
});
.finally(() => done());
});

test('#save proxies to content even if it does not implement #save', function(assert) {
Expand Down

0 comments on commit eb2455c

Please sign in to comment.