2013-04-25 68 views
0

無論如何要添加一個「全局」自定義綁定?例如,我想綁定每個綁定的元素,而不必將綁定添加到data-bind屬性。把它看作是在數據綁定過程中某個時候觸發的初始化器。自動附加到每個綁定元素的自定義綁定?

我真正想要做的是:當一個新模型被添加到observableArray,我想自動專注於新模型的第一個input,以便用戶可以立即開始輸入。我不認爲這會適用於任何現有的綁定。

ko.bindingHandlers.attach = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     valueAccessor().boundElements.push(element); 
    } 
}; 

這可行,但我寧願不必在每個綁定元素上做data-bind="attach: $data"。有沒有什麼辦法可以告訴KO在元素上存在另一個綁定時總是使用attach綁定。

注意:寫完這個之後,我想我已經決定採用手動方法,但是我仍然想知道這是否可行。

回答

1

這個答案是明確如何集中視圖的第一input當增加一個新的模式,因爲這種技術,我建議因爲這樣做與你的完全不同。

我在最近的一個項目中有同樣的要求,基本上通過在我的視圖模型中包含一個名爲firstHasFocus的可觀察項來解決它。無論何時該視圖模型要變爲活動狀態,例如切換「標籤」時,我會將firstHasFocus設置爲true。在該視圖中,第一個input綁定到使用hasfocus的可觀察值。

下面是我的代碼中的一個示例,它響應嚮導類型界面中的「下一步」按鈕。它切換到下一步,如果這是當前最後一個可用步驟,則它會將第一個輸入聚焦。

this.goNext = function() { 
    if (this.isNextAvailable()) { 
     var newIndex = this.currentStepIndex() + 1; 
     this.setCurrentStep(this.steps()[newIndex], newIndex); 
     if (!this.isNextAvailable()) { 
      this.currentStep().firstHasFocus(true); 
     } 
    } 
}; 

爲了確保firstHasFocus(true)始終更新的結合,它的定義總是通知:

this.firstHasFocus = ko.observable(false).extend({notify: 'always'}); 

每一步都有相應的觀點,即可以包括結合firstHasFocus

<h1>Select the Station Info Columns</h1> 
<form> 
    <label for="stationColumn">Station Name</label> 
    <select id="stationColumn" name="stationColumn" data-bind=" 
        options: data.headerVarNames, optionsCaption: '----', 
        value: data.stationHeaderName, valueUpdate: 'afterkeydown', 
        setfocus: firstHasFocus"></select> 
    <label for="siteColumn">Site Name</label> 
    <select id="siteColumn" name="siteColumn" data-bind=" 
        options: data.headerVarNames, optionsCaption: '----', 
        value: data.siteNameHeaderName"></select> 
... 

我使用的是自定義綁定,setfocus,而不是標準的hasfocus,因爲再也不想blur被調用。這是我的setfocus裝訂:

ko.bindingHandlers.setfocus = { 
    init: function(element, valueAccessor) { 
     var modelValue = valueAccessor(); 
     if (!ko.isWriteableObservable(modelValue)) { 
      throw new Error('setfocus must be used with a writable observable'); 
     } 
     var writeValue = function(event) { 
      var modelValue = valueAccessor(), 
       valueToWrite = element.ownerDocument.activeElement === element; 
      if (event.type == 'focusin' && !valueToWrite) 
       element.focus(); 
      else if (valueToWrite != modelValue()) 
       modelValue(valueToWrite); 
     }; 
     ko.utils.registerEventHandler(element, "focus", writeValue); 
     ko.utils.registerEventHandler(element, "focusin", writeValue); // For IE 
     ko.utils.registerEventHandler(element, "blur", writeValue); 
    }, 
    update: function(element, valueAccessor) { 
     var value = valueAccessor()(); // access and unwrap observable 
     setTimeout(function() { 
      if (value && element.offsetWidth && element.offsetHeight && document.activeElement && document.activeElement != element) { 
       element.focus(); 
       ko.utils.triggerEvent(element, "focusin"); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously 
      } 
     }); 
    } 
}; 
0

通常,您的視圖模型不應該需要訪問DOM元素(這就是綁定的用途)。但有一種方法可以做到這一點,它被稱爲自定義綁定提供程序。這沒有正式記錄,但它的描述是在Ryan Niemeyer's blog上的一些細節。

所以這裏有一個方法,你可以修改綁定提供添加這種行爲:

var origNodeHasBindings = ko.bindingProvider.instance.nodeHasBindings, 
    origGetBindings = ko.bindingProvider.instance.getBindings; 

ko.bindingProvider.instance.nodeHasBindings = function(node) { 
    return (node.nodeType === 1) || origNodeHasBindings(node); 
}; 
ko.bindingProvider.instance.getBindings = function(node, bindingContext) { 
    var bindings = origGetBindings.call(this, node, bindingContext) || {}; 
    bindings.attach = bindingContext.$data; 
    return bindings; 
}; 
+0

謝謝邁克爾。有沒有更好的方法來完成我想要做的事情?例如。當一個新模型被添加到'observableArray'中時,我想自動對焦模型的第一個'輸入',以便用戶可以立即開始輸入。我不認爲這會適用於任何現有的綁定。 – 2013-04-25 12:31:20

+0

你可以添加到你的問題?然後我可以添加一個關於它的不同答案。 – 2013-04-25 20:12:34

+0

好,問題更新。 – 2013-04-25 21:15:20