2016-01-13 286 views
0

我有一個3層級聯選擇列表,我已經使用knockout.js/jQuery/json實現。級聯選擇默認值

有些情況下,選擇框中只有一個選擇 - 在這種情況下,我不想強​​制用戶不得不手動選擇它,而是將其默認爲單個值,然後級聯到下一個框自動。這可以做到嗎?

我的選擇列表(第一個是目前略有不同,因爲它是由MVC剃刀產生的視圖與視圖模型提供直接值):

<!--Variants--> 
<select class="dim" data-bind="value: selectedDim1" id="Dim1" name="Dim1" onchange="FetchDim2();"><option selected="selected" value="">Select Colour</option> 
<option value="Black">Colour:Black</option> 
<option value="NAVYBLUE">Colour:Navy Blue</option> 
</select> 
<select id="Dim2" data-bind="value: selectedDim2, options: ddlDim2, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Waist Size'" class="dim"></select> 
<select id="Dim3" data-bind="value: selectedDim3, options: ddlDim3, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Leg Length'" class="dim"></select> 

我敲代碼:

function DDLViewModel() { 
     this.ddlDim1 = ko.observableArray([]); 
     this.ddlDim2 = ko.observableArray([]); 
     this.ddlDim3 = ko.observableArray([]); 
     this.selectedDim1 = ko.observable(); 
     this.selectedDim1.subscribe(FetchDim2, this); 
     this.selectedDim2 = ko.observable(); 
     this.selectedDim2.subscribe(FetchDim3, this); 
     this.selectedDim3 = ko.observable(); 
     this.selectedDim3.subscribe(FetchVariant, this); 
    } 

    var objVM = new DDLViewModel(); 
    // Activates knockout.js 
    ko.applyBindings(objVM); 

    function FetchDim2() { 
     $.ajax({ 
      type: 'POST', 
      url: '/product/getdims/', // we are calling json method 
      dataType: 'json', 
      // here we get value of selected dim. 
      data: { id: 20408, 
       level: 2, 
       head: 'Waist Size', 
       code: $("#Dim1").val() 
      }, 
      success: function (dims) { 
       // dims contains the JSON formatted list of dims passed from the controller 
       objVM.ddlDim2(dims); 
       objVM.ddlDim3.removeAll(); 
      }, 
      error: function (ex) { 
       alert('Failed to retrieve dims.' + ex); 
      } 
     }); 
    } 

    function FetchDim3() { 
     $.ajax({ 
      type: 'POST', 
      url: '/product/getdims/', // we are calling json method 
      dataType: 'json', 
      // here we get value of selected dim. 
      data: { id: 20408, 
       level: 3, 
       head: 'Leg Length', 
       code: $("#Dim2").val() 
      }, 
      success: function (dims) { 
       // dims contains the JSON formatted list of dims passed from the controller 
       objVM.ddlDim3(dims); 
      }, 
      error: function (ex) { 
       alert('Failed to retrieve dims.' + ex); 
      } 
     }); 
    } 

我猜我(a)需要指定一個默認值,如果只有在選擇時,並且(b)強制調用填充下一級的代碼的調用?不知道如何做,但沒有打破一切,但!

回答

1

哎呀!不要將jQuery和Knockout混合在一起。不要讓jQuery執行DOM操作(例如val(...)),而是從視圖模型中獲取選定的值。

這也將大大簡化您的視圖,因爲像這些id屬性變得無關緊要。

此外,我建議使Fetch...方法成爲您的視圖模型的依賴項。在下面的示例中,我只是將這些函數內聯在視圖模型構造函數內部,但是也可以將它們包裝在一個服務中,並將該服務作爲依賴項(當然,您仍然需要爲該服務提供輸入和成功處理程序) 。

另一件事,非常需要/有用的,如果你按照上面的建議是:使用var self = this成語,而不是重申this無處不/處處提供this說法。

隨着所有這些變化,修復您的原始問題變得微不足道。觸發級聯更新可以在成功功能內完成。在我告訴了全段,這裏是爲您的實際問題的細節問題:

success: function(dims) { 
    self.ddlDim3(dims); 
    if (dims.length === 1) { 
    self.selectedDim3(dims[0].Value); 
    } 
} 

簡單地說,如果只有一個這種選擇第一個選項,並允許在需要時淘汰賽處理更新DOM(和級聯, )。

這裏的關閉基於一個完整的演示你的原始代碼:

// Fake the Ajax requests: 
 
