#jquery #angularjs #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 объектов.
Ответы
Ответ 1
Так как рабочего примера нет, можно рассуждать только теоретически:
Так как шаблон не меняется, его не нужно подгружать не только на каждый фокус, но
и на каждый 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();
});
});
}