下拉列表的多个实例:使用子可观察对象进行处理

时间:2013-10-24 10:29:39

标签: knockout.js

我有一个这样的视图模型:

var Jobs = [
    { "Id": "J01", "Value": "description1" }, 
    { "Id": "J02", "Value": "description2" }, 
    { "Id": "J03", "Value": "description3" }
]

var Tasks = []

var Line = function (obj) {
    var self = this;
    self.Job    =   ko.observable(obj.JobId)
    self.Task   =   ko.observable(obj.TaskId)

    self.Job.subscribe(function () {
        /*
        Here i want to run ajax and fetch tasks for that 
        job and i assume this should work for related tasks dropdown only
        */
    });
}

function ViewModel() {
    var self = this
    self.Timesheet = ko.observable()
    self.LoadData = function () {

        var data = {
            "timesheet": {
                "ApprovalStatus": 1,
                "Description": "Timesheet",
                "PeriodFrom": "2013-09-01",
                "PeriodTo": "2013-09-15",
                "RecId": "1",
                "Lines": [{
                    "DestinationRecId": "D01",
                    "LaborCategoryRecId": "C01",
                    "PayTypeRecId": "PAY-01",
                    "ProjectRecId": "J01",
                    "ProjectWBSRecId": "J01-T01",
                    "RecId": "1"

                }, {
                    "DestinationRecId": "D02",
                    "LaborCategoryRecId": "C01",
                    "PayTypeRecId": "PAY-02",
                    "ProjectRecId": "J02",
                    "ProjectWBSRecId": "J02-T01",
                    "RecId": "2"
                }
            }
        }   

        self.Timesheet(data.timesheet)

        for (var i = 0; i < data.timesheet.Lines.length; i++) {
            var line = self.Timesheet().Lines[i]
            var obj =   {
                JobId           :   line.ProjectRecId,
                TaskId          :   line.ProjectWBSRecId
            }
            /*  Here i am adding property SelectedItem and 
            * in it assigning a child object
            */
            self.Timesheet().Lines[i].SelectedItem      =   new Line(obj)
            console.log(self.Timesheet().Lines[i])
        }   
    }

    self.LoadData()
}

以下是相应的观点:

<table>
    <thead>
        <tr>
            <th>Job </th>
            <th>Job WBS</th>
        </tr>
    </thead>    
    <tbody id="lines" data-bind="foreach:Timesheet().Lines">
    <tr>
        <td>
            <select 
                data-bind="
                options: Jobs,  
                optionsText: 'Value', 
                optionsValue: 'Id',
                optionsCaption: 'Select Job',
                value : $data.ProjectRecId
                "
                class="m-wrap">
                <!-- $data.ProjectRecId $data.SelectedItem.Job-->
            </select>
        </td>
        <td data-bind="with: Jobs">
            <select
                data-bind="
                options: Tasks, 
                optionsText: 'Value', 
                optionsValue: 'Id', 
                value : $data.ProjectWBSRecId,
                optionsCaption: 'Select Task'
                "
                class="m-wrap">
            </select>
        </td>
    </tr>
    </tbody>
</table>

问题在于,当我使用$data.SelectedItem.Job时,它表示SelectedItem未定义 使用$data.ProjectRecId可以正常工作。目标是实现“Knockout Dependent Dropdowns Handling”之类的内容。

我想单独处理下拉菜单,但我没有做到这一点。

输出:

enter image description here

1 个答案:

答案 0 :(得分:1)

查看my implementation

基本上我使用Note 3: Using “as” to give an alias to “foreach” items来允许直接连接到self.Timesheet().Lines[i].SelectedItem,这反过来又允许我为JobTask使用每个相应value binding的观察值}}

通过使用函数调用替换“任务”组合框的options绑定,您可以根据该行的选定“作业”加载自定义值。如果self.Task = ko.observable(obj.TaskId)设置的原始值存在于函数返回的选项中,则将选择/显示该值。

