Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat(ngPluralize): add support for bind-once in count #10022

Closed
wants to merge 1 commit into from

Conversation

gkalpak
Copy link
Member

@gkalpak gkalpak commented Nov 12, 2014

The 1st commit contains the change and test for adding support for bindOnce in count.
The 2nd commit contains some minor refactoring (mainly to avoid repetitive actions).

Closes #10004
(Makes #5452 obsolete)

tmpMatch = IS_WHEN.exec(attributeName);
if (tmpMatch) {
var whenKey = lowercase((tmpMatch[1] ? '-' : '') + tmpMatch[2]);
whens[whenKey] = element.attr(attr.$attr[attributeName]);
}
});
forEach(whens, function(expression, key) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if whens was created with createMap() then forEach() will break :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe default to [] instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or {} I guess

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alternatively, you could remove the forEach() and just do it Object.keys()-for-loop style.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True !
But shouldn't we rather be fixing forEach() ?
(I.e. replacing obj.hasOwnProperty(...) with hasOwnProperty.call(obj, ...) at https://github.com/angular/angular.js/blob/master/src/Angular.js#L265)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't care a whole lot about that --- @petebacondarwin would you be pro-refactoring forEach?

@caitp
Copy link
Contributor

caitp commented Nov 12, 2014

@lgalfaso since you wanted #10004 you can review this =)

@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch 2 times, most recently from 2908731 to ff6f155 Compare November 13, 2014 06:55
@jbedard
Copy link
Collaborator

jbedard commented Nov 13, 2014

I was about to say that this solution looks way too confusing - but it looks like you fixed it up as I started typing. Here's what I tried (yours basically does the same now): jbedard@6ffe579

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

@lgalfaso: I addressed your comments (and squashed everything in a single commit).

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

@jbedard: Actually, there is a problem with both our imlementation:
If a when expression has other embedded expressions (e.g. Hello, {{user}}, you have {} unread emails.), the element's text will not reflect any new values of them (e.g. user), because the watch only watches over count.
(Working on it.)

@jbedard
Copy link
Collaborator

jbedard commented Nov 13, 2014

Interesting... that makes it way more complicated :|

@jbedard
Copy link
Collaborator

jbedard commented Nov 13, 2014

Could watch numberExp (like we both did), and when it changes watch the appropriate interpolation (and unwatch the old one). As long as calling watch/unwatch whenever the number changes isn't a perf hit. Then, now that the result of $interpolate() will be watched directly, it will allow the $$watchDelegate to be used and will avoid doing an expensive $interpolate per-digest...

@jbedard
Copy link
Collaborator

jbedard commented Nov 13, 2014

Seems to work: jbedard@1583415, haven't looked into the performance differences at all though (I think it will actually be faster by not doing the interpolation in the watcher though).

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

@jbedard: That was my first thought too. One problem is that the count will also be updated, since in whensExpFns we have replaced {} with {{<numberExp> - <offset>}}.

@jbedard
Copy link
Collaborator

jbedard commented Nov 13, 2014

But that {} should be replaced with the bind-once numberExp. So assuming it doesn't change again between the numberExp watcher being invoked and the first interpolation watcher being invoked it should work? I think?

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

I pushed a 2nd commit which seems to fix the issue (in a different way than @jbedard).
Still not 100% satisfied with it.

Will play a bit with jbedard@1583415

@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch from 1e1c080 to abc03a3 Compare November 13, 2014 08:49
@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

But that {} should be replaced with the bind-once numberExp. So assuming it doesn't change again between the numberExp watcher being invoked and the first interpolation watcher being invoked it should work.

You are right about that.

Overall, I think I like the 2nd watcher approach better - perf implications aside (if any).
It might be better to not remove/readd the $watcher at every $digest, but just change the value somehwere it can access it.

@lgalfaso: WDYT ?

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

It might be better to not remove/readd the $watcher at every $digest, but just change the value somehwere it can access it.

Seems like we can't do that. (I guess I am not familiar enough with $interpolate and the $$watchDelegate thingy.)

@gkalpak
Copy link
Member Author

gkalpak commented Nov 13, 2014

I pushed another commit using the 2 watchers approach (similar to @jbedard's jbedard@1583415) and I am pretty happy with it 😃.

I added a check, so that we only unregister and re-register the 2nd watcher only if the key did actually change (e.g. the count might change from 10 to 20, but the watched function is still whensExpFns['other'], so we don't need to re-register).

/ping @lgalfaso

If it lgty, let me know so I squash the commits into 1.

@lgalfaso
Copy link
Contributor

@gkalpak I do not feel comfortable with how this is going. If the idea is to fix #10004, then the PR should be about this. Just trying to bundle everything that can be done to ngPluralize into a single PR does not make things any easier... specially when this change involves a breaking change

I would like to have a single commit that the only thing it does is fix the valid use case of #10004 (some small cleanup would be ok, but not behavior changes)

@gkalpak
Copy link
Member Author

gkalpak commented Nov 14, 2014

@lgalfaso: Not sure what behaviour changes you are talking about. The changes in this PR are about adding support for count to be a one-time expression (+ some minor cleanup).
Unfortunately, due to the previous implementation of ngPluralize, adding that kind of support isn't as straightforward.

Feel free to suggest a simpler approach; I might have missed something.

Also, not sure what is the breaking change you mention (other than that one-time expressions will work with `count`)...

$interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
offset + endSymbol));
});
for (var key in whens) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it cleaner to use forEach even when this implies that we end up using a {} or Object.keys()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wonder how forEach is cleaner, but I will change it 😃

