Выберите() поле ввода с помощью Knockout.js

Я новичок в Knockout.js.

Каков наилучший способ select() a <input />, когда он станет видимым?

Вид:

<p>
    Name: 
    <b data-bind="visible: !editing(), text: name, click: edit">&nbsp;</b>
    <input data-bind="visible: editing, value: name, hasfocus: editing" />
</p>

ViewModel:

function PersonViewModel(name) {
    // Data
    this.name = ko.observable(name);
    this.editing = ko.observable(false);

    // Behaviors
    this.edit = function() { this.editing(true) }
}

ko.applyBindings(new PersonViewModel("Bert Bertington"));

http://knockoutjs.com/documentation/hasfocus-binding.html

http://jsfiddle.net/RnCUd/

Спасибо!

Ответ 1

Вы можете создать новое привязку для выбора дескриптора.

ko.bindingHandlers.selected = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var selected = ko.utils.unwrapObservable(valueAccessor());
        if (selected) element.select();
    }
};

Добавьте это связывание в свое поле ввода.

<input data-bind="visible: editing, value: name, hasfocus: editing, selected: editing" />

Вот скрипка: http://jsfiddle.net/RnCUd/2/


В качестве альтернативы вы можете создать пользовательскую привязку, которая привязывает привязку hasfocus:

ko.bindingHandlers.hasSelectedFocus = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ko.bindingHandlers['hasfocus'].init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    },        
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ko.bindingHandlers['hasfocus'].update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);        

        var selected = ko.utils.unwrapObservable(valueAccessor());
        if (selected) element.select();
    }
};

Это связывание просто делегирует инициализацию и обновление до hasfocus и заботится о выборе элемента, если наблюдаемое является истинным. Используйте его вместо hasfocus.

<input data-bind="visible: editing, value: name, hasSelectedFocus: editing" />

Вот скрипка: http://jsfiddle.net/RnCUd/1/

Ответ 2

Я попытался использовать стандартную привязку John Earles выше (спасибо John!) вместе с текстовым полем, которое также использовало привязку valueUpdate: "afterkeydown" и выяснило, что это действительно не работает должным образом. (Я предполагаю, что это связано с тем, что все привязки загораются снова, когда нужно связать одну из привязок, а valueUpdate скорее всего вызывает привязку значения к огню после каждого символа).

После нескольких попыток я сделал полуфикс для этой проблемы, которая, похоже, работает хорошо для меня. Основная идея заключается в том, что перед тем, как мы запустим привязку hasfocus, мы проверяем, имеет ли данный элемент внимание фокус, и мы фактически выбираем текст, когда элемент фактически не имел фокуса до того, как сработала привязка hasfocus.

Я использовал jquery для проверки фокуса, но вы, вероятно, могли бы сделать это и другим способом.

ko.bindingHandlers.hasSelectedFocus = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ko.bindingHandlers['hasfocus'].init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var focusBefore = $(element).is(':focus');
        ko.bindingHandlers['hasfocus'].update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);

        var selected = ko.utils.unwrapObservable(valueAccessor());
        if (selected && !focusBefore) {
            element.select();   
        }
    }
};

Изменить: я заметил, что такая привязка может работать не так, как вы хотите, если она используется на устройстве iOS. Нет ничего плохого в привязке как таковой, но логика автофокусировки и выбора приводит к тому, что клавиатура устройств появляется, как только будет выполняться связывание, которое может или не может быть именно тем, что вы хотите совершить на таком устройстве. Чтобы сравнить, на устройствах Android, которые я использую для тестирования, я не получаю автоматически клавиатуру, как только это связывание выполняется. Для меня в итоге я создал еще одну привязку, чтобы ничего не делать на устройствах iOS следующим образом.

ko.bindingHandlers.hasNonIosSelectedFocus = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        if (navigator.userAgent.match(/iPad/i) == null && navigator.platform.indexOf("iPhone") == -1 && navigator.platform.indexOf("iPod") == -1) {
            ko.bindingHandlers['hasSelectedFocus'].init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
        }
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        if (navigator.userAgent.match(/iPad/i) == null && navigator.platform.indexOf("iPhone") == -1 && navigator.platform.indexOf("iPod") == -1) {
            ko.bindingHandlers['hasSelectedFocus'].update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
        }
    }
};

Тл; дг:

Если вы используете это и хотите обслуживать планшеты/смартфоны, убедитесь, что это логика взаимодействия, которую вы действительно ожидаете.