Knockoutjs:复选框列出了多对多关系

时间:2017-04-26 11:01:02

标签: javascript knockout.js

我在下面的代码段中创建了一个Knockout模型。

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

我在第一个选项组中默认了我想要的输出数据,但我不确定如何使其工作。

我不确定我是否会采用这种正确的方式,并希望一些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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分: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>