Search code examples
knockout.jsrequirejsknockout-amd-helpers

RequireJS Knockout Amd-Helper


I'm struggling with arranging my code using requireJS and will appreciate any help.

I have a dashboard.html which gets bound to the 'dashboard' viewmodel in dashboard-init.js. The dashboard viewmodel has a list of Panels that get shown as a list in dashboard.html.

After the render completes, I invoke the gridList function to convert the list into a dashboard.

Please note that this works correctly if I simply include these scripts in the html using script src=... etc.

But when I removed the script tags and pushed these dependencies to dashboard viewmodel, I get this error:

Uncaught Error: Unable to process binding "foreach: function (){return { data:Panels,afterRender:postRender} }" Message: GridList lib required

What do I need to do to satisfy the GridList lib requirement?

Here is the page that is giving this error (dashboard.html):

<html>
<head>
    <link rel="stylesheet" href="css/style.css" />
</head>
<body>
    <div class="grid-container">
        <ul id="grid" class="grid" data-bind="foreach: { data: Panels, afterRender: postRender }">
            <li ...">
                ...
            </li>            
        </ul>
    </div>
    <script src="Scripts/require.js"></script>
    <script src="viewmodels/common-init.js"></script>
    <script src="viewmodels/dashboard-init.js"></script>

</body>

This is what common-init looks like:

requirejs.config({
baseUrl: "../Scripts",
paths: {
    "jquery": "jquery-2.0.3.min",
    "jqueryui": "jquery-ui-1.11.4.min",
    "knockout": "knockout-3.3.0",
    "knockout-amd-helpers": "knockout-amd-helpers",
    "text": "text"
},
shim: {
    'gridList': ['jquery'],
    'jquery.gridList': ['jquery','gridList']
}

});

Here is dashboard-init

require(["knockout", "../viewmodels/modules/dashboard", "knockout-amd-helpers", "text"], function (ko, dashboard) {

ko.amdTemplateEngine.defaultPath = "../templates";

ko.bindingHandlers.module.baseDir = "modules";

ko.bindingHandlers.module.templateProperty = "embeddedTemplate";

setTimeout(function () {
    ko.applyBindings(new dashboard());
}, 0);

});

Finally, here is the dashboard module:

define(["knockout", "jquery", "jqueryui", "gridList", "jquery.gridList"], function (ko) {
return function () {
    var self = this;

    self.Panels = [{...}, {...}];

    self.postRender = function(elements, data) {
        if (this.foreach[this.foreach.length - 1] === data) {
            $('#grid').gridList({
                rows: 3,
                widthHeightRatio: 264 / 294,
                heightToFontSizeRatio: 0.25
            });
        }
    }
};

});

Also, I don't like the fact that I need to refer to #grid inside the viewmodel but do not know any better. Any advice would help.

Thanks


Solution

  • I haven't used the gridList that you are working with, but I see that they have a check for window.GridList that is throwing the error that you are seeing. In an AMD setting, it is not exposed on the window. They should check that the GridList from their dependency is there instead.

    You can work around this by doing:

    define(["knockout", "jquery", "gridList", "jqueryui", "jquery.gridList"], function (ko, $, GridList) {
            window.GridList = GridList;
    
            // your other code
        });
    

    As far as accessing the #grid element, you could access any of the elements parentNode instead or better consider using a custom binding on the parent element that actually initializes the GridList.