0

视图代码:

<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 问题标签的颜色选择器。该视图呈现一组单选按钮,您可以单击以选择颜色。检查收音机时,我将selectedcss添加class到 parent <li>。css 类导致复选标记图标出现在<li>.

在 Firefox 中,选定的 css 类仅在用户完成并检查每个单选按钮至少一次后才会应用。我调试并发现这是因为在闭包中计算计算的self.Colorobservable的方式。BackColorOption在第一次检查无线电之前,typeof(self.Color) == 'function'评估为真。然而,在它被检查之后,typeof(self.Color) == 'string'评估为真。

typeof(self.Color)根据 Firebug 和 Chrome 的 js 调试器,这种行为是相同的。然而,FF 中的问题是由于闭包中self.Selected计算的 observable 中的这一行:BackColorOption

return backColor.toLowerCase() == self.Color;

即使self.Color是函数而不是字符串,Chrome 和 IE 仍然返回 true。然而火狐没有。当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;
});

然而,这感觉就像我在与淘汰赛作斗争。它不应该“正常工作”吗?

4

1 回答 1

2

KO 中的value绑定对于单选按钮和复选框来说并不理想。在您的情况下,您需要您的单选按钮具有一个value属性,以便当您单击它们时,该值可用于更新您的TestViewModel.BackColorobservable。

value通常使用单选按钮,一旦呈现 html ,您不希望属性更改(如果有的话)。

因此,我已将您的 html 模板从使用value绑定更改为使用attr绑定(html 属性)。这现在只是设置value单选按钮的 html 属性。然后,checked绑定使您的observable 与选中的单选按钮的TestViewModel.BackColor任何内容保持同步。value

看到这个小提琴:http: //jsfiddle.net/m2KQ2/

此外,您的BackColorOption函数中的行有一个错字:

self.Selected = ko.computed(function () {
    var backColor = self.parent.BackColor();
    if (backColor) {
        return backColor.toLowerCase() == self.Color; //<-- should be Color();
    }
    return false;
});
于 2012-03-13T18:05:29.030 回答