实现与您提供的教程不完全相同,因为该示例中使用的viewmodel的结构与您提供的data对象的结构完全不同。我将Jobs移动到他们自己的属性中,并假设您可以在遍历行时单独查询/构建该数据。否则,数据需要以这样的方式构造,即它将1个Job与多个任务相关联,而不是将Job / Task对彼此相关联。如果要更改数据结构,那么可以实现与所提供的示例更紧密相关的实现。

<强> HTML

<button data-bind="click:printLines">Print Lines</button>
  <table>
     <thead>
      <tr>
        <th>Job </th>
        <th>Job WBS</th>
      </tr>
     </thead>    
     <tbody id="lines" data-bind="foreach: {data: Timesheet().Lines, as: 'line'}">
      <tr>
       <td>
        <select 
            data-bind="
            options: $root.Jobs,  
            optionsText: 'Value', 
            optionsValue: 'Id',
            optionsCaption: 'Select Job',
            value : line.SelectedItem.Job
            "
            class="m-wrap">
            <!-- $data.ProjectRecId $data.SelectedItem.Job-->
        </select>
       </td>
       <td data-bind="with: line.SelectedItem.Job">
        <select
            data-bind="
            options: $root.getAvailableTasks(line.SelectedItem.Job), 
            optionsText: 'Value', 
            optionsValue: 'Id', 
            value : line.SelectedItem.Task,
            optionsCaption: 'Select Task'
            "
            class="m-wrap">
        </select>
       </td>
      </tr>
     </tbody>
 </table>

<强>的Javascript

var Line = function (obj) {
  var self = this;
  self.Job    =   ko.observable(obj.JobId)
  self.Task   =   ko.observable(obj.TaskId)

  self.Job.subscribe(function () {
    /*
    Here i want to run ajax and fetch tasks for that 
    job and i assume this should work for related tasks dropdown only
    */
  });
}

function ViewModel() {
  var self = this;
  self.Jobs = ko.observableArray([
                                 { "Id": "J01", "Value": "description1" }, 
                                 { "Id": "J02", "Value": "description2" }, 
                                 { "Id": "J03", "Value": "description3" }
                                 ]);

  self.formattedData = ko.observableArray([]);

  self.Timesheet = ko.observable()
  self.LoadData = function () {

    var data = {
        "timesheet": {
            "ApprovalStatus": 1,
            "Description": "Timesheet",
            "PeriodFrom": "2013-09-01",
            "PeriodTo": "2013-09-15",
            "RecId": "1",
            "Lines": [{
                "DestinationRecId": "D01",
                "LaborCategoryRecId": "C01",
                "PayTypeRecId": "PAY-01",
                "ProjectRecId": "J01",
                "ProjectWBSRecId": "J01-T01",
                "RecId": "1"

            }, {
                "DestinationRecId": "D02",
                "LaborCategoryRecId": "C01",
                "PayTypeRecId": "PAY-02",
                "ProjectRecId": "J02",
                "ProjectWBSRecId": "J02-T01",
                "RecId": "2"
            }]
        }
    }   


    self.Timesheet(data.timesheet)

    for (var i = 0; i < data.timesheet.Lines.length; i++) {
        var line = self.Timesheet().Lines[i]
        var obj =   {
            JobId           :   line.ProjectRecId,
            TaskId          :   line.ProjectWBSRecId
        }
        /*  Here i am adding property SelectedItem and 
        * in it assigning a child object
        */

        line.SelectedItem      =   new Line(obj);   
    }   
}
self.printLines = function() {
  for (var i = 0; i < self.Timesheet().Lines.length; i++) {
      var selectedItem = self.Timesheet().Lines[i].SelectedItem;
      console.log('Job: ' + selectedItem.Job() + " Task: " + selectedItem.Task());
  }
}

self.getAvailableTasks=function(selectedJob) {

    //your ajax would move here
    if("J01" == selectedJob()){
        return  ko.observableArray([{"Id": "J01-T01", "Value": "TaskJ01-T01Value"},
                                {"Id": "J01Task02", "Value": "Task02Value"}]);
    }
    else {
      return  ko.observableArray([{"Id": "DefaultTask01", "Value": "Task01Value"},
                                {"Id": "DefaultTask02", "Value": "Task02Value"}]);
    }
 }

 self.LoadData()
}

ko.applyBindings(new ViewModel())