Add Knockout Data Driven Table to Knockout Data Dr

2019-06-14 13:35发布

问题:

I am trying to create a sort of generic control that I want to use in my application. It will be a standard accordion (I Used Twitter Bootstrap for mine), this is dependent on JSON Data that I receive from the Server how many Accordion Sections will be created. In each accordion section I want to add a normal HTML table also built with JSON data acquired from the server. Everything will be running on client side accept for the initial post of the Ajax to obtain the JSON info. So I believe some sort of HTML Template is Required??

So this is what I have so far. JSON DATA:

 var data = {
        "d": [
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.AvailibleStock",
        "WarehouseID": 1,
        "ProductSKUID": 1,
        "ProductSKUName": "Decoder 1132",
        "WarehouseName": "SoftwareDevelopmentTest",
        "Status": "Staging",
        "QtyUnassigned": 10
    },
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.AvailibleStock",
        "WarehouseID": 1,
        "ProductSKUID": 2,
        "ProductSKUName": "Decoder 1131",
        "WarehouseName": "SoftwareDevelopmentTest",
        "Status": "Staging",
        "QtyUnassigned": 5
    }
]
    };

    var data2 = {
        "d": [
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
        "WarehouseID": 1,
        "ProductSKUID": 2,
        "LotID": 2,
        "LotName": "TestLot2",
        "AreaID": 8,
        "AreaName": "TestArea3L2",
        "BinID": 18,
        "BinName": "Area8Bin2"
    },
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
        "WarehouseID": 1,
        "ProductSKUID": 2,
        "LotID": 3,
        "LotName": "TestLot3",
        "AreaID": 11,
        "AreaName": "TestArea2L3",
        "BinID": 20,
        "BinName": "Area10Bin1"
    },
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
        "WarehouseID": 1,
        "ProductSKUID": 2,
        "LotID": 4,
        "LotName": "TestLot4",
        "AreaID": 15,
        "AreaName": "TestArea2L4",
        "BinID": 24,
        "BinName": "Area14Bin1"
    },
     {
         "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
         "WarehouseID": 1,
         "ProductSKUID": 1,
         "LotID": 2,
         "LotName": "TestLot2",
         "AreaID": 8,
         "AreaName": "TestArea3L2",
         "BinID": 18,
         "BinName": "Area8Bin2"
     },
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
        "WarehouseID": 1,
        "ProductSKUID": 1,
        "LotID": 3,
        "LotName": "TestLot3",
        "AreaID": 11,
        "AreaName": "TestArea2L3",
        "BinID": 20,
        "BinName": "Area10Bin1"
    },
    {
        "__type": "Warehouse.Tracntrace.Members_Only.DLL.StockMovement.StockReturnMethod",
        "WarehouseID": 1,
        "ProductSKUID": 1,
        "LotID": 4,
        "LotName": "TestLot4",
        "AreaID": 15,
        "AreaName": "TestArea2L4",
        "BinID": 24,
        "BinName": "Area14Bin1"
    }
]
    };

I just used 2 AJAX calls to get this from my server, and as you can see there is a similarity between the 2 data Sets (Both can be related to each Other With ProductSKUID and WarehouseID).

Next I have my KnockoutJS and Standard JQuery to build the functionality for the accordion by using the innerHTML methods to create the the accordion and to create the HTML Table within the accordion.

 var ProductViewmodel;
    //debugger; 

    //Binds ViewModel
    function bindProductModel(Products) {
        var self = this;
        self.items = ko.mapping.fromJS([]);
        ProductViewmodel = ko.mapping.fromJS(Products.d, self.items);
        console.log(ProductViewmodel());

    }

    //Binds First DataSet
    function bindModel(vm, data) {
        var self = this;
        vm.Locations = ko.mapping.fromJS(data.d);
        console.log(ProductViewmodel());
    }

    //Create Table In Accordion PANE based on Data
    //This Creates The Table in Each Accordion Pane
    function InjectBody() {
        var bodyContainer = document.getElementById('injectbody');
        var body = bodyContainer.innerHTML;
        body = body + '<table class="table table-striped"><thead><tr><th>#</th><th>Lot</th><th>Area</th><th>Bin</th><th>Qty To Assign</th></tr></thead><tbody data-bind="foreach: Locations"><tr><td id="Assign"><input type="checkbox" /></td><td id="Lot" data-bind="text: LotName"></td><td id="Area" data-bind="text: AreaName"></td><td id="Bin" data-bind="text: BinName"></td><td id="QtyToAssign"><input type="text" /></td></tr></tbody></table>';
        bodyContainer.innerHTML = body;
    }

    //Create Accordian Panes
    //This Creates The Hyperlink Based On JSON DATA
    function BuildLinkFromJSON() {
        var link;
        link = '<a data-bind="foreach: items" class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapse"><span data-bind="text: ProductSKUName"></span></a>';
        //This Creates The Table in Each Accordion Pane
        InjectBody();
        return link;
    }

    //Create Accordian Header
    //This Creates Each Header in the Accordian
    function BuildAccordian() {
        //This Creates The Hyperlink Based On JSON DATA
        var link = BuildLinkFromJSON();
        var eventsContainer = document.getElementById('accordion');
        var events = eventsContainer.innerHTML;
        events = events + '<div class="accordion-group"><div class="accordion-heading">' + link + '</div><div id="collapseOne" class="accordion-body collapse in"><div class="accordion-inner"><div id="injectbody"></div></div></div>';
        eventsContainer.innerHTML = events;
    }


    //Starting Function
    //This Creates the ProductViewModel Binding of both DataSets
    $(document).ready(function () {
        bindProductModel(data);
        bindModel(ProductViewmodel()[0], data2);
        ko.applyBindings(ProductViewmodel);

    })

Well it seems to fail completely, and I am unsure of what to do to fix it... I have created this Fiddle but no output is even given. Any help will be greatly appreciated!!

回答1:

When I do custom "controls" for KO I use a string template source and write the HTML inside the script for the "control". You can check out my work in progress KO Combobox for how you can do it

https://github.com/AndersMalmgren/Knockout.Combobox/blob/master/src/knockout.combobox.js

Check out the template part

//string template source engine
var stringTemplateSource = function (template) {
    this.template = template;
};

stringTemplateSource.prototype.text = function () {
    return this.template;
};

var stringTemplateEngine = new ko.nativeTemplateEngine();
stringTemplateEngine.makeTemplateSource = function (template) {
    return new stringTemplateSource(template);
};

var template= '<div data-bind="with: model">\
   <span data-bind="text: data"></span>\
</div>';

And to apply the template from a custom binding

ko.bindingHandlers.myBinding = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var model = new MyBindingViewModel(valueAccessor());
        ko.renderTemplate(template, bindingContext.createChildContext(model), { templateEngine: stringTemplateEngine }, element, "replaceChildren");

        return { controlsDescendantBindings: true };
    }
};

You can now use your custom binding like a normal binding from your views

<div data-bind="myBinding: model"></div>