Код код:
<ul data-bind="foreach: BackColorOptions">
<li data-bind="css: { selected: Selected }">
<label>
<input type="radio" name="BackColorOption"
data-bind="value: Color, checked: $root.BackColor" />
</label>
</li>
</ul>
@{
var jsonModel = new System.Web.Script.Serialization.
JavaScriptSerializer().Serialize(Model);
}
<input type="hidden" id="JsonModel" value='@jsonModel' />
модель представления код:
var initialData = $.parseJSON($('#JsonModel').val());
function BackColorOption(data, parent) {
var self = this;
self.parent = parent;
self.Text = ko.observable(data.Text);
self.Color = ko.computed(function () {
return '#' + self.Text().toLowerCase();
});
self.Selected = ko.computed(function () {
var backColor = self.parent.BackColor();
if (backColor) {
return backColor.toLowerCase() == self.Color;
}
return false;
});
}
function TestViewModel() {
var self = this;
self.BackColor = ko.observable(initialData.BackColor);
var mappedBackColorOptions = $.map(initialData.BackColorOptions,
function (item) {
return new BackColorOption(item, self);
}
);
self.BackColorOptions = ko.observableArray(mappedBackColorOptions);
}
ko.applyBindings(new TestViewModel());
Модель код:
string BackColor { get; set; }
SelectListItem[] BackColorOptions
{
get
{
return new[]
{
new SelectListItem{Text = "cc0000"},
new SelectListItem{Text = "ff9900"},
new SelectListItem{Text = "dddd33"},
new SelectListItem{Text = "009900"},
new SelectListItem{Text = "00cccc"},
new SelectListItem{Text = "0066ff"},
new SelectListItem{Text = "9900ff"},
new SelectListItem{Text = "ff00ff"},
};
}
}
Приведенный выше код работает должным образом в IE (8) и Chrome (17), но не в FF (10.0.2). Я в основном пытаюсь сделать селектор цвета, похожий на ярлыки проблемы GitHub. Представление отображает набор переключателей, по которым вы можете выбрать цвет. Когда радио проверяется, я добавляю selected
css class
к родителю <li>
. Класс css приводит к появлению значка галочки над <li>
.
В Firefox выбранный класс CSS применяется только после того, как пользователь прошел и проверил каждую радиокнопку хотя бы один раз. Я отладил и обнаружил, что это из-за того, как вычисляемая наблюдаемая self.Color
оценивается в замыкании BackColorOption
. Перед первой проверкой радио, typeof(self.Color) == 'function'
оценивается как истинное. Однако после проверки typeof(self.Color) == 'string'
оценивается как true.
Это typeof(self.Color)
поведение одинаково как для Firebug, так и для js-отладчика Chrome. Однако проблема в FF из-за этой строки в self.Selected
, вычисляемой наблюдаемой в закрытии BackColorOption
:
return backColor.toLowerCase() == self.Color;
Chrome & IE по-прежнему возвращают true, даже если self.Color
является функцией вместо строки. Однако Firefox этого не делает. Когда self.Color
является функцией, она возвращает false. Вот почему вы должны проверить каждую радиостанцию хотя бы один раз, прежде чем класс css будет добавлен в <li>
и появится значок.
Я все еще немного новичок в нокауте, и, возможно, не совсем правильно вызывать свойство viewmodel как функцию, когда это необходимо. Мне все еще немного неясно, когда использовать скобки ()
и когда их опускать. Есть ли другой способ написать вычисляемую наблюдаемую self.Selected
, которая зависит от вычисляемой наблюдаемой self.Color
(в замыкании BackColorOption
)?
Обновление 1
Мне удалось заставить это работать в FF 10.0.2 со следующим:
self.Selected = ko.computed(function () {
var backColor = self.parent.BackColor();
var selfColor = self.Color;
if (typeof (selfColor) === 'function')
selfColor = self.Color();
if (backColor) {
return backColor.toLowerCase() === selfColor;
}
return false;
});
Однако мне кажется, что я борюсь с нокаутом. Разве это не должно "просто работать"?