-
Notifications
You must be signed in to change notification settings - Fork 27.4k
refactor(data): camelCase keys in jqLite#data #15238
Conversation
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 performance is a concern then we ought to run some benchmarking...
Can we make camelCase()
more efficient in the common case?
|
||
fdescribe('camelCasing keys', function() { | ||
// jQuery 2.x has different behavior; skip the tests. | ||
// if (isJQuery2x()) return; |
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.
commented out?
var element = jqLite(a); | ||
|
||
element.data('a-B-c-d-42--e', 'z-x'); | ||
expect(element.data()).toEqual({'a-BCD-42-E': 'z-x'}); |
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.
is this actually how we want the camelcasing behaviour to work when there are already capital letters and double hyphens in the key? Or is it because of our current implementation of camelCase()
?
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.
This is exactly as jQuery does it. Only a single dash + a lowercase letter get converted.
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.
This is also how the HTML5 spec converts data attribute names to keys in dataset. That's where jQuery took it from.
It's also nice in that it's fully 1-1, the conversion doesn't lose any information.
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.
OK
a1fa313
to
ab465de
Compare
The first (new) commit is the commit from PR #15249, it's a prerequisite to make the second commit pass the tests. |
20bd769
to
72b195b
Compare
I updated the commit message, adding a breaking change info. I'm not very happy about the migration steps there, any better ideas? |
} else { // mass-setter: data({key1: val1, key2: val2}) | ||
extend(data, key); | ||
for (prop in key) { |
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.
This is different than extend
:
extend
only copies own properties.extend
ignores$$hashKey
.
If the chenges are intentional (e.g. to align with jQuery), we should clearly document them in the breaking change notice.
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.
Ok. Relevant jQuery code: https://github.com/jquery/jquery/blob/3.1.1/src/data/Data.js#L63-L65
The migration steps for that usecase work for me. I would also add an example of how this affects interacting with the data retrieved with a mass-getter. E.g.: // Before:
elem.data('foo-bar', 42);
elem.data()['foo-bar'];
// After:
elem.data('foo-bar', 42);
elem.data()['fooBar']; |
Both these commits should be scoped as |
I am not clear about what the migration step in 99b2dde is saying. Why are there more items in the "before" version? It would be helpful if the migration described what the "before" was trying to achieve and then how the "after" achieves it. |
I meant that either one of them may be replaced by either one of the cases in the "After" section. Can we have multiple before/after pairs? |
OK, so it would be good if you said this explicitly in the commit message. |
jqLite needs camelCase for it's css method; it should only convert one dash followed by a lowercase letter to an uppercase one; it shouldn't touch underscores, colons or collapse multiple dashes into one. This is behavior of jQuery 3 as well. This commit separates jqLite camelCasing from the $compile one (and $sce but that's an internal-only use). The $compile version should behave as before. Also, jqLite's css camelCasing logic was put in a separate function and refactored: now the properties starting from an uppercase letter are used by default (i.e. Webkit, not webkit) and the only exception is for the -ms- prefix that is converted to ms, not Ms. This makes the logic clearer as we're just always changing a dash followed by a lowercase letter by an uppercase one; this is also how it works in jQuery. Ref angular#15126 Fix angular#7744 BREAKING CHANGE: before, when Angular was used without jQuery, the key passed to the css method was more heavily camelCased; now only a single (!) hyphen followed by a lowercase letter is getting transformed. This also affects APIs that rely on the css method, like ngStyle. If you use Angular with jQuery, it already behaved in this way so no changes are needed on your part. To migrate the code follow the example below: Before: HTML: // All five versions used to be equivalent. <div ng-style={background_color: 'blue'}></div> <div ng-style={'background:color': 'blue'}></div> <div ng-style={'background-color': 'blue'}></div> <div ng-style={'background--color': 'blue'}></div> <div ng-style={backgroundColor: 'blue'}></div> JS: // All five versions used to be equivalent. elem.css('background_color', 'blue'); elem.css('background:color', 'blue'); elem.css('background-color', 'blue'); elem.css('background--color', 'blue'); elem.css('backgroundColor', 'blue'); // All five versions used to be equivalent. var bgColor = elem.css('background_color'); var bgColor = elem.css('background:color'); var bgColor = elem.css('background-color'); var bgColor = elem.css('background--color'); var bgColor = elem.css('backgroundColor'); After: HTML: // Previous five versions are no longer equivalent but these two still are. <div ng-style={'background-color': 'blue'}></div> <div ng-style={backgroundColor: 'blue'}></div> JS: // Previous five versions are no longer equivalent but these two still are. elem.css('background-color', 'blue'); elem.css('backgroundColor', 'blue'); // Previous five versions are no longer equivalent but these two still are. var bgColor = elem.css('background-color'); var bgColor = elem.css('backgroundColor');
This change aligns jqLite with jQuery 3. Close angular#15126 BREAKING CHANGE: Previously, keys passed to the data method were left untouched. Now they are internally camelCased similarly to how jQuery handles it, i.e. only single (!) hyphens followed by a lowercase letter get converted to an uppercase letter. This means keys `a-b` and `aB` represent the same data piece; writing to one of them will also be reflected if you ask for the other one. If you use Angular with jQuery, it already behaved in this way so no changes are required on your part. To migrate the code follow the examples below: BEFORE: /* 1 */ elem.data('my-key', 2); elem.data('myKey', 3); /* 2 */ elem.data('foo-bar', 42); elem.data()['foo-bar']; // 42 elem.data()['fooBar']; // undefined /* 3 */ elem.data()['foo-bar'] = 1; elem.data()['fooBar'] = 2; elem.data()['foo-bar']; // 1 AFTER: /* 1 */ // Rename one of the keys as they would now map to the same data slot. elem.data('my-key', 2); elem.data('my-key2', 3); /* 2 */ elem.data('foo-bar', 42); elem.data()['foo-bar']; // undefined elem.data()['fooBar']; // 42 /* 3 */ elem.data()['foo-bar'] = 1; elem.data()['fooBar'] = 2; elem.data()['foo-bar']; // 2
I fixed the first commit in #15249 and the second here & rebased. PTAL. |
@gkalpak PTAL as well, I added sth like what you suggested. |
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
A behavior change.
What is the current behavior? (You can also link to an open issue here)
jqLite#data
uses keys unchanged.What is the new behavior (if this is a feature change)?
jqLite#data
camelCases keys in its getters/setters. This aligns jqLite with jQuery.Does this PR introduce a breaking change?
Yes.
Please check if the PR fulfills these requirements
Other information:
This is WIP; this might slightly decrease performance so I wanted to discuss it first.
Also, finishing this would require making our
camelCase
function more strict so I'd like to discuss it first but I think we should do that anyway; the-moz-
hack doesn't really belong here.