2017-04-26 58 views
0

我在下面的代码段中创建了Knockout模型。Knockoutjs:复选框列表多对多关系

我想要做的是在弹出对话框中创建一个多对多的关系,从选项行添加到选项(我希望这有助于你看看jsfiddler)。当您单击行上的子列的查找链接时,我会列出对话框中的所有选项行和复选框列表,并允许用户选择到特定行的子关系,因此多对多行之间的关系。

我已经默认了第一个选项组中输出的数据,但我不确定如何使这项工作。

我不确定我是否正在讨论这个正确的方法,并希望有一些Knockout专家可以指出我在正确的方向在弹出窗口中获得此功能。

/*Select Options*/ 
 
var initialData = [{ 
 
    title: "User Band", 
 
    productoptionrows: [{ 
 
     id: "1", 
 
     title: "25-100", 
 
     related: [{ 
 
      id: "4", 
 
      title: '1 Year' 
 
     }, { 
 
      id: "5", 
 
      title: '2 Year' 
 
     }, { 
 
      id: "6", 
 
      title: '3 Year' 
 
     }] 
 
    }, { 
 
     id: "2", 
 
     title: "101-250", 
 
     related: [{ 
 
      id: "7", 
 
      title: '1 Year' 
 
     }, { 
 
      id: "8", 
 
      title: '2 Year' 
 
     }, { 
 
      id: "9", 
 
      title: 'qwe' 
 
     }] 
 
    }, { 
 
     id: "3", 
 
     title: "251-500", 
 
     related: [{ 
 
      id: "10", 
 
      title: '1 Year' 
 
     }, { 
 
      id: "11", 
 
      title: '2 Year' 
 
     }, { 
 
      id: "12", 
 
      title: '3 Year' 
 
     }] 
 
    }] 
 
}, { 
 
    title: "Please select the number of years license", 
 
    productoptionrows: [{ 
 
     id: "4", 
 
     title: "1 Year", 
 
     related: [] 
 
    }, { 
 
     id: "5", 
 
     title: "2 Year", 
 
     related: [] 
 
    }, { 
 
     id: "6", 
 
     title: "3 Year", 
 
     related: [] 
 
    }, { 
 
     id: "7", 
 
     title: "1 Year", 
 
     related: [] 
 
    }, { 
 
     id: "8", 
 
     title: "2 Year", 
 
     related: [] 
 
    }, { 
 
     id: "9", 
 
     title: "3 Year", 
 
     related: [] 
 
    }, { 
 
     id: "10", 
 
     title: "1 Year", 
 
     related: [] 
 
    }, { 
 
     id: "11", 
 
     title: "2 Year", 
 
     related: [] 
 
    }, { 
 
     id: "12", 
 
     title: "3 Year", 
 
     related: [] 
 
    }] 
 
}]; 
 

 

 
$(document).ready(function() { 
 
    /*Models*/ 
 
    var mappingOptions = { 
 
     'productoptionrows': { 
 
      create: function (options) { 
 
       return new productoptionrow(options.data); 
 
      } 
 
     } 
 
    }; 
 
    var mappingOptionsPR = { 
 
     create: function (options) { 
 
      return new productoptionrow(options.data); 
 
     } 
 
    }; 
 
    var productoptionrow = function (por) { 
 
     var self = ko.mapping.fromJS(por, {}, this); 
 
     self.relatedcsv = ko.computed(function() { 
 
      return $(por.related).map(function() { 
 
       return this.id; 
 
      }).get().join(','); 
 
     }, self); 
 
     self.selectedrelated = ko.observableArray($(por.related).map(function() { 
 
      return this.id; 
 
     }).get()); 
 
    }; 
 
    var ProductOptionModel = function (data) { 
 
     var self = this; 
 
     self.productoptions = ko.mapping.fromJS(data, mappingOptions); 
 
     self.isOpen = ko.observable(false); 
 
     self.selectedrelated = ko.observableArray([]); 
 
     /*Control Events*/ 
 
     self.addProductOption = function() { 
 
      var newoption = ko.mapping.fromJS({ 
 
       title: "Please select the number of years license", 
 
       productoptionrows: ko.observableArray([{ 
 
        id: "15", 
 
        title: "25-100", 
 
        related: [] 
 
       }, { 
 
        id: "16", 
 
        title: "101-250", 
 
        related: [] 
 
       }, { 
 
        id: "17", 
 
        title: "251-500", 
 
        related: [] 
 
       }]) 
 
      }, mappingOptions); 
 
      self.productoptions.push(newoption); 
 
     }; 
 
     self.copyProductOption = function (productoption) { 
 
      var copy = ko.mapping.fromJS(ko.mapping.toJS(productoption), mappingOptions); 
 
      self.productoptions.push(copy); 
 
     }; 
 
     self.removeProductOption = function (productoption) { 
 
      self.productoptions.remove(productoption); 
 
     }; 
 
     self.addProductOptionRow = function (productoption) { 
 
      var newrow = ko.mapping.fromJS({ 
 
       id: "15", 
 
       title: "25-100", 
 
       related: [] 
 
      }, mappingOptionsPR); 
 
      productoption.productoptionrows.push(newrow); 
 
     }; 
 
     self.removeProductOptionRow = function (productoption) { 
 
      $.each(self.productoptions(), function() { 
 
       this.productoptionrows.remove(productoption) 
 
      }) 
 
     }; 
 
     self.open = function (productoption, event) { 
 
      self.selectedrelated(productoption.related); 
 
      self.isOpen(true); 
 
     }; 
 
     self.close = function() { 
 
      self.isOpen(false); 
 
     } 
 
     self.associaterelated = function (record, elem) { 
 
      //console.log(ko.mapping.toJS(record)); 
 
     } 
 
    }; 
 
    ko.applyBindings(new ProductOptionModel(initialData), document.getElementById('page-wrapper')); 
 

 
});
<link href="https://code.jquery.com/ui/1.12.1/themes/ui-lightness/jquery-ui.css" rel="stylesheet" /> 
 
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> 
 
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script> 
 
