2011-07-19 4 views
8

Wiązanie listy obiektów do select przy użyciu nokautu. Klasa obiekt może mieć dowolną liczbę właściwościPowiązanie pojedynczej opcji z poprawnością jQuery nie działa

<select id="TheProperty_City" 
     name="TheProperty_City" 
     class="required" 
     data-bind="options: cityList, 
        optionsText: 'Name', 
        value: selectedCity, 
        optionsCaption: '--select the city--'" /> 

to działa perfekcyjnie i mogę używać viewModel.selectedCity().Name lub viewModel.selectedCity().Value załadunku elementów podrzędnych.

Mój problem dotyczy sprawdzania poprawności jQuery. Jeśli opuszczę instrukcję jak powyżej, jQuery nie zresetuje błędu nawet po wyborze.

Naprawiłem to, określając optionsValue w wiązaniu, ale następnie selectedCity zwraca wartość skalarną, a nie cały obiekt. Każdy pomysł, jak zachować zachowanie obiektu lub inaczej walidacji?

<select id="TheProperty_City" 
     name="TheProperty_City" 
     class="required" 
     data-bind="options: cityList, 
        optionsText: 'Name', 
        optionsValue: 'Value', //added the optionsValue 
        value: selectedCity, 
        optionsCaption: '--select the city--'" /> 

Błąd pozostaje tam, kiedy optionsValue nie jest określony:

Without the OptionsValue

Oto mój Object Watch na selectedCity:

viewModel.selectedCity() in watch returns an object

Oto Object Uważaj na selectedCity gdy optionsValue jest określony:

With OptionsValue

Odpowiedz

8

Problem jest, że gdy mamy do czynienia z obiektami jak wartości, option elementy mają ich wartość ustawiona na „”. Walidacja jQuery kończy się niepowodzeniem z tego powodu. Możesz napisać powiązanie lub opakowanie do powiązania options, które przechodzi przez i ustawia je na wartość, ale nie sądzę, że lepiej jest jechać tą trasą.

Przyzwoitą opcją jest zapisanie wartości i użycie obiektu dependObservable do reprezentowania aktualnie wybranego obiektu.

To byłoby jak:

var viewModel = { 
    cityList: [{ Name: "Madison", Value: "MSN" }, { Name: "Milwaukee", Value: "MKE" }, { Name: "Green Bay", Value: "GRB" }], 
    selectedCityValue: ko.observable() 
}; 

viewModel.selectedCity = ko.dependentObservable(function() { 
    var value = this.selectedCityValue(); 
    return ko.utils.arrayFirst(this.cityList, function(city) { 
     return city.Value === value; 
    }); 
}, viewModel); 

ze środkiem wiążącym jak:

<select id="TheProperty_City" name="TheProperty_City" class="required" 
    data-bind="options: cityList, 
    optionsText: 'Name', 
    optionsValue: 'Value', 
    value: selectedCityValue, 
    optionsCaption: '--select the city--'" /> 

próbki tutaj: http://jsfiddle.net/rniemeyer/EgCM3/

+3

Dzięki, to jest to, co mam jako obejście, ale nużące to zrobić dla wszystkich dropdownów. Mój skrypt knockoutjs szybko rośnie i zastanawiam się, czy to jest warte wysiłku, gdy tracisz pomocników HTML mvc control, adnotacje danych ViewModel serwera i wbudowaną obsługę sprawdzania poprawności. Ofcourse databinding jest świetny. W każdym razie, zrobię to jako odpowiedź, by pomóc innym poszukiwaczom. –

+0

Jak zaimplementować niestandardowe powiązanie, aby to naprawić? – Jason

+0

Miałem ten sam problem i rozwiązany w taki sam sposób, jak opisał RP Niemeyer. Nadal zastanawiam się, jak zrobić to ładniej, bo Jason napisał coś nieczytelnego dla dużych modeli podglądu. –

5

rozwiązanie Całkiem miłe byłoby dodać optionsAfrerRender parametr do opcji wiązania . Zakładając, że w obiekcie "selectedCity" znajduje się pole "cityId", możesz przypisać je do wartości opcji. Proszę sprawdzić następujące rozwiązanie oparte na przykład:

<select id="TheProperty_City" 
    name="TheProperty_City" 
    class="required" 
    data-bind="options: cityList, 
       optionsText: 'Name', 
       value: selectedCity, 
       optionsAfterRender: function(option, item) 
             { option.value = item.cityId; } 
       optionsCaption: '--select the city--'" /> 

Stosując to podejście dostaniesz pracę obu opcji pucharowej wiążące i sprawdzania poprawności jQuery.

+0

ładne obejście! –

+0

To działa bardzo dobrze, aby pozbyć się dziwności podczas integracji z walidatorami Bootstrap. – AdjunctProfessorFalcon

1

Powyższa odpowiedź działa z jednym zastrzeżeniem. Pierwsza wybrana wartość związana ("- wybierz miasto -") będzie niezdefiniowana, powodując błąd.

Jeśli zmodyfikujesz kod, aby sobie z tym poradzić, zadziała.

<select id="TheProperty_City" 
name="TheProperty_City" 
class="required" 
data-bind="options: cityList, 
      optionsText: 'Name', 
      value: selectedCity, 
      optionsAfterRender: setOptionValue 
      optionsCaption: '--select the city--'" /> 

Uwaga: Usunąłem wszystko z ViewModel, z wyjątkiem metody setOptionValue dla zwięzłości.

<script type="text/javascript"> 
var vm = { 
    setOptionValue: function(option, item) { 
     if (item === undefined) { 
      option.value = ""; 
     } else { 
      option.value = item.id; 
     } 
    } 
}; 
ko.applyBindings(vm); 

+0

Idąc dalej: w funcie 'setOptionValue' podaj nazwę właściwości jako trzeci parametr (' propId'), a następnie wykonaj 'option.value = item [propId]'. Można go teraz użyć dla dowolnego menu rozwijanego z różnymi powiązaniami modelu. –

0

Aby przedłużyć na odpowiedź Roberta możemy uczynić pracę funkcji pomocnika dla każdej listy rozwijanej w modelu widoku bez względu na kontekst wiązania danych, umożliwiając użytkownikowi przejść na sznurku za prawo Obiekt:

JS

self.setOptionValue = function(propId) { 
    return function (option, item) { 
     if (item === undefined) { 
      option.value = ""; 
     } else { 
      option.value = item[propId]; 
     } 
    } 
}; 

HTML

<select class="custom-dropdown" data-bind="options: cityList, 
     optionsAfterRender: setOptionValue('AppointmentTypeId'), value: selectedCityObj, optionsCaption: 'Choose...'" data-validation="required"></select>