2013-07-10 31 views
8

Ok, tôi đã chiến đấu với vấn đề này trong nhiều giờ ngay bây giờ và thu hẹp vấn đề này một FiddleTwitter Bootstrap lựa chọn typeahead không bị ràng buộc bởi KnockoutJS

Vấn đề rất đơn giản là, khi tôi đang sử dụng typeahead twitter bootstrap của cắm trên nhập văn bản và thực hiện lựa chọn, giá trị không cập nhật trong KnockoutJS ViewModel. Tôi biết tôi có thể hack nó để làm việc nhưng phải có một cái gì đó mà tôi đang thiếu ở đây.

Về cơ bản những gì tôi có là:

Knockout Binding

// Bind twitter typeahead 
ko.bindingHandlers.typeahead = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var $element = $(element); 
     var allBindings = allBindingsAccessor(); 
     var typeaheadArr = ko.utils.unwrapObservable(valueAccessor()); 

     $element.attr("autocomplete", "off") 
       .typeahead({ 
        'source': typeaheadArr, 
        'minLength': allBindings.minLength, 
        'items': allBindings.items, 
        'updater': allBindings.updater 
       }); 
    } 
}; 

Knockout ViewModel

function MyModel(){ 
    var self = this; 
    self.productName = ko.observable(); 
    self.availableProducts = ['One', 'Two', 'Three']; 
} 

ko.applyBindings(new MyModel()); 

HTML

<input type="text" data-bind="typeahead:availableProducts, value:productName"/> 

Phần còn lại của nội dung chỉ đơn giản là đến từ Twitter Bootstrap.

+1

Tôi không phải là tác giả của các ràng buộc. Các ràng buộc ban đầu là ở đây: https://github.com/billpull/knockout-bootstrap Tôi tự hỏi nếu tôi bị mất một cái gì đó trong việc sử dụng? –

Trả lời

4

Một giải pháp là thay đổi chức năng updater của bạn khi bạn cần phải lấy các quan sát được sử dụng trong value ràng buộc và cập nhật nó với chức năng paramter:

'updater': function(item) { 
    allBindings.value(item); 
    return item; 
} 

Demo JSFiddle.

Nếu bạn không phải là tác giả của việc ràng buộc bạn hơn bạn có thể sử dụng tùy chọn updater để chỉ định chức năng updater

data-bind="typeahead:availableProducts, 
      updater: function(item) { productName(item); return item; }" 

Bởi vì các updater nên trả về các mục đã chọn cú pháp của điều này là không tốt đẹp như vậy.

Demo JSFiddle.

+0

Ok, điều đó dường như hoạt động tốt. Bạn có thể giải thích tại sao điều này hoạt động so với việc thực hiện trước đó? Tôi không phải là tác giả của sự ràng buộc loại trực tiếp. Tôi muốn hiểu những gì tác giả ban đầu nghĩ khi ông đặt allBindings.updater vào trình cập nhật và nếu có cách 'chính xác' để sử dụng ràng buộc. Cái gì tôi đang thiếu trong HTML có thể? Plugin gốc ở đây: https://github.com/billpull/knockout-bootstrap –

+0

Tôi không biết rằng ràng buộc này nằm trong thư viện. Tôi đã sửa đổi câu trả lời của mình để làm việc với mã gốc. Về lý do tại sao tác giả thiết kế API theo cách này tôi không có ý tưởng. Tôi đã không thể tìm thấy bất kỳ ví dụ về github trong đó sử dụng tùy chọn 'updater'. Vì vậy, tôi sẽ nói rằng đây là một "lỗi thiết kế API" trong thư viện bởi vì chúng ta đang nói về thư viện ko-bootstrap nên sử dụng thành ngữ hơn KO. Vì vậy, có thể tưởng tượng một cái gì đó như thế này như thực hiện đúng: http://jsfiddle.net/wTRhF/ – nemesv

+0

Tôi nghĩ rằng việc thực hiện ban đầu hoạt động tốt với các chức năng hơn là ràng buộc giá trị đơn giản. Về cơ bản hàm updater làm những gì nó cần làm với giá trị được chọn, ở đây nó gán cho một ko quan sát được. giải pháp của nemesv là một giải pháp ngắn gọn. –

3

updater này thứ không làm việc cho tôi, đây là những gì đã làm

ko.bindingHandlers.typeahead = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var $element = $(element); 
     var allBindings = allBindingsAccessor(); 
     var typeaheadArr = ko.utils.unwrapObservable(valueAccessor()); 

     var updateValues = function (val) { 
      allBindings.value(val); 
     }; 

     $element.attr("autocomplete", "off") 
       .typeahead({ 
        'local': typeaheadArr, 
        'minLength': allBindings.minLength, 
        'items': allBindings.items, 
       }).on('typeahead:selected', function (el, item) { 
        updateValues(item.value); 
       }).on('typeahead:autocompleted', function (el, item) { 
        updateValues(item.value); 
       }); 
    } 
}; 
3

Tôi muốn giữ danh sách đề xuất autocomplete của tôi tách rời khỏi Knockout hoàn toàn. Tôi chỉ muốn Knockout biết khi người dùng thực sự đã nhập giá trị.

Điều này gần hơn với kỹ thuật của người dùng2576666, vì nó sử dụng Typeahead's custom events để buộc cập nhật trong mô hình Knockout khi có lựa chọn hoặc tự động hoàn thành. Tuy nhiên, nó không đòi hỏi một ràng buộc tùy chỉnh typeahead, và cũng không yêu cầu các giá trị được lưu trữ trong Knockout ViewModel. Điều này mở ra phạm vi để hoàn thành tùy biến hơn xuống dòng (chẳng hạn như sử dụng Bloodhound), điều này sẽ trở nên vô ích nếu chúng tôi cố gắng lưu trữ nó trong mô hình Knockout. ViewModel của tôi chắc chắn không phải là nơi thích hợp để lưu trữ các tùy chọn tự động hoàn thành cho trường hợp sử dụng của tôi (và, tôi sẽ đề xuất, nhiều trường hợp khác - đặc biệt nếu bạn có danh sách tiềm năng lớn cần dân số động).IMO phiên bản này cũng là dễ hiểu:

var availableProducts = ['One', 'Two', 'Three']; 

var substringMatcher = function(strs) { 
    return function findMatches(q, cb) { 
    var matches, substrRegex; 
    matches = []; 
    substrRegex = new RegExp(q, 'i'); 
    $.each(strs, function(i, str) { 
     if (substrRegex.test(str)) { 
     matches.push({ value: str }); 
     } 
    }); 
    cb(matches); 
    }; 
}; 


function MyModel(){ 
    var self = this; 
    self.productName = ko.observable(); 
} 

var myModel = new MyModel(); 

ko.applyBindings(myModel); 

var onUpdated = function($e, datum) { 
    myModel.productName(datum.value); 
}; 

$(".typeahead") 
    .typeahead(
     {hint: true, minLength: 1, highlight: true}, 
     {displayKey: 'value', source: substringMatcher(availableProducts)}) 
    .on('typeahead:autocompleted', onUpdated) 
    .on('typeahead:selected', onUpdated); // for knockoutJS 

Tôi đã, tất nhiên, lưu này như a JSFiddle:

Các vấn đề liên quan