<script src="https://cdn.rawgit.com/gvas/knockout-jqueryui/075b303a/dist/knockout-jqueryui.min.js"></script> 
 

 
<div id="page-wrapper"> 
 
    <div> 
 
    <button title="Add Option" type="button" data-bind='click: $root.addProductOption'>Add Option</button> 
 
    </div> 
 
    <div id="options" data-bind="foreach: productoptions"> 
 
    <div style="padding:10px;margin:20px;background-color:whitesmoke"> 
 
     <table class="option-header" cellpadding="0" cellspacing="0"> 
 
     <thead> 
 
      <tr> 
 
      <th>Group Title <span class="required">*</span></th> 
 
      <th> 
 
       <button title="Copy" type="button" class="" style="" data-bind='click: $root.copyProductOption'>Copy</button> &nbsp;&nbsp; 
 
       <button title="Delete Option" type="button" data-bind='click: $root.removeProductOption'>Delete Option</button> 
 
      </th> 
 
      </tr> 
 
     </thead> 
 
     <tbody> 
 
      <tr style="height:36px;"> 
 
      <td> 
 
       <input type="text" data-bind='value: title'> 
 
      </td> 
 
      <td> 
 

 
      </td> 
 
      </tr> 
 
     </tbody> 
 
     </table> 
 
     <div> 
 
     <table class="option-header-rows" cellpadding="0" cellspacing="0"> 
 
      <thead> 
 
      <tr class="headings"> 
 
       <th>Id</th> 
 
       <th colspan="2" class="type-title">Title <span class="required">*</span></th>   
 
       <th>Children</th> 
 
       <th></th> 
 
      </tr> 
 
      </thead> 
 
      <tbody data-bind="foreach: productoptionrows"> 
 
      <tr> 
 
       <td align="center"> 
 
       <input required type="text" style="width:40px" data-bind='value: id'> 
 
       </td> 
 
       <td colspan="2"> 
 
       <input type="text" value="25-100" data-bind='value: title'> 
 
       </td> 
 
       <td> 
 
       <input type="text" data-bind='value: relatedcsv' name="isdefault"><a href="#" data-bind="click: $root.open, disable: $root.isOpen">Lookup</a></td> 
 
       <td> 
 
       <button title="Delete Row" type="button" data-bind='click: $root.removeProductOptionRow'>Delete Row</button> 
 
       </td> 
 
      </tr> 
 
      </tbody> 
 
      <tfoot> 
 
      <tr> 
 
       <td align="right"> 
 
       <button title="Add New Row" type="button" data-bind='click: $root.addProductOptionRow'>Add New Row</button> 
 
       </td> 
 
      </tr> 
 
      </tfoot> 
 
     </table> 
 
     </div> 
 
    </div> 
 
    </div> 
 
    <!-- popup --> 
 
    <div data-bind="dialog: { isOpen: isOpen,title:'Select relations', modal:true }"> 
 
    <div data-bind="foreach: $root.productoptions"> 
 
     <div data-bind='text: title'></div> 
 
     <div data-bind="foreach: productoptionrows"> 
 
     <div> 
 
      <input type="checkbox" data-bind="value: id, checked: $root.selectedrelated" style="width:auto" /> 
 
      ID <span data-bind='text: id'></span> - <span data-bind='text: title'></span> 
 
     </div> 
 
     </div> 
 
    </div> 
 
    </div> 
 
    <pre data-bind="text: ko.toJSON($data, null, 2)"></pre> 
 
