如何防止选定的索引在绑定数据更改时更改?

时间:2013-04-10 15:19:49

标签: javascript data-binding knockout.js

使用knockout,我有一个select(一个名字列表),其选项绑定到另一组敲除数据(人)。当任何人的姓名更改时,绑定到该人姓名的选择选项的值将正确更新。但是,如果您已选择该人,则不会保留选择的选择。

请参阅此jsFiddle以获取实例:http://jsfiddle.net/DbBZQ/

  1. 从列表中选择“Jane”。
  2. 将名称“Jane”更改为其他名称(例如“Jane Doe”)。
  3. 请注意,select默认返回第一项。
  4. 即使基础值发生了变化,如何使选择保持相同的选项索引?有没有办法指示淘汰赛保留选择,还是我必须使用JS单独执行此操作?

    完整代码示例

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta charset="utf-8" />
            <title></title>
            <script type="text/javascript" src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
            <script type="text/javascript">
                var data =
                {
                    people: ko.observableArray(
                    [
                        { name: ko.observable("Jim") },
                        { name: ko.observable("Jane") },
                        {
                            name: ko.observable("Sam"),
                            subordinates: ko.observableArray(
                            [
                                { 
                            name: ko.observable("Tambone"),
                                    subordinates: ko.observableArray(
                                    [
                                        { name: ko.observable("Edward") },
                                        { name: ko.observable("Kristy") },
                                        { name: ko.observable("Thomas") },
                                        { name: ko.observable("Andy") }
                                    ])
                                },
                                { name: ko.observable("Jules") }
                            ])
                        }
                    ])
                };
                var allNames = ko.computed(function ()
                {
                    var names = [];
                    var selector = function (name, indent)
                    {
                        var option =
                        {
                            value: name,
                            text: (indent || "") + name
                        };
    
                        return option;
                    };
    
                    for (var i = 0; i < data.people().length; i++)
                    {
                        names.push(selector(data.people()[i].name()));
                        addSubordinates(names, 1, data.people()[i].subordinates, selector);
                    }
    
                    return names;
                });
    
                function addSubordinates(names, depth, subordinates, selector)
                {
                    if (subordinates != null)
                    {
                        var indentText = "";
    
                        for (var i = 0; i < depth; i++)
                            indentText += ". . ";
    
                        for (var i = 0; i < subordinates().length; i++)
                        {
                            names.push(selector(subordinates()[i].name(), indentText));
                            addSubordinates(names, depth + 1, subordinates()[i].subordinates, selector);
                        }
                    }
                }
            </script>
        </head>
        <body>
            <div data-bind="foreach: data.people">
                <input type="text" data-bind="value: name" /><br />
            </div>
            <a href="JavaScript:data.people.push({ name: ko.observable('New Person') });">Add Person</a>
    
            <br /><br /><br />
    
            <select data-bind="options: allNames, optionsValue: 'value', optionsText: 'text', optionsCaption: 'All Names...'" />
    
            <script type="text/javascript">
                ko.applyBindings();
            </script>
        </body>
    </html>
    

1 个答案:

答案 0 :(得分:1)

选择丢失的原因是因为所选值直接与name属性匹配,而name属性会发生变化。因此,数据源(allNames)中不再存在所选值。

如果您想保留选择,您有几个选择:

  1. 实施黑客攻击,例如跟踪索引,并在值更改后重置
  2. 将所选值绑定到不会更改的属性。
  3. 您是否拥有可用作所选值的不可变属性?

    为了举例,我在数据源中的对象中添加了一个id属性,并将其用作选定的值而不是name。这符合您的预期:

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta charset="utf-8" />
            <title></title>
            <script type="text/javascript" src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
            <script type="text/javascript">
                var data =
                {
                    people: ko.observableArray(
                    [
                        { id: 1, name: ko.observable("Jim") },
                        { id: 2, name: ko.observable("Jane") },
                        {
                            id: 3, name: ko.observable("Sam"),
                            subordinates: ko.observableArray(
                            [
                                { 
                            id: 4, name: ko.observable("Tambone"),
                                    subordinates: ko.observableArray(
                                    [
                                        { id: 5, name: ko.observable("Edward") },
                                        { id: 6, name: ko.observable("Kristy") },
                                        { id: 7, name: ko.observable("Thomas") },
                                        { id: 8, name: ko.observable("Andy") }
                                    ])
                                },
                                { id: 9, name: ko.observable("Jules") }
                            ])
                        }
                    ])
                };
                var allNames = ko.computed(function ()
                {
                    var names = [];
                    var selector = function (id, name, indent)
                    {
                        var option =
                        {
                            value: id,
                            text: (indent || "") + name
                        };
    
                        return option;
                    };
    
                    for (var i = 0; i < data.people().length; i++)
                    {
                        names.push(selector(data.people()[i].id, data.people()[i].name()));
                        addSubordinates(names, 1, data.people()[i].subordinates, selector);
                    }
    
                    return names;
                });
    
                function addSubordinates(names, depth, subordinates, selector)
                {
                    if (subordinates != null)
                    {
                        var indentText = "";
    
                        for (var i = 0; i < depth; i++)
                            indentText += ". . ";
    
                        for (var i = 0; i < subordinates().length; i++)
                        {
                            names.push(selector(subordinates()[i].id,subordinates()[i].name(), indentText));
                            addSubordinates(names, depth + 1, subordinates()[i].subordinates, selector);
                        }
                    }
                }
            </script>
        </head>
        <body>
            <div data-bind="foreach: data.people">
                <input type="text" data-bind="value: name" /><br />
            </div>
            <a href="JavaScript:data.people.push({ name: ko.observable('New Person') });">Add Person</a>
    
            <br /><br /><br />
    
            <select data-bind="options: allNames, optionsValue: 'value', optionsText: 'text', optionsCaption: 'All Names...'" />
    
            <script type="text/javascript">
                ko.applyBindings();
            </script>
        </body>
    </html>
    

    修改 作为替代方案,如果您设置value属性以使其为返回项目索引的ko.computed,该怎么办?像这样:

    var allNames = ko.computed(function ()
    {
        var names = [];
        var selector = function (item, name, indent)
        {
            var option =
            {
                value: ko.computed(function(){ return data.people().indexOf(item);}),
                text: (indent || "") + name
            };
    
            return option;
        };
    
        for (var i = 0; i < data.people().length; i++)
        {
            names.push(selector(data.people()[i], data.people()[i].name()));
            addSubordinates(names, 1, data.people()[i].subordinates, selector);
        }
    
        return names;
    });
    
    function addSubordinates(names, depth, subordinates, selector)
    {
        if (subordinates != null)
        {
            var indentText = "";
    
            for (var i = 0; i < depth; i++)
                indentText += ". . ";
    
            for (var i = 0; i < subordinates().length; i++)
            {
                names.push(selector(subordinates()[i],subordinates()[i].name(), indentText));
                addSubordinates(names, depth + 1, subordinates()[i].subordinates, selector);
            }
        }
    }