if (count !== lastCount) {
watchRemover();
watchRemover = scope.$watch(whensExpFns[count],
function ngPluralizeWhensWatchAction(newVal) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move this function out, as it uses nothing from the closure

@lgalfaso
Copy link
Contributor

sorry, I misread part of the patch

once the changes from the comment are in place, the PR LGTM

@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch 2 times, most recently from d388a4a to 67c88b7 Compare November 14, 2014 21:19
@gkalpak
Copy link
Member Author

gkalpak commented Nov 14, 2014

@lgalfaso: Thx for the help on watch interceptors. This works great 😃
I addressed your comments and rebased.

watchRemover = scope.$watch(whensExpFns[newVal], updateElementText);
}

function ngPluralizeWatchInterceptor(newVal) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if at all possible, can we try to do this without interceptors? Otherwise it makes it slightly harder to get rid of them :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your call @lgalfaso but it would be better

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous implementation was without interceptors (but used an extra local variable).
So, it is doable (remains to see if it is desirable).

@caitp: Why remove interceptors ? They seem pretty cool :) What's the catch ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they add an extra hook in an aleady multi-hook process which complicates things and causes headaches which are very hard to debug, I want them gone .v.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after talking with @caitp I find it clear that it is better not to use the interceptor. Sorry @gkalpak for making you work extra, but can you repost this PR with a version that does not use an interceptor?
Thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also want them gone... but they do provide a useful feature of filtering the output of an expression like what @lgalfaso mentioned. But I don't like how they are implemented right now, but also haven't thought of anything better yet.

@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch from 67c88b7 to 8a24974 Compare November 14, 2014 23:23
@gkalpak
Copy link
Member Author

gkalpak commented Nov 14, 2014

Back to not using $parse interceptors.

@lgalfaso
Copy link
Contributor

LGTM
will merge after we cut 1.3.3

@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch from 8a24974 to a6029ee Compare November 18, 2014 09:53
@gkalpak gkalpak force-pushed the ngPluralize-bindOnce-count branch from a6029ee to e4dee6a Compare November 18, 2014 11:03
@gkalpak
Copy link
Member Author

gkalpak commented Nov 18, 2014

(FYI: I just removed an unused $parse dependency - a left-over from rapidly switching between interceptor/no-interceptor implementation 😃)

@lgalfaso
Copy link
Contributor

landed 2b41a58

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support one-time binding in ng-pluralize
5 participants