MDL version: 1.1.3
Browser: Internet Explorer
Browser version: 11
Operating system: Windows
Operating system version: 10
CodePen: http://codepen.io/anon/pen/ZWrKjX?fork=xGWgXa (use this in IE11 or Edge)
What steps will reproduce the problem:
What is the expected result?
MDL is initialized on page load "automatically" or by upgrading elements manually.
What happens instead of that?
The CSS is applied but components do not get upgraded. The debug console shows an error: "Object doesn't support this action"
I am using MDL 1.1.3 in an environment which uses a polyfill for CustomEvent. When I run my app with IE11 and using componentHandler.upgradeElement I'm getting the following error:
TypeError: Object doesn't support this action.
at upgradeElementInternal (Unknown script code:96:13)
I could track it down to this part of componentHandler:
if ('CustomEvent' in window && typeof window.CustomEvent === 'function') {
ev = new Event('mdl-componentupgraded', {
'bubbles': true, 'cancelable': false
});
}
The check for CustomEvent does not fail (basically a false positive) and the componentHandler tries to create an Event by calling the new Event(...) constructor which apparently isn't accessible with IE11. Doing a manual new Event('test', { bubbles: true }); leads to the exact same error mentioned above.
I have read in another issue that new Event() is used to stay compatible with IE10, so this may not be a bug but intentional.
Suggested fix: use CustomEvent to raise events on upgrading components instead of Event which is not usable in IE11/Edge.
@Thanood You could try to use another custom event polyfill. I use the WebModules custom event polyfill i my projects: https://github.com/webmodules/custom-event. Just make shure that the polyfill kicks in before material.js. I have not tested this on IE11 - but it could be a solution.
Thanks, @leifoolsen I have tried this now.
The polyfill also introduces a CustomEvent function on the global namespace. This is the reason why material.js check will be positive.
The actual problem is with using the Event constructor instead of the CustomEvent constructor. The Event constructor seems to be not usable in IE11.
For now I have overwritten componentHandler.upgradeElement to set window.CustomEvent to false (defined but not a function anymore so the test will fail) and set it back afterwards.
But apart from feeling abusive I guess this introduces negative effects on performance (maybe not much, I don't know).
Yes, I can see that. MDL does not even try to polyfill the custom event, which should have been performed at startup. The polyfill i mentioned actually fires an event as a part of the native check, so false positives should not be an issue. But again, that does not help much if the componentHandler misbehaves.
@Thanood
I have done some testing on IE11 (edge), using MDL with and without the CustomEvent() constructor polyfill provided by MDN here: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
Without the polyfill, I don't get any errors in console (IE11 edge). But if I add the MDN polyfill, the two methods in material.js (componentHandler.upgradeElementInternal and componentHandler.deconstructComponentInternal) that uses a "hard coded" custom event fails with the following error: "Object doesn't support this action".
As you mention, we can override componentHandler.upgradeElement - but hopefully the MDL team will fix this bug soon.
BTW: The MDL components I build relies on custom events, so hardcoding the custom event like it's done in MDL is not an option for me.
Thank you for testing and confirming this, @leifoolsen.
BTW: If you want the MDL team to respond to this issue, I think you must follow the "Code of Conduct" guidelines: https://github.com/google/material-design-lite/blob/master/CONTRIBUTING.md#submitting-an-issue
Thanks, I will edit my original post accordingly later.
Thanks! I need this bugfix too!
Post updated. :smile:
Thanks. Found an additional issue (or maybe it is intentional?). In componentHandler.deconstructComponentInternal the created custom event does not call element.dispatchEvent - so no event is actually fired.
I have looked at the corresponding code in v2-components-poc branch. The code in v1.1.3 is replaced with this:
var ev = document.createEvent('Events');
ev.initEvent('mdl-componentupgraded', true, true);
element.dispatchEvent(ev);
According to MDN createEvent should be avoided: "Many methods used with createEvent, such as initCustomEvent, are deprecated. Use event constructors instead.". See: https://developer.mozilla.org/en-US/docs/Web/API/Document/createEvent.
Code found in Google dialog-polyfill:
var supportCustomEvent = window.CustomEvent;
if (!supportCustomEvent || typeof supportCustomEvent == 'object') {
supportCustomEvent = function CustomEvent(event, x) {
x = x || {};
var ev = document.createEvent('CustomEvent');
ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
return ev;
};
supportCustomEvent.prototype = window.Event.prototype;
}
Why not use something similar to that?
I'm having a hard time finding something actionable here for us to do internally. As far as I can tell, nothing is incorrect with our code at all. It is instead a conflict with custom code you are executing that is interfering with our feature detection.
Without a clear way for us to detect if the Event constructor _can_ be called, I'm at a loss for what to do.
Any ideas on that one (without a try/catch)? We won't be implementing a polyfill for this internally as that may cause issues with other developers integrations.
Otherwise this seems to be a support issue which should be handled on StackOverflow or some other support forum.
See #4264
This code in mdlComponentHandler results in a false positive:
var ev;
if ('CustomEvent' in window && typeof window.CustomEvent === 'function') {
ev = new Event('mdl-componentupgraded', {
'bubbles': true, 'cancelable': false
});
} else {
ev = document.createEvent('Events');
ev.initEvent('mdl-componentupgraded', true, true);
}
element.dispatchEvent(ev);
So we are supposed to build the core to keep every poor polyfill on the internet from conflicting with what we do?
MDL has the incorrect code. This is correct: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
It isn't "incorrect" as we aren't carrying custom data (which is the point of CustomEvent). However, if changing to CustomEvent instead of Event for the constructor still upholds our full browser support without a polyfill then that change is acceptable.
PR #4348 is open to fix this, just needs lots of device testing.
Well, if the browser doesn't support CustomEventyou do nearly the same as the MDN polyfill but if it does support CustomEvent you don't have any problem at all because it's there anyway, right?
IE11 simply doesn't allow using the Event constructor directly so in a strict sense you could technically say that this isn't compatible, either. :smile:
IE11 without a polyfill doesn't have this problem for the sole fact that createEventis used in that case.
You have been faster, thank you! :+1:
I can help testing this on everything but Safari (if my co-worker still has a Windows phone).
The code from webcomponents.js should be correct. See: https://github.com/webcomponents/webcomponentsjs/blob/v0.7.12/CustomElements.js#L950
Also, IE11 will fail on new CustomEvent(...);, so instead of browser detection as done in webcomponents, one can use code similar to this:
try {
// Modern browsers
return new window.CustomEvent('myevent');
}
catch(e) {
// Polyfill IE11
}
try/catches can't be optimized by engines so we should avoid them internally at all costs.
I have what should be a workable patch in the PR. Waiting on IE VM's to download to confirm.
Thanks 馃憤
new CustomEvent instead.If that fails still, then there isn't anything else we can feasibly do about it internally.