-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Using attributeBindings for component in 1.11+ doesn't bind the form attr #11221
Comments
s = document.createElement('select')
// => <select></select>
s.form = 'foo'
// => "foo"
s.form
// => null Oh, DOM... |
@rwjblue it looks like |
I am inclined to thing that this is actually a bug in |
so setAttribute works correctly s = document.createElement('select')
// => <select></select>
s.setAttribute('form', 'foo')
// => undefined
s.form
// confusingly => null
s.getAttribute('form')
// => "bar" |
So it appears ember is setting this as a property, not an attribute... I suspect the AttrNode, needs to be aware its actually a property? Something seems extremely fishy... cc @mixonic I believe you are more familiar with this code-path (as you wrote it), thoughts? |
Ember will always set a property if a property exists. This is decided around here. We can probably deem |
I believe this also affects
I suspect we need to nail the heuristics and see what other strange attributes exists we need to take into account. |
i wonder if we can handle it via. var originalValue = element[name];
element[name] = value
if (element[name] === originalValue && // if the value hasn't changed
value !== originalValue && // if the value is different then the originalValue
value === value // if the value is not NaN
) {
element.setAttribute(name, value)
} |
@stefanpenner could that cause some calculations due to reading such properties as As an alternative, we can create a list of readonly attributes from the DOM specification: http://www.w3.org/TR/DOM-Level-2-HTML/html.html Searching for |
@vectart but 40 across how many elements, with what combination / permutation? Also the DOM changes over time.. |
@vectart we could likely cache the outcome to minimize the chance of an issue. |
Just for considering, I was thinking of building a list of read-only attributes and checking the element prototype. Is this solution overcomplicated? element = document.createElement('select');
attr = 'form';
// some dictionaries, might be generated by creating elements and brute-forcing their attributes
HTMLSelectElement.readOnlyAttributes = ['type', 'form', 'option'];
HTMLObjectElement.readOnlyAttributes = ['form', 'contentDocument'];
// check if it's impossible to set attribute
if (element instanceof HTMLSelectElement && HTMLSelectElement.readOnlyAttributes.indexOf(attr) > -1) {
set(element, attr, value);
} else {
element[attr] = value;
} |
shipping the list or computing it? |
@stefanpenner it's possible to ship it [{
interface: Document,
attrs: ['doctype', 'implementation', 'documentElement']
},
{
interface: Node,
attrs: ['nodeName', 'nodeType', 'parentNode', 'childNodes', 'firstChild', 'lastChild', 'previousSibling', 'nextSibling', 'attributes', 'ownerDocument']
},
{
interface: NodeList,
attrs: ['length']
},
{
interface: NamedNodeMap,
attrs: ['length']
},
{
interface: CharacterData,
attrs: ['length']
},
{
interface: Attr,
attrs: ['name', 'specified']
},
{
interface: Element,
attrs: ['tagName']
},
{
interface: DocumentType,
attrs: ['name', 'entities', 'notations']
},
{
interface: ProcessingInstruction,
attrs: ['target']
},
{
interface: HTMLCollection,
attrs: ['length']
},
{
interface: HTMLDocument,
attrs: ['referrer', 'domain', 'URL', 'images', 'applets', 'links', 'forms', 'anchors']
},
{
interface: HTMLFormElement,
attrs: ['elements', 'length']
},
{
interface: HTMLSelectElement,
attrs: ['type', 'length', 'form', 'options']
},
{
interface: HTMLOptionElement,
attrs: ['form', 'text', 'selected']
},
{
interface: HTMLInputElement,
attrs: ['form', 'type']
},
{
interface: HTMLTextAreaElement,
attrs: ['form', 'type']
},
{
interface: HTMLButtonElement,
attrs: ['form', 'type']
},
{
interface: HTMLLabelElement,
attrs: ['form']
},
{
interface: HTMLFieldSetElement,
attrs: ['form']
},
{
interface: HTMLLegendElement,
attrs: ['form']
},
{
interface: HTMLObjectElement,
attrs: ['form']
},
{
interface: HTMLMapElement,
attrs: ['areas']
},
{
interface: HTMLTableElement,
attrs: ['rows', 'tBodies']
},
{
interface: HTMLTableSectionElement,
attrs: ['rows']
}] I've performed a speed test with frequent used interfaces only and it displays quite low overhead |
For our purposes I think we can limit the map to just the list of |
@rwjblue I've updated the test with your recommendation: http://codepen.io/anon/pen/EjgvXP?editors=001 |
Seems good to me. Should I integrate & test this or @vectart do you want to take it from here? |
@stefanpenner I'd be glad to contribute, can work on that today. |
I'd prefer to see a dynamic system instead of a whitelist. |
I'm somewhat unsure as well. pro:
con:
|
@mixonic this list is converted from IDL definitions that are 17 years old, so it's quite stable :-) |
@mixonic hmm, wont the detection be screwed up once glimmer re-uses DOM produced by SSR ? As the current check is merely existence of a property, which deems it a property over an attribute. This in theory would confuse the check, and I suspect it would result attributes being incorrectly characterized as properties. I suspect I am also confused when overlap is acceptable, and when it is not. @mixonic can you share? |
@stefanpenner not all attributes become properties- for example if you set |
So we can't really safely detect, as some attributes throw when being set to. This means copious amounts of try/catch based detection. Which will be a debugging hazard i want to avoid. I think the whitelist is the right way. |
so, |
[edit: content to large to display reasonably] the true list of readOnly appears to be: https://gist.github.com/stefanpenner/a3cf3b3f49e429965cec this is far far to big to actually ship. So we have some options:
|
After some thought, although someone should sanity check me, I actually believe we just need to care about: var READ_ONLY_ATTR_BY_TAG = {
SELECT: ['form'],
OPTION: ['form'],
INPUT: ['form'],
TEXTAREA: ['form'],
BUTTON: ['form'],
LABEL: ['form'],
FIELDSET: ['form'],
LEGEND: ['form'],
OBJECT: ['form']
}; This is because, most of the documented readOnly properties, such as |
interesting discovery thanks to @jayphelps var form = document.createElement('form');
form.id = 'i-am-form';
var input = document.createElement('input');
input.form = 'i-am-form';
document.body.appendChild(form);
input.form === 'i-am-form' //=> false
document.body.appendChild(input);
input.form === 'i-am-form' //=> false but the following (with setAttribute) works. Please note, var form = document.createElement('form');
form.id = 'i-am-form';
var input = document.createElement('input');
input.setAttribute('form', 'i-am-form');
document.body.appendChild(form);
input.form === 'i-am-form' //=> false
document.body.appendChild(input);
input.form === 'i-am-form' //=> true |
Note that we might actually be be able to detect these instances in HTMLBars. Observe: Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'form')
/*
Object {
configurable: true
enumerable: true
get: () { [native code] }
set: undefined
}
*/ It isn't "readonly" (technically) is just doesn't have a setter, which makes it just effectively readonly. Hence why it does not error when you attempt to write to it. whether this is the same descriptor cross-browser, for all we support is a different story..... |
@jayphelps you are correct, but ES5 only. Also, it appears this attribute is the only one I have found so far. So we can likely just hard-code the solution. I am curious if we can find other ones. |
one work-around: tildeio/htmlbars#352 |
@jayphelps should we use the gOPD and detect the missing setter or.. |
@stefanpenner I'm working on testing a solution that uses it. @everyoneelse--getOwnPropertyDescriptor works IE8+ on DOM objects, so I'm running with that knowledge to test whether we can prevent a hardcoded list and instead detect "readonly" behavior of a given property. |
|
@stefanpenner 😝 not that simple, but close. Could have |
@jayphelps yes, but the question is, should setAttribute be used if other modes are active? |
quick list of attributes with https://gist.github.com/stefanpenner/575cfc90889cbab9d52b but still unable to find another attribute that requires this (beyond |
@stefanpenner |
@aFarkas Fixed in tildeio/htmlbars#363 |
Glimmer currently doesn't support binding the `form` attribute because of how it detects settable attributes vs properties. See emberjs/ember.js#11221
should be fixed in 1.13.3 due to tildeio/htmlbars#374 |
Please confirm, and we can close... |
When upgrading emberx-select I encountered an odd bug where using
attributeBindings
in a component to bind theform
attribute doesn't actually bind form as of 1.11+.I've provided two JSBins below. One is 1.10 where the binding works correctly and the other is 1.11+ where the binding doesn't work.
Also here is a failing test for emberx-select on ember 1.12.
1.10:
http://emberjs.jsbin.com/hejeqevosu/1/edit?html,js,output
1.11+:
http://emberjs.jsbin.com/fahiwurece/1/edit?html,js,output
I'm going to CC @stefanpenner since I reached out to him on twitter :P
The text was updated successfully, but these errors were encountered: