-
-
Notifications
You must be signed in to change notification settings - Fork 131
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
Add afterInfinityModel #77
Conversation
Sorry about opening a PR with test failures. Before I go in and fix them up, I wanted to make sure that this was actually an option you were interested in and an approach that makes sense. If it is, I'm happy to go in and update all of the testing. If the approach doesn't make sense, I'm also happy to try something else. |
innnnnneresting @kxcrl ! thanks for this. Let me mull it over a couple days while we work on supporting ED 1.13x |
@hhff Cool. = ) Sounds good. Again, just let me know if you'd like to see any of it changed or rewritten. |
👍 to this idea. Thanks for the PR! |
I think I'd like the ergonomics to feel more like the regular model() {
return this.infinityModel('product', { perPage: 12, startingPage: 1 });
},
afterInfinityModel(infinityModelPromise) {
return infinityModelPromise.then(collection => {
let preloadPromises = [];
collection.forEach(item => {
preloadPromises.push(item.get('somethingAsync'));
});
return Ember.RSVP.all(preloadPromises);
});
} default would look like: afterInfinityModel(infinityModelPromise) {
return infinityModelPromise;
} I'm a little worried that this may obscure the semantics of how the model hook works though - ie: where should a "catch" live? @kxcrl / @mike-north / @kellyselden / @mkorfmann thoughts? |
@hhff I think that sounds great. I'm not sure I fully follow your concern, though - can you expound on it a bit more? Is it just about the extra overhead in making sure that any promise passed into the chain has a way to fail gracefully? |
@kxcrl I just mean that exposes a couple of places where developers can handle failed promises, instead of just one obvious place. I don't think it's a big concern tho - also, now you can catch failures in the Do you want to have a pass at implementing it in this style brother? |
@hhff Ah, gotcha. Yep, will do! |
@hhff Alright, I finally had some time to sit down and implement this. Maybe I did something wrong, but your version was very easy to get working. Let me know what you think and I'll get it wrapped in some tests. |
@@ -174,7 +174,8 @@ export default Ember.Mixin.create({ | |||
} | |||
|
|||
var params = Ember.merge(requestPayloadBase, options); | |||
let promise = this.store[this._storeFindMethod](modelName, params); | |||
|
|||
let promise = this.afterInfinityModel(this.store[this._storeFindMethod](modelName, params)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think afterInfinityModel
should be called on the resolved outcome of the promise - that way you know the object passed in is data, rather than a thennable
.
This is closer to how the regular afterModel
works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, there was another implementation of this that I tried out and didn't commit:
let promise = this.store[this._storeFindMethod](modelName, params).then(afterInfinityModel);
Something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yuuuuuuuuuuuuup
👍 awesome work - added a comment in! |
Aaaaand maybe that'll do it? I updated the |
@hhff Just checking in real quick. Anything else you'd like to see on this one? |
return this.infinityModel('item'); | ||
}, | ||
afterInfinityModel(items) { | ||
return items.setEach('author', 'F. Scott Fitzgerald'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we also do a test that uses a second promise as the return?
something like:
afterInfinityModel(items) {
return new Promise((resolve) => {
resolve(items.setEach('author', 'F. Scott Fitzgerald'));
});
}
thanks so much @kxcrl ! Could u add a test for a returning promise (comment above)
and then we're good!! You're the man thankyou! |
@hhff Awesome! Thanks for all the feedback and walking me through everything you were looking for. Let me know if there's anything else that needs changing. |
Amazing...! I'm very excited for this. Any idea why beta is failing on travis? |
@hhff Great question. I read through the 2.2.0-beta.1 changelog and couldn't find anything that would seem to cause this. I can reproduce the failure locally with If you checkout I tried a few things with the failing test itself, but I ran out of time before I could get anywhere. |
@hhff Hmmm, possibly, but unfortunately not until later next week at the earliest. I'm also wondering if it might just be a bug in the latest ember beta. Is this something you want fixed before you merge any pulls? |
Yeah Ideally! No rush / no stress :) |
@return {Ember.RSVP.Promise} | ||
*/ | ||
afterInfinityModel(infinityModelPromiseResult) { | ||
return infinityModelPromiseResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this gets used as a chained promise, it requires the end-user code to make sure to call _super
and also return the correct result needed downstream by updateInfinityModel
. It would be better if it was an optional hook like so:
_afterInfinityModel(infinityModelPromiseResult) {
if (typeof this.afterInfinityModel === 'function') {
this.afterInfinityModel(infinityModelPromiseResult);
}
return infinityModelPromiseResult;
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not too sure if a call to _super
is needed. You're right about it expecting afterInfinityModel
to return the objects, which I don't like too much either.
What's your take on this? @kxcrl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provided the user returns something that can get('content')
we should be fine yeah?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be ideal IMHO if the user didn't have to remember to do anything at all. They have the option to alter infinityModelPromiseResult
in-place as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If returning something from the hook is a desired feature, that can be added, but it should be seen as a feature-add not a requirement IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regardless of the ember-infinity implementation (always flowing through the hook vs only flowing through it if defined) the developer must always be sure the return implements get('content')
though... right?
The difference is if we always flow through the hook, the developer can call _super
(conditionally, perhaps) if they feel like it.
afterInfinityModel(newObjects) {
if (mercuryInRetrograde) {
return doWork(newObjects)
} else {
this._super.apply(...arguments);
}
}
I'd imagine always flowing through a function is also sliiiiiiiiightly
quicker for the machine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhh i actually understand what you're saying now @davidgoli sorry
you're saying "do the afterInfinityModel
work" in tandem to the actual return, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
like, it could return syncronously but also trigger an async update, so it wouldn't block the population of the infinityModel
yeah?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aah not exactly. There's already an infinityModelUpdated
hook that executes async, and it doesn't work for #90 because the user route needs to update itself synchronously, before another request can be made.
If we go with this PR, I'd propose treating afterInfinityModel
EXACTLY the same as Ember.Route#afterModel
(http://emberjs.com/api/classes/Ember.Route.html#method_afterModel), if the value returned from this hook is a promise, the transition will pause until the transition resolves. Otherwise, non-promise return values are not utilized in any way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree @davidgoli 👍 we should wait if it's a promise!
@hhff @davidgoli @ManuelArno Sorry for the long delay. I went through and rebased this and added in the changes that you all were requesting to |
}) | ||
.then(function(posts) { | ||
return posts | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this then
does nothing and can be removed?
return _this.afterInfinityModel(infinityModelPromiseResult); | ||
}; | ||
} else { | ||
return infinityModelPromiseResult; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be wrapped in a function? in either case, the return value of this method should be a function that accepts infinityModelPromiseResult
. In fact you might just do:
_afterInfinityModel(_this) {
return function (infinityModelPromiseResult) {
if (typeof _this.afterInfinityModel === 'function') {
return _this.afterInfinityModel(infinityModelPromiseResult);
} else {
return infinityModelPromiseResult;
}
};
}
I'm not seeing a test failure for this though, but I'm p sure infinityModelPromiseResult
isn't defined when the method is called on line 270
Right on both counts, @davidgoli |
post.get('author') | ||
}) | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need a return
in the afterInfinityModel function, right? Otherwise infinityModel
would end up as null
. (here and above)
Also, I don't think this code would actually work. We'd need an RSVP#all
I think!
afterInfinityModel: function(posts) {
return Ember.RSVP.all(posts.map(function(post) {
post.get('author');
});
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there also aren't enough closing parens here:
afterInfinityModel: function(posts) {
return Ember.RSVP.all(posts.map(function(post) {
return post.get('author');
}));
}
@davidgoli / @ManuelArno - are u guys happy with this? After the changes to the Readme - I'm happy to release this badboi |
👍 2015-11-12 4:03 GMT+01:00 Hugh Francis [email protected]:
Manuel Arno Korfmann manu @ korfmann . info |
@@ -250,7 +267,7 @@ export default Ember.Mixin.create({ | |||
const nextPage = this.incrementProperty('currentPage'); | |||
const params = this._buildParams(nextPage); | |||
|
|||
return this.store[this._storeFindMethod](modelName, params); | |||
return this.store[this._storeFindMethod](modelName, params).then(this._afterInfinityModel(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please wrap before .then
to reduce line length
A few nitpicks but otherwise looking solid! |
great nitpicks @davidgoli ! one can never nitpick enough with software ore one has to nitpick later (and longer) 👍 |
Thanks @davidgoli - I just made you a collab to this repo. When you're happy with this PR - please merge it and I'll cut a release! |
@davidgoli K. Things got pretty busy with work again, but I'm hoping to have time to fix this up real quick tomorrow. |
@kxcrl any updates? would be great to get this out! |
@davidgoli I implemented a couple of your changes. I couldn't figure out how to refactor the tests to use the new method with the time I had and |
@kxcrl I don't have push access to your repository, so I'm just going to check it out and create a new branch in the main repo to finish the work. Thanks so much for your help! |
Closing this in favor of #105 amazing work @kxcrl & @davidgoli ! |
@davidgoli Awesome. 👍 |
In the application that I'm working on, there are many cases where
get(this, 'store').find(modelName, params)
is not the end of the promise chain before we hand the fetched models to the route. This PR adds that functionality.I tried to follow the conventions that I could see for declaring private parameters, using the options object, and deleting keys after creating variables for them. That said, it does seem a little odd to have an
_afterModelPromise
private property, and you might have better suggestions for how things should be named.