2012-12-10 3 views
2

У меня есть флажок, который ранее был привязан непосредственно к наблюдаемому свойству в моей модели представления. Я использую общий грязный флаг во всех моделях просмотра, который отслеживает все наблюдаемые свойства в модели представления для изменений.Knockout.js записываемый вычисляемый логический наблюдаемый привязан к флажку - недопустимая настройка свойства

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

function VM() { 
    var self = this; 

    self.SelectedInternal = ko.observable(false); 

    self.selected= ko.computed({ 
     read: function() { 
      return self.SelectedInternal(); 
     }, 
     write: function (value) { 
      alert('Clicked'); // To demonstrate problem 
      if (value === false) { 
       if (confirm('Are you sure you wish to deselect this option?')) { 
        self.SelectedInternal(value); 
       }   
      } 
     } 
    }); 
} 

var vm = new VM(); 

ko.applyBindings(vm); 

Что я вижу (как в Firefox и IE) является то, что, когда я по умолчанию наблюдаемого значения SelectedInternal к ложному, как описан выше , то «выбранная» функция записи срабатывает только каждый раз, когда я устанавливаю флажок, а не когда снимаю его. Если я по умолчанию значение SelectedInternal для наблюдаемого значения равно true, то при первом отключении его выполняется установка записи, но не последующие отмены.

Вот скрипку, чтобы продемонстрировать:

http://jsfiddle.net/xHqsZ/18/

Что здесь происходит? Есть ли лучший способ достичь этого?

UPDATE: Этот подход, вероятно, не сработает, потому что я не могу получить крючок в исходный щелчок, чтобы вернуть значение false, и сбросить наблюдаемое на true, если пользователь выбрал Отменить в поле подтверждения. t, похоже, вступает в силу. Но мне все же хотелось бы знать, почему сам вычислительный сеттер не ведет себя так, как ожидалось.

ответ

1

Взгляните на документацию по адресу http://knockoutjs.com/documentation/computedObservables.html.

Функция записи вызывается, когда значение из функции чтения изменяется. См. Пример №1 в документации.

Одна вещь, которую я сделал в функции записи, - это установить другие наблюдаемые значения. Например, один флажок для удаления всех остальных в группе. Я сделал это, просто обновив эти наблюдаемые в функции записи.


Редактировать

Я собрал скрипку, показывающий, как сделать то, что описано в последнем абзаце - http://jsfiddle.net/photo_tom/xHqsZ/22/. Рассчитанная функция, которая позволяет работать в

self.clearAll = ko.computed({ 
    read: function() { 
     return !(self.option1() || self.option2() || self.option3()); 
    }, 
    write: function(value) { 
     alert('Clicked'); 
     self.option1(false); 
     self.option2(false); 
     self.option3(false); 

    } 
}); 

Edit # 2 Чтобы ответить на комментарий о желании вручную подтвердить ложь истина проверяется состояние вопроса.

Самый чистый способ справиться с этим с помощью специального связующего. Ключевой раздел - это регистрация настраиваемого обработчика событий. Внутри этой функции вы можете спросить, действительно ли пользователь хочет установить флажок в true.

ko.bindingHandlers.checkConfirm = { 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 

     //handle the field changing 
     ko.utils.registerEventHandler(element, "change", function() { 
      // get the current observable value. 
      var value = valueAccessor(); 
      var valueUnwrapped = ko.utils.unwrapObservable(value); 

      if (!valueUnwrapped && element.checked) { 
       var r = confirm("Confirm Setting value to true"); 
       if (r) { 
        value(true); 
        return; 
       } else { 
        // not okayed, so clear cb. 
        element.checked = false; 
       } 
      } 
      value(false); 
     }); 
    }, 
    update: function(element, valueAccessor) { 
     // use default ko code to update checkbox 
     ko.bindingHandlers.checked.update(element, valueAccessor); 
    } 
}; 

Обновлено скрипку в http://jsfiddle.net/photo_tom/xHqsZ/32/

+0

Спасибо, но не могли бы вы раскошелиться на эту скрипку, чтобы продемонстрировать, как вы могли бы получить подтверждение с помощью этой техники? Я экспериментировал с отдельным связыванием кликов, а также с проверенным связыванием, но я еще не смог его исправить. –

+0

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

+0

См. Мой ответ. Я открыт для чего-нибудь приятного :-) –

2

Я до сих пор достигнуто это таким образом (свойства переименованы для простоты):

<input type="checkbox" data-bind="checked: vm.optionComputed, click: vm.toggleOption" /> 

А в модели представления:

self.optionComputed = ko.computed({ 
    read: function() { 
     return self.Option(); 
    }, 
    write: function (value) { 
    } 
}); 

self.toggleOption = function (vm, event) { 
    var checkBox = $(event.target); 
    var isChecked = checkBox.is(':checked'); 

    if (!(!isChecked && !confirm('Are you sure?'))) { 
     self.Option(isChecked); 
    }  
}; 

Есть небольшая смута, когда вы выбираете OK для отмены выбора, флажок (который имеет al готовый был заглушен щелчком), кратковременно появляется снова, прежде чем окончательно снять флажок. Но поведение в плане предотвращения наблюдаемого изменения до подтверждения правильное.

+0

Это один из подходов. Это ситуация, когда пользовательская привязка будет работать лучше. У меня есть частично рабочий ответ: http://jsfiddle.net/photo_tom/xHqsZ/31/. Мне нужно потратить немного больше времени на это, я должен уехать на свою дневную работу. Сегодня у меня будет рабочий образец для вас. –

0

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

$(document).ready(function() { 
    function VM() { 
     var self = this; 
     self.items = ko.observableArray([ 
      { name: "Foo", active: ko.observable(true) }, 
      { name: "Bar", active: ko.observable(true) }, 
      { name: "Bas", active: ko.observable(true) } 
     ]); 
     self.allActive = ko.observable(true); 
     self.allActive.subscribe(function(value) { 
      if(self.allActiveCanceled) { 
       self.allActiveCanceled = false; 
       return; 
      } 
      if(!confirm('Really?')) { 
       window.setTimeout(function() { 
        self.allActiveCanceled = true; 
        self.allActive(!value); 
       }, 1); 
       return; 
      } 
      var items = self.items(); 
      for(var i = 0, l = items.length; i < l; i++) { 
       items[i].active(value); 
      } 
     }); 
     self.allActiveCanceled = false; 
    } 
    var vm = new VM(); 
    ko.applyBindings(vm); 
}); 

Вот скрипка с соответствующей разметкой: http://jsfiddle.net/makeblake/dWNLA/

SetTimeout и отменен флаг чувствует себя немного рубить, но он получает работу.

0

Я также хотел бы предложить использовать связывание пользовательского нокаута, но убедитесь, что повторное использование/унаследует полную функциональность ko.bindingHandlers.checked связывания, чтобы получить прибыль от его обработки совместимости унаследованной браузера:

ko.bindingHandlers.confirmedChecked = { 
    'after': ['value', 'attr'], 
    'init': function (element, valueAccessor, allBindings) 
    { 
     ko.utils.registerEventHandler(
     element, 
     'click', 
     function(event) 
     { 
      if (
       element.checked && 
       !confirm('Are you sure you want to enable this setting?') 
      ) 
      { 
       if (event.stopImmediatePropagation) 
       { 
        event.stopImmediatePropagation(); 
       } 

       element.checked = false; 
      } 
     } 
    ); 

    ko.bindingHandlers.checked.init(element, valueAccessor, allBindings); 
    } 
};