Open subashdbc opened 5 years ago
Any quick fix on this?
How to fix this error?
The same here!! :( This problem happens only in Chrome, Edge works fine.
It´s a race condition
https://bugs.chromium.org/p/chromium/issues/detail?id=941910
The workaround is a setTimeout on root focus.
Exactly. Either throttle / debounce (see pickadate 3.6.1) or use the setTimeout workaround.
@Marzon We use materialize.js and where to use setTimeout?
I am also looking for workaround for time picker cause upgrading to new materialcss is time consuming. Please let us know workaround for time picker
For datepicker
comment this code in materialize.js file
P.close(target === P.$root.children()[0]);
It´s a race condition
https://bugs.chromium.org/p/chromium/issues/detail?id=941910
The workaround is a setTimeout on root focus.
Can please specify where to add setTimeout in the JS file. That would be really helpful
See https://github.com/amsul/pickadate.js/pull/1140 with the right workaround.
The other proposed change breaks focus (a11y).
@DanielRuf it's quite hard to find the places to change the logic based on github.com/amsul/pickadate.js/pull/1140/files these changes, on materialize.js file. It would much be appreciated any solution on materialize.js
Hi! On materialize.js, add a setTimeout (100 ms) in end of the
open: function (dontGiveFocus) {
Move de $document.on('click.' . .... and the
P.$root.eq(0).focus();
to the setTimeOut function.
Leave document.on first and $root.focus() after document.on ..
I´m waiting the race condition bug to be fixed.. before to propose a PR..
Hi, Not sure, if this is a bulletproof solution but this works for me especially with clockpicker. The version should be materializecss (v0.100.2). In materialize.js file Line No: 8913
ClockPicker.prototype.show = function (e) {
Just wrap setTimeout( 200 ms) inside this whole function, works well.
Hi, Not sure, if this is a bulletproof solution but this works for me especially with clockpicker. The version should be materializecss (v0.100.2). In materialize.js file Line No: 8913
ClockPicker.prototype.show = function (e) {
Just wrap setTimeout( 100 ms) inside this whole function, works well.
Now it works fine `
ClockPicker.prototype.show = function (e) { var _this = this;
setTimeout(function () { // Not show again if (_this.isShown) { return; }
raiseCallback(_this.options.beforeShow);
$(':input').each(function () {
$(this).attr('tabindex', -1);
});
var self = _this; // Initialize
_this.input.blur();
_this.popover.addClass('picker--opened');
_this.input.addClass('picker__input picker__input--active');
$(document.body).css('overflow', 'hidden'); // Get the time
var value = ((_this.input.prop('value') || _this.options['default'] || '') + '').split(':');
if (_this.options.twelvehour && !(typeof value[1] === 'undefined')) {
if (value[1].indexOf("AM") > 0) {
_this.amOrPm = 'AM';
} else {
_this.amOrPm = 'PM';
}
value[1] = value[1].replace("AM", "").replace("PM", "");
}
if (value[0] === 'now') {
var now = new Date(+new Date() + _this.options.fromnow);
value = [now.getHours(), now.getMinutes()];
if (_this.options.twelvehour) {
_this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM';
}
}
_this.hours = +value[0] || 0;
_this.minutes = +value[1] || 0;
_this.spanHours.html(_this.hours);
_this.spanMinutes.html(leadingZero(_this.minutes));
if (!_this.isAppended) {
// Append popover to input by default
var containerEl = document.querySelector(_this.options.container);
if (_this.options.container && containerEl) {
containerEl.appendChild(_this.popover[0]);
} else {
_this.popover.insertAfter(_this.input);
}
if (_this.options.twelvehour) {
if (_this.amOrPm === 'PM') {
_this.spanAmPm.children('#click-pm').addClass("text-primary");
_this.spanAmPm.children('#click-am').removeClass("text-primary");
} else {
_this.spanAmPm.children('#click-am').addClass("text-primary");
_this.spanAmPm.children('#click-pm').removeClass("text-primary");
}
} // Reset position when resize
$win.on('resize.clockpicker' + _this.id, function () {
if (self.isShown) {
self.locate();
}
});
_this.isAppended = true;
} // Toggle to hours view
_this.toggleView('hours'); // Set position
_this.locate();
_this.isShown = true; // Hide when clicking or tabbing on any element except the clock and input
$doc.on('click.clockpicker.' + _this.id + ' focusin.clockpicker.' + _this.id, function (e) {
var target = $(e.target);
if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0) {
self.hide();
}
}); // Hide when ESC is pressed
$doc.on('keyup.clockpicker.' + _this.id, function (e) {
if (e.keyCode === 27) {
self.hide();
}
});
raiseCallback(_this.options.afterShow);
}, 200); };
`
@DavinderPRO This is what I mean, does this work for you?
// Show popover
ClockPicker.prototype.show = function (e) {
setTimeout(() => {
// Not show again
if (this.isShown) {
return;
}
raiseCallback(this.options.beforeShow);
$(':input').each(function () {
$(this).attr('tabindex', -1);
});
var self = this;
// Initialize
this.input.blur();
this.popover.addClass('picker--opened');
this.input.addClass('picker__input picker__input--active');
$(document.body).css('overflow', 'hidden');
// Get the time
var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':');
if (this.options.twelvehour && !(typeof value[1] === 'undefined')) {
if (value[1].indexOf("AM") > 0) {
this.amOrPm = 'AM';
} else {
this.amOrPm = 'PM';
}
value[1] = value[1].replace("AM", "").replace("PM", "");
}
if (value[0] === 'now') {
var now = new Date(+new Date() + this.options.fromnow);
value = [now.getHours(), now.getMinutes()];
if (this.options.twelvehour) {
this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM';
}
}
this.hours = +value[0] || 0;
this.minutes = +value[1] || 0;
this.spanHours.html(this.hours);
this.spanMinutes.html(leadingZero(this.minutes));
if (!this.isAppended) {
// Append popover to input by default
var containerEl = document.querySelector(this.options.container);
if (this.options.container && containerEl) {
containerEl.appendChild(this.popover[0]);
} else {
this.popover.insertAfter(this.input);
}
if (this.options.twelvehour) {
if (this.amOrPm === 'PM') {
this.spanAmPm.children('#click-pm').addClass("text-primary");
this.spanAmPm.children('#click-am').removeClass("text-primary");
} else {
this.spanAmPm.children('#click-am').addClass("text-primary");
this.spanAmPm.children('#click-pm').removeClass("text-primary");
}
}
// Reset position when resize
$win.on('resize.clockpicker' + this.id, function () {
if (self.isShown) {
self.locate();
}
});
this.isAppended = true;
}
// Toggle to hours view
this.toggleView('hours');
// Set position
this.locate();
this.isShown = true;
// Hide when clicking or tabbing on any element except the clock and input
$doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function (e) {
var target = $(e.target);
if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0) {
self.hide();
}
});
// Hide when ESC is pressed
$doc.on('keyup.clockpicker.' + this.id, function (e) {
if (e.keyCode === 27) {
self.hide();
}
});
raiseCallback(this.options.afterShow);
}, 200);
};
To fix the date picker change the code from:
// Only bind keydown events if the element isn’t editable.
if (!SETTINGS.editable) {
$ELEMENT.
// On focus/click, focus onto the root to open it up.
on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
event.preventDefault();
P.$root.eq(0).focus();
}).
// Handle keyboard event based on the picker being opened or not.
on('keydown.' + STATE.id, handleKeydownEvent);
}
to:
// Only bind keydown events if the element isn’t editable.
if (!SETTINGS.editable) {
$ELEMENT.
// On focus/click, focus onto the root to open it up.
on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
setTimeout(function(){
event.preventDefault();
P.$root.eq(0).focus();
}, 100);
}).
// Handle keyboard event based on the picker being opened or not.
on('keydown.' + STATE.id, handleKeydownEvent);
}
+1
+1
@markonose Are you sure that event.preventDefault();
works as intended in a setTimout()
?
I suspect you only want the .focus()
call delayed.
@ray007 You are indeed correct, but at least in my case the event.preventDefault();
does nothing.
// On focus/click, focus onto the root to open it up.
on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
event.preventDefault();
setTimeout(function(){
P.$root.eq(0).focus();
}, 100);
}).
would work more like the original code intended
If anyone stumbles uppon this thread here's how to fix the problem for the select dropdown
$newSelect.on({
'focus': function () {
var _this = this;
setTimeout(function () {
if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
$('input.select-dropdown').trigger('close');
$(window).off('click.select');
}
if (!options.is(':visible')) {
$(_this).trigger('open', ['focus']);
var label = $(_this).val();
if (multiple && label.indexOf(',') >= 0) {
label = label.split(',')[0];
}
var selectedOption = options.find('li').filter(function () {
return $(_this).text().toLowerCase() === label.toLowerCase();
})[0];
activateOption(options, selectedOption, true);
$(window).off('click.select').on('click.select', function () {
multiple && (optionsHover || $newSelect.trigger('close'));
$(window).off('click.select');
});
}
}, 75);
},
'click': function (e) {
e.stopPropagation();
}
});
1.0.0 does not have this problem so if you are able to upgrade, I would recommend that route. However if you can't, try one of the fixes in this thread. Potentially we may add a fix for this if chrome doesn't revert this behavior.
@Dogfalo do you know what was the change introduced in Chrome that produces this behaviour?
I think it has to do with the timing of events when clicking an input. Where before it was click -> focus, it seems to now be focus -> click. This is just a guess as I haven't looked deeply into the issue yet.
If anyone stumbles uppon this thread here's how to fix the problem for the select dropdown
$newSelect.on({ 'focus': function () { var _this = this; setTimeout(function () { if ($('ul.select-dropdown').not(options[0]).is(':visible')) { $('input.select-dropdown').trigger('close'); $(window).off('click.select'); } if (!options.is(':visible')) { $(_this).trigger('open', ['focus']); var label = $(_this).val(); if (multiple && label.indexOf(',') >= 0) { label = label.split(',')[0]; } var selectedOption = options.find('li').filter(function () { return $(_this).text().toLowerCase() === label.toLowerCase(); })[0]; activateOption(options, selectedOption, true); $(window).off('click.select').on('click.select', function () { multiple && (optionsHover || $newSelect.trigger('close')); $(window).off('click.select'); }); } }, 75); }, 'click': function (e) { e.stopPropagation(); } });
Above fix was not showing the already selected item from drop-down hence i modified it little bit. below is changed code.
$newSelect.on({ 'focus': function () {
if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
$('input.select-dropdown').trigger('close');
}
if (!options.is(':visible')) {
setTimeout(function () {
$(this).trigger('open', ['focus']);
}, 70);
var label = $(this).val();
var selectedOption = options.find('li').filter(function () {
return $(this).text().toLowerCase() === label.toLowerCase();
})[0];
activateOption(options, selectedOption);
}
},
'click': function (e) {
e.stopPropagation();
},
@Dogfalo Version 74 of Chrome is released and they didn't fix this, reading the comment 23 in https://bugs.chromium.org/p/chromium/issues/detail?id=941910#c6 it doesn't seem they are going to fix it, couldn't you please just fix it in materializecss?
@Dogfalo Version 74 of Chrome is released and they didn't fix this, reading the comment 23 in bugs.chromium.org/p/chromium/issues/detail?id=941910#c6 it doesn't seem they are going to fix it, couldn't you please just fix it in materializecss?
Well it will not fix old releases as 0.x is not actively developed anymore but 1.x. Also this is opensource so anyone can provide a PR to fix this. We had to do another workaround as the timeout / debouncing did not completely fix this bug in Chrome.
I thought this may help some who stumbled on this page. I am using angular2-materialize and my materialize select input sometimes closes immediately after opening.
I solved this by adding a click listener on a div
that wraps the select
tag, with nothing but event.stopPropagation()
in the listener. This fixed the issue for me.
For anyone who is too lazy to edit the file yourself
@LemuelHui
Awesome =)
Is there also a minified patched version? If you need help with that, just let me know.
PS: the timeout does not really fix that (longpress click).
You can check how we have fixed it in pickadate.js.
@DanielRuf could you provide a link to the commit with the fix that you did for pickadate?
@Sebastriani see https://github.com/amsul/pickadate.js/commit/31789ebf7fb9c832f0e8e06003654e20ab91c63d
My initial approach using timers (with setTimeout) did not work in all but many cases as it was added at the top of the counter stack of the VM.
The quick fix in the original codepen example (https://codepen.io/anon/pen/evQxPy) in this issue would be a code snippet like this:
document.getElementById('birthdate').addEventListener('pointerdown', (e)=>{e.target.setPointerCapture(e.pointerId);})
I was going to send a pull request to fix this issue, but I'm having some trouble with this repo and understanding how I should get a local example with un-built files to work. I can see from the documentations that we should not modify materialize.js directly. But I'm not able to produce a local example similar to the codepen example that includes the unbuilt files to verify the fix locally before sending the pull request. Can someone guide me here on what files from js/ directory I should include + the html/css in the code pen to reproduce the issue locally? Alternatively if you could just attach a html file that include the local files from this repo and reproduce the issue and I can work on the fix.
Hi,
When we click on the filed the clock modal opens and immediately close https://codepen.io/anon/pen/evQxPy This happens after I have updated my chrome version to 73