Страницы

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

Показаны сообщения с ярлыком focus. Показать все сообщения
Показаны сообщения с ярлыком focus. Показать все сообщения

пятница, 24 января 2020 г.

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

#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(); }); }); }

воскресенье, 15 декабря 2019 г.

Как в Android создать набор полей с автопереходом между ними?

#java #android #android_edittext #focus


Как в Android (2.3+) cоздать список полей, например, для ввода IP-адреса
... ? Причем, чтобы пользователь активировал поле и просто набивал
цифры, например 010001225001 -> 10.001.225.001.
Если делать строковое поле  ввода, то в нем не получается  автоматический перескок
через точки.  Начальное содержимое строкового поля не сохраняется, так что подсказка
вида xxx.xxx.xxx.xxx будет стерта вводом и все. 
Если делать набор полей с цифрами - то по активации первого поля (010) оно так и
остается активированным и для перехода во второе поле (001) надо еще раз кликать на
следующее поле (фокус остается на первом поле, а надо бы, чтобы он перескочил на второе
поле).    


Ответы

Ответ 1



Мне кажется, что Вам нужно создать список Ваших EditText. Затем на каждый EditText повесить по TextWatcher'у и при достижении в каждом из них 3-х цифр переводить фокус на следующий EditText. Так, моя догадка была верна. Вот Вам работающий код. Извините, написан чуть некрасиво, но я проверил - всё работает так, как Вы описали в вопросе. Это самый простой xml с 4-мя EditText. А это уже само Activity, в котором происходит нужная работа. package com.blogspot.leved_notes.answerhashcode; import java.util.ArrayList; import android.os.Bundle; import android.app.Activity; import android.text.Editable; import android.text.TextWatcher; import android.widget.EditText; public class MainActivity extends Activity implements TextWatcher { int current; ArrayList array; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); current = 0; array = new ArrayList(4); EditText edit1 = (EditText) findViewById(R.id.editText1); EditText edit2 = (EditText) findViewById(R.id.editText2); EditText edit3 = (EditText) findViewById(R.id.editText3); EditText edit4 = (EditText) findViewById(R.id.editText4); edit1.addTextChangedListener(this); edit2.addTextChangedListener(this); edit3.addTextChangedListener(this); edit4.addTextChangedListener(this); array.add(0, edit1); array.add(1, edit2); array.add(2, edit3); array.add(3, edit4); } @Override public void afterTextChanged(Editable s) { if (s.length() == 3) { current++; if (current < 4) { array.get(current).requestFocus(); } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } }

Ответ 2



На stackoverlow.com есть множество ответов на этот вопрос. Наиболее простой (но с низким рейтингом):

Ответ 3



Задача аналогична форматированию номера телефона. Можно подписаться на TextChangedListener и модифицировать поле ввода. Здесь можно прочитать подробнее. Также для красоты можно переопределить поведение подсказки edittext, чтобы при вводе символов было видно серым текстом формат.

вторник, 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(); }); }); }

среда, 24 октября 2018 г.

Как в Android создать набор полей с автопереходом между ними?

Как в Android (2.3+) cоздать список полей, например, для ввода IP-адреса ... ? Причем, чтобы пользователь активировал поле и просто набивал цифры, например 010001225001 -> 10.001.225.001. Если делать строковое поле ввода, то в нем не получается автоматический перескок через точки. Начальное содержимое строкового поля не сохраняется, так что подсказка вида xxx.xxx.xxx.xxx будет стерта вводом и все. Если делать набор полей с цифрами - то по активации первого поля (010) оно так и остается активированным и для перехода во второе поле (001) надо еще раз кликать на следующее поле (фокус остается на первом поле, а надо бы, чтобы он перескочил на второе поле).


Ответ

Мне кажется, что Вам нужно создать список Ваших EditText. Затем на каждый EditText повесить по TextWatcher'у и при достижении в каждом из них 3-х цифр переводить фокус на следующий EditText. Так, моя догадка была верна. Вот Вам работающий код. Извините, написан чуть некрасиво, но я проверил - всё работает так, как Вы описали в вопросе. Это самый простой xml с 4-мя EditText.




А это уже само Activity, в котором происходит нужная работа. package com.blogspot.leved_notes.answerhashcode;
import java.util.ArrayList;
import android.os.Bundle; import android.app.Activity; import android.text.Editable; import android.text.TextWatcher; import android.widget.EditText;
public class MainActivity extends Activity implements TextWatcher {
int current; ArrayList array;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
current = 0; array = new ArrayList(4);
EditText edit1 = (EditText) findViewById(R.id.editText1); EditText edit2 = (EditText) findViewById(R.id.editText2); EditText edit3 = (EditText) findViewById(R.id.editText3); EditText edit4 = (EditText) findViewById(R.id.editText4);
edit1.addTextChangedListener(this); edit2.addTextChangedListener(this); edit3.addTextChangedListener(this); edit4.addTextChangedListener(this);
array.add(0, edit1); array.add(1, edit2); array.add(2, edit3); array.add(3, edit4); }
@Override public void afterTextChanged(Editable s) { if (s.length() == 3) { current++; if (current < 4) { array.get(current).requestFocus(); } } }
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
}