递归淘汰列表-不使用jQuery设置选定值

递归淘汰列表-不使用jQuery设置选定值,jquery,recursion,knockout.js,Jquery,Recursion,Knockout.js,如果我试图更改元素的样式或可见性,我会后悔在淘汰视图模型中使用jQuery。所以我猜有更好的方法: 我有一些递归淘汰视图模型来显示公司的树状结构,这些公司中的经理,以及这些经理下的任何公司等等(因此递归性) 在递归创建这些对象时,如何从$root(ApproverViewModel)中设置子对象(ManagerViewModel)中的可观察对象?目前,我正在使用jQuery进行这项工作,并设置一个隐藏元素的值,但这似乎与KO的可观察模式背道而驰——这让我觉得有一种更好的方式,我只是不知道 在Ma

如果我试图更改元素的样式或可见性,我会后悔在淘汰视图模型中使用jQuery。所以我猜有更好的方法:

我有一些递归淘汰视图模型来显示公司的树状结构,这些公司中的经理,以及这些经理下的任何公司等等(因此递归性)

在递归创建这些对象时,如何从$root(ApproverViewModel)中设置子对象(ManagerViewModel)中的可观察对象?目前,我正在使用jQuery进行这项工作,并设置一个隐藏元素的值,但这似乎与KO的可观察模式背道而驰——这让我觉得有一种更好的方式,我只是不知道

在MangerViewModel中,我将在页面第一次加载时设置
\u self.DefaultApproverClass()
。然后,当用户选择一个不同的管理器时,我只是删除所有的类,找到新选择的元素的ID并对其应用CSS类

我猜有一种更好、更“击倒递归”的方法来实现这一点。有什么建议吗

下面是我的ViewModels()的精简版本

加价

<div id="CompanyTree">
    <div class="selectedApproverHeader">
        <h4 class="lighter smaller">Currently Selected Approver:
        <br />
            <span id="selectedManagerName"></span>,
            ID: <span id="selectedClientID"></span>
        </h4>
    </div>
    <div class="approver-list-contaier">
        <ul data-bind="template: { name: 'companyElement', foreach: UserCompanies }"></ul>
    </div>
    <script id="companyElement" type="text/html">
        <li class="companyList">
            <h4 class="smaller" data-bind="text: CompanyName"></h4>
            <ul class="managerList" data-bind="template: { name: 'managerElement', foreach: Managers }"></ul>
            <ul data-bind="template: { name: 'companyElement', foreach: Companies }"></ul>
        </li>
    </script>
    <script id="managerElement" type="text/html">
        <li class="managerList">
            <span data-bind="text: ManagerName, attr: { id: ClientID },  css: DefaultApproverClass, click: $root.SetSelectedManager"></span>
            <ul data-bind="template: { name: 'managerElement', foreach: SubordinateMgrs }">
            </ul>
        </li>
    </script>
    <div>
        <button data-bind="click:$root.GetSelected">Click Me</button>
    </div>
</div>

当前选定的审批人:

, 身份证件:
      • 点击我
        删除所有jQuery代码,使用ko控制所有视图表示,查看更新的JSFIDER

        为了处理复杂的数据,有一个init逻辑来查找初始默认管理器

        be.ApproverViewModel = function (data) {
            var _self = this;
            _self.SelectedManager = ko.observable();
        
            _self.UserCompanies = ko.observableArray(
            ko.utils.arrayMap(data.userCompanies, function (item) {
                return new be.CompanyViewModel(item);
            }));
        
            _self.GetSelected = function (data, event) {
                if (_self.SelectedManager()) alert(_self.SelectedManager().ClientID());
            };
        
            // init default one
            function find_default(companies) {
                var default_manager;
                ko.utils.arrayFirst(companies, function(c) {
                    var a_default = ko.utils.arrayFirst(c.Managers(), function(m) {
                       return m.IsDefaultApprover(); 
                    });
        
                    if (a_default) {
                        default_manager = a_default;
                        return true;
                    } else {
                        var deeper_default = find_default(c.Companies());
                        if (deeper_default) {
                            default_manager = deeper_default;
                            return true;
                        }
                    }    
                });
                return default_manager;
            }
        
            _self.SelectedManager(find_default(_self.UserCompanies()));
        };
        
        顺便说一句,如果你愿意牺牲可读性,你可以简化find_default()。


        你为什么不将其作为自定义数据绑定?@Ben-我想我也会遇到同样的问题。如果你对我如何做到这一点有什么建议,我将非常感谢你的帮助。太好了,谢谢你!我在玩弄一个递归循环,但没有弄明白。谢谢你提供这两个例子。
        be.ApproverViewModel = function (data) {
            var _self = this;
            _self.SelectedManager = ko.observable();
        
            _self.UserCompanies = ko.observableArray(
            ko.utils.arrayMap(data.userCompanies, function (item) {
                return new be.CompanyViewModel(item);
            }));
        
            _self.GetSelected = function (data, event) {
                if (_self.SelectedManager()) alert(_self.SelectedManager().ClientID());
            };
        
            // init default one
            function find_default(companies) {
                var default_manager;
                ko.utils.arrayFirst(companies, function(c) {
                    var a_default = ko.utils.arrayFirst(c.Managers(), function(m) {
                       return m.IsDefaultApprover(); 
                    });
        
                    if (a_default) {
                        default_manager = a_default;
                        return true;
                    } else {
                        var deeper_default = find_default(c.Companies());
                        if (deeper_default) {
                            default_manager = deeper_default;
                            return true;
                        }
                    }    
                });
                return default_manager;
            }
        
            _self.SelectedManager(find_default(_self.UserCompanies()));
        };
        
        // init default one
        function find_default(companies) {
            var default_manager;
            ko.utils.arrayFirst(companies, function(c) {
                return default_manager = ko.utils.arrayFirst(c.Managers(), function(m) {
                   return m.IsDefaultApprover(); 
                }) || find_default(c.Companies());
            });
            return default_manager;
        }