</div>

+0

这并不完全清楚,我弹出应该做的事情。将选中的许可证添加到所有选中的用户乐团?还是仅限于您点击的那个?您可能需要删除一些数据和附加属性,以便我们可以专注于无法工作的部分... – user3297291

+0

@ user3297291即时消息尝试要做的是将年份选项与每个用户乐队相关联,具有默认期望的每个用户频带的输出以及年份选项的对应ID。例如 例如。 用户带25-100用户应该能够检查ID 4,5,6 用户带101-250用户应该能够检查ID 7,8,9 用户带251-500用户应该能够检查ID 10 ,11,12 然后在每个用户带的子文本框中,您可以看到相应年份的ID。 当我点击一个用户乐队弹出窗口时,我会预计年份选项已经如上所述 – user363727

+0

这些组的意义是什么?看起来他们都是以同样的方式创建的。一个组中的任何项目是否可以映射到任何其他组中的任何项目?项目能映射到它自己的组中的项目吗?它可以映射到自己吗?如果项目A映射到项目B,这是否意味着项目B也映射到项目A? –

回答

0

我试图提炼出许多对许多问题降低到一个简单的例子。在这里,人与事物相互映射。为了跟踪映射,每个人都有一个事物清单。对于每一个可能的事情,都有一个带有该值的复选框。它的checked绑定绑定到当前人的thingList。

绑定到一个数组使得复选框插入或从数组中删除它的值。

function person(name) { 
 
    return { 
 
    name, 
 
    thingList: ko.observableArray() 
 
    }; 
 
} 
 

 
const vm = { 
 
    people: ko.observableArray(['Abby', 'Bill', 'Charlie'].map((n) => person(n))), 
 
    things: ko.observableArray(['apple', 'bullet', 'cup', 'doll', 'egg']) 
 
}; 
 

 
ko.applyBindings(vm);
.checklist { 
 
    display: inline-block; 
 
} 
 

 
.no-bullets { 
 
    list-style-type: none; 
 
} 
 

 
.no-bullets li { 
 
    display: inline; 
 
    padding-right: 15px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 
<div data-bind="foreach:people"> 
 
    <div>Name: <span data-bind="text:name"></span> 
 
    <div class="checklist" data-bind="foreach:$parent.things"> 
 
     <label><input type="checkbox" data-bind="value:$data, checked:$parent.thingList"><span data-bind="text:$data"></span></label> 
 
    </div> 
 
    <ul class="no-bullets" data-bind="foreach:thingList"><li data-bind="text:$data"></li></ul> 
 
    </div> 
 
</div>

+0

Hi Roy, 感谢您发布关于如何处理多对多关系的更新。 我遇到的问题是如何做一个自我引用多对多的关系。我减少了我原来的例子,但我无法得到这个工作。 – user363727