2014-04-01 65 views
0

如果我試圖改變元素的樣式或可視性,我傾向於在Knockout Viewmodel中使用jQuery而後悔。所以我猜這裏有更好的方法:遞歸敲除列表 - 設置沒有jQuery的選定值

我有一些遞歸敲擊視圖模型來顯示公司的樹結構,這些公司的經理以及這些經理之下的任何公司以及(因此遞歸岬)。

我如何可以設置一個孩子(ManagerViewModel)可觀察到的從$根(ApproverViewModel)當我遞歸創建這些對象之內?目前,我正在用jQuery做這件事,並設置了隱藏元素的值,但這似乎違背了KO的可觀察模式 - 這讓我覺得還有一種更好的方式,我只是不知道。

在MangerViewModel中,我在第一次加載頁面時設置了_self.DefaultApproverClass()。然後,當用戶選擇不同的管理器時,我只需刪除所有類,找到新選定元素的ID並將CSS類應用到它。

我猜這樣做有一個更好的,更「敲除遞歸」的方式。有什麼建議麼?

這裏是我的ViewModels(the complete version is in this JSFiddle

be.ApproverViewModel = function (data) { 
    var _self = this; 

    _self.UserCompanies = ko.observableArray(
     ko.utils.arrayMap(data.userCompanies, function (item) { 
      return new be.CompanyViewModel(item); 
     }) 
    ); 
    _self.SetSelectedManager = function (data, event) { 
     // remove all classes, then add the selected class to the selected element 
     $('.selectedApprover').removeClass('selectedApprover'); 
     $('#' + data.ClientID()).addClass('selectedApprover'); 
     // set UI elements 
     $('#selectedClientID').text(data.ClientID()); 
     $('#selectedManagerName').text(data.ManagerName()); 
    }; 
    _self.GetSelected = function (data, event) { 
     console.log($('#selectedClientID').text()); 
    }; 
}; 

be.CompanyViewModel = function (data) { 
    var _self = this; 
    ko.mapping.fromJS(data, {}, _self); 

    _self.Companies = ko.observableArray(
     ko.utils.arrayMap(data.Companies, function (item) { 
      return new be.CompanyViewModel(item); 
     }) 
    ); 
    _self.Managers = ko.observableArray(
     ko.utils.arrayMap(data.Managers, function (item) { 
      return new be.ManagerViewModel(item); 
     }) 
    ); 
}; 
be.ManagerViewModel = function (data) { 
    var _self = this; 
    ko.mapping.fromJS(data, {}, _self); 

    _self.DefaultApproverClass = ko.observable(''); 
    _self.SubordinateMgrs = ko.observableArray(
     ko.utils.arrayMap(data.SubordinateMgrs, function (item) { 
      return new be.ManagerViewModel(item); 
     }) 
    ); 
    // Styles 

    _self.LoadStyleSelected = function() { 
     if (_self.IsDefaultApprover()) { 
      _self.DefaultApproverClass('selectedApprover'); 
      $('#selectedManagerName').text(_self.ManagerName()); 
      $('#selectedClientID').text(_self.ClientID()); 
     } 
    }; 
    // just call it the first time 
    _self.LoadStyleSelected(); 

}; 

的有所削減版本標記

<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> 
+0

任何原因你沒有使這個自定義的數據綁定? – noname

+0

@Ben - 我在想我會遇到同樣的問題。如果您對我如何實現這一目標有所建議,我會很感激幫助。 –

回答

1

丟棄所有的jQuery代碼,使用KO來控制所有視圖呈現,看看的更新jsfidder http://jsfiddle.net/H9V7g/9/

處理您複雜的數據,有一個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())); 
}; 

BTW,您可以簡化find_default(),如果你願意sacrifize可讀性。 http://jsfiddle.net/H9V7g/10/

// 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; 
} 
+0

太好了,謝謝!我正在玩一個遞歸循環,但無法弄清楚。並感謝提供這兩個例子。 –