Knockout.js - как мне настроить пользовательские привязки
У меня есть пользовательская привязка для обработки автозаполнения, и когда пользователь выбирает элемент из автозаполнения, я общаюсь с сервером и заменяю текстовое поле сокращенным именем. Проблема в том, что это вызывает функцию "обновления" моей пользовательской привязки во второй раз.
Код Knockout.js (правка: Обратите внимание, что ниже приведен код CoffeeScript):
ko.bindingHandlers.ko_autocomplete =
init: (element, params) ->
$(element).autocomplete(params())
update: (element, valueAccessor, allBindingsAccessor, viewModel) ->
unless task.name() == undefined
$.ajax "/tasks/name",
data: "name=" + task.name(),
success: (data,textStatus, jqXHR) ->
task.name(data.short_name)
Task = ->
@name = ko.observable()
@name_select = (event, ui) ->
task.name(ui.item.name)
false
task = Task.new()
Посмотреть
= f.text_field :name, "data-bind" => "value: name, ko_autocomplete: { source: '/autocomplete/tasks', select: name_select }"
Есть ли способ применить дроссель к пользовательской привязке?
Я просто хочу, чтобы функция обновления пользовательских привязок не запускалась во второй раз, когда я задаю для task.name короткое имя, возвращаемое с сервера.
2 ответа
В общем, я нашел такой шаблон, чтобы работать на меня
ko.bindingHandlers.gsExample =
update: (element, valueAccessor, allBindingsAccessor, viewModel) ->
args = valueAccessor()
# Process args here, turn them into local variables
# eg.
span = args['span'] || 10
render = ko.computed ->
# Put your code in here that you want to throttle
# Get variables from things that change very rapidly here
# Note: You can access variables such as span in here (yay: Closures)
some_changing_value = some_observable()
$(element).html(some_changing_value)
# Now, throttle the computed section (I used 0.5 seconds here)
render.extend throttle : 500
# Cause an immediate execution of that section, also establish a dependancy so
# this outer code is re-executed when render is computed.
render()
Если вы не хотите нарушать изоляцию, вы можете использовать параметры задержки автозаполнения и выбрать событие, отбрасывая функцию обновления.
Измените ваш init следующим образом:
var options = $.extend(params(), {
select: function(ev, ui) {
var name = ui.item ? ui.item.short_name : this.value
task.name(name);
}
})
$(element).autocomplete(options)
Ваше обновление вызывается во второй раз, потому что (для упрощения) обновление само по себе вычисляется. Таким образом, он подписывается на все наблюдаемые доступы внутри него. В этой строке unless task.name() == undefined
вы подписываетесь на обновление task.name()
, Затем, когда вы обновите свой наблюдаемый с task.name(data.short_name)
при успешном выполнении ajax-запроса, обновление получает уведомление и пересчитывается.