var $ = { 
 
    ajax: function(options) { 
 
    if (options.data.level === 2 && options.data.code === "Black") { 
 
     options.success([{ 
 
     Text: "Waist size S", 
 
     Value: "S" 
 
     }, { 
 
     Text: "Waist size M", 
 
     Value: "M" 
 
     }, { 
 
     Text: "Waist size L", 
 
     Value: "L" 
 
     }]); 
 
    } 
 

 
    if (options.data.level === 2 && options.data.code === "NAVYBLUE") { 
 
     options.success([{ 
 
     Text: "Waist size M", 
 
     Value: "M" 
 
     }]); 
 
    } 
 

 
    // Not faking lvl 3 as extensively, but the same would hold as above. 
 
    if (options.data.level === 3) { 
 
     options.success([{ 
 
     Text: "Legs 40", 
 
     Value: "40" 
 
     }]); 
 
    } 
 
    } 
 
}; 
 

 
function DDLViewModel() { 
 
    var self = this; 
 

 
    self.ddlDim1 = ko.observableArray([]); 
 
    self.ddlDim2 = ko.observableArray([]); 
 
    self.ddlDim3 = ko.observableArray([]); 
 
    self.selectedDim1 = ko.observable(); 
 
    self.selectedDim1.subscribe(FetchDim2); 
 
    self.selectedDim2 = ko.observable(); 
 
    self.selectedDim2.subscribe(FetchDim3); 
 
    self.selectedDim3 = ko.observable(); 
 
    self.selectedDim3.subscribe(FetchVariant); 
 

 
    function FetchDim2() { 
 
    console.log(2); 
 

 
    $.ajax({ 
 
     url: '/product/getdims/', 
 
     data: { 
 
     id: 20408, 
 
     level: 2, 
 
     head: 'Waist Size', 
 
     code: self.selectedDim1() 
 
     }, 
 
     success: function(dims) { 
 
     self.ddlDim2(dims); 
 
     self.ddlDim3.removeAll(); 
 
     if (dims.length === 1) { 
 
      self.selectedDim2(dims[0].Value); 
 
     } else { 
 
      self.selectedDim2(null); 
 
     } 
 
     } 
 
    }); 
 
    } 
 

 
    function FetchDim3() { 
 
    if (!self.selectedDim2()) { 
 
     self.ddlDim3.removeAll(); 
 
    } else { 
 
     $.ajax({ 
 
     data: { 
 
      id: 20408, 
 
      level: 3, 
 
      head: 'Leg Length', 
 
      code: self.selectedDim2() 
 
     }, 
 
     success: function(dims) { 
 
      self.ddlDim3(dims); 
 
      if (dims.length === 1) { 
 
      self.selectedDim3(dims[0].Value); 
 
      } 
 
     } 
 
     }); 
 
    } 
 
    } 
 

 
    function FetchVariant() { 
 
    // Noop/not provided in question 
 
    } 
 
} 
 

 
ko.applyBindings(new DDLViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 

 
<select data-bind="value: selectedDim1"> 
 
    <option selected="selected" value="">Select Colour</option> 
 
    <option value="Black">Colour:Black</option> 
 
    <option value="NAVYBLUE">Colour:Navy Blue</option> 
 
</select> 
 

 
<select data-bind="value: selectedDim2, options: ddlDim2, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Waist Size'"></select> 
 

 
<select data-bind="value: selectedDim3, options: ddlDim3, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Leg Length'"></select>

+0

非常感謝 - 我扯下一些代碼從一個jQuery版本我的工作因此混搭 - 它似乎工作,但我需要做的第一下拉相同 - 如果只有一次選擇,選擇它並填充下拉2 - 但是,這是由MVC視圖模型預先填充 - 我應該交換工作與其他2次下降相同的方式?如果是這樣,我可以強制頁面加載時?這是否也會級聯下來,如果1,2和3只有一個選擇,他們都會被填滿? – chilluk

+0

另外我創建了我的FetchVariant()函數,但是我不能爲我的生活訪問所得到的數據 - 我是否必須將observableArray映射到另一個模型以便能夠在整個頁面中使用它? – chilluk

+0

你問的是非常廣泛的後續問題。我建議爲每個單獨的案例詢問一個新的Stack Overflow問題,包括每個問題的簡化示例。另外,您可能需要一位朋友或同事幫助思考設計。另外,如果你還沒有,請查看KnockoutJS教程。 (通過KnockoutJS將客戶端MVVM與服務器端預填充選擇框混合在一起可能是一個多毛的主題...) – Jeroen