Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor updates #343

Merged
merged 1 commit into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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