我做错了这个淘汰赛绑定吗?

时间:2012-03-13 16:51:20

标签: asp.net-mvc knockout.js asp.net-mvc-4 knockout-2.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' />

viewmodel 代码:

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添加class css <li>。 css类会在<li>上显示一个复选标记图标。

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

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

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

Chrome&amp;即使self.Color是函数而不是字符串,IE仍然返回true。但Firefox没有。当self.Color是函数时,它返回false。这就是为什么在将css类添加到<li>之前必须至少检查一次每个无线电并显示图标的原因。

我对淘汰赛仍然有点新意,可能不适当地将viewmodel属性称为函数。我还不清楚何时使用()括号以及何时省略它们。还有另一种方法我应该编写self.Selected计算的observable,它取决于self.Color计算的observable(在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;
});

然而,这感觉就像我在打击淘汰赛。是不应该“只是工作”?

1 个答案:

答案 0 :(得分:2)

KO中的value绑定对于单选按钮和复选框并不是很理想。在您的情况下,您需要单选按钮具有value属性,以便在您单击它们时,该值可用于更新TestViewModel.BackColor可观察对象。

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

所以,我已经使用value绑定将html模板改为使用attr绑定(html属性)。现在只需设置单选按钮的value html属性即可。然后,checked绑定会使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;
});