Страницы

Поиск по вопросам

вторник, 19 марта 2019 г.

Как в обработчике blur дождаться окончания обработки в focus

Возникла проблема с созданием datepicker для поля даты. На поле висит 2 обработчика - blur и focus, в focus создается datepicker, в blur он удаляется. Причем в focus он создается с помощью deferred объекта.
.directive('datePicker', [ '$compile', '$document', 'datePickerService', '$templateRequest', function ($compile, $document, datePickerService, $templateRequest) { function link(scope, element, attrs) { var picker = null; var $elementFocusProcessing = $.Deferred(); element.on('focus', function (event) { populatelimits(); prepareViewData(); var pos = angular.extend(element.offset(), { height: element[0].offsetHeight });
$templateRequest(datePickerService.datePickerTemplate).then(function (html) { var template = angular.element(html); $document.find('body').append(template); picker = $compile(template)(scope); picker.css({ top: pos.top + pos.height + 5, left: pos.left, display: 'block', position: 'absolute' });
picker.on('mousedown', function (evt) { evt.preventDefault(); }); $elementFocusProcessing.resolve(); }); });
element.on('blur', function () { $elementFocusProcessing.then(function () { if (picker) { picker.remove(); picker = null; }; $elementFocusProcessing = $.Deferred(); }); }); }
return { restrict: 'A', link: link, scope : { model: '=ngModel' } };
И собственно проблема: если выделить поле даты, потом переключиться на другое окно, а затем кликнуть на любое место страницы, кроме поля даты, возникают подряд несколько событий: focus поля, blur поля, click по странице. При этом создание picker в focus завершается позже, чем попытка его удаления в blur, и он не удаляется, хотя фокус элемента в тоге оказывается потерян. Как сделать так, чтобы выполнение кода в blur происходило только после завершения выполнения кода в focus? Мне пока пришло в голову только сделать дополнительную переменную focusEnded для определения того, идет ли выполнение кода в focus, а в blur организовать цикл с таймаутом, но чувствую, что можно более изящно сделать это с использованием deferred объектов.


Ответ

Так как рабочего примера нет, можно рассуждать только теоретически:
Так как шаблон не меняется, его не нужно подгружать не только на каждый фокус, но и на каждый link. Следовательно, его можно вынести из функции и результат, а он является promise, сохранить в переменной:
var templatePromise = $templateRequest(datePickerService.datePickerTemplate); Далее, функция link, внутри нее подразумеваем, что шаблон уже подгрузился, для этого все остальное делаем в обработчике success функции then у нашего сохраненного templatePromise
function link(scope,element,attrs){ templatePromise.then(function(html){ //достаточно сделать всего один элемент, // который мы будем добавлять или удалять var template = angular.element(html);
//и добавим событие, чтобы не добавлять его каждый раз //так как template это уже объект jqLite можно сделать так template.on('mousedown', function (evt) { evt.preventDefault(); } );
//добавляем on focus element.on('focus', function (event) { ... $document.find('body').append(template); $compile(template)(scope); //так как template это объект jqLite, то вместо picker можно использовать его template.css(...) ... });
//добавляем on blur element.on('blur', function () { //так как добавляли template, то и удалять можно его //а так как он у нас всегда есть, то не надо проверять на null template.remove(); }); }); }

Комментариев нет:

Отправить комментарий