knockout.jscustom-bindingscriptbundle

Custom Binding triggers error with Script Bundle in Production


I have the following KnockoutJS custom binding:

ko.bindingHandlers.dtp = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        //initialise datetimepicker with some optional options
        var options = allBindingsAccessor().dtpOptions || {};
        $(element).datetimepicker(options);  //ERROR HAPPENS HERE IN PRODUCTION

        //when a user changes the date, update the view model
        ko.utils.registerEventHandler(element, "changeDate", function (event) {
            var value = valueAccessor();
            if (ko.isObservable(value)) {
                value(event.localDate);
            }
        });
    },
    update: function (element, valueAccessor) {
        var widget = $(element).data("datetimepicker");
        //when the view model is updated, update the widget
        if (widget) {
            widget.setLocalDate(ko.utils.unwrapObservable(valueAccessor()));
            if (widget.date) {
                widget.setValue();
            }
        }
    }
};

This works fine when running in debug mode from Visual Studio. I have my "vendor" scripts bundled as follows:

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.IgnoreList.Clear();
    AddDefaultIgnorePatterns(bundles.IgnoreList);

    var cssTransformer = new CssTransformer();
    var nullOrderer = new NullOrderer();

    bundles.Add(
      new ScriptBundle("~/scripts/vendor")
        .Include("~/scripts/jquery-{version}.js")
        .Include("~/scripts/bootstrap.js")
        .Include("~/scripts/bootstrap-datetimepicker.min.js")
        .Include("~/scripts/knockout-{version}.js")
        .Include("~/scripts/ko-realtimevalue.js")
        .Include("~/scripts/ko-datetimepicker.js")
        .Include("~/scripts/sammy-{version}.js")
        .Include("~/scripts/moment.js")                
        .Include("~/scripts/Q.js")
        .Include("~/scripts/breeze.debug.js")  
        .Include("~/scripts/breeze.savequeuing.js")
        .Include("~/scripts/toastr.js")
        .Include("~/scripts/html5shiv.js")
        .Include("~/scripts/underscore.js")
        .Include("~/scripts/modernizr-{version}.js"));

    var styleBundle = new StyleBundle("~/Content/css")
        .Include("~/Content/ie10mobile.css")
        .Include("~/Content/less/bootstrap/bootstrap.less")
        .Include("~/Content/less/bootstrap/responsive.less")
        .Include("~/Content/less/bootstrap/bootstrap-datetimepicker.less")
        .Include("~/Content/font-awesome.min.css")
        .Include("~/Content/durandal.css")
        .Include("~/Content/less/toastr.less")
        .Include("~/Content/less/app.less");

    styleBundle.Transforms.Add(cssTransformer);
    styleBundle.Transforms.Add(new CssMinify());
    styleBundle.Orderer = nullOrderer;

    bundles.Add(styleBundle);
}

When I deploy to the server and therefore utilise the vendor script bundle I get an error as indicated above at the line: $(element).datetimepicker(options);. The error is:

Object [object Object] has no method 'datetimepicker'

I don't understand why this works in development but not in production. It seems that in production it cannot find the datetimepicker javascript.


Solution

  • Have you looked at the bundled vendor script file? When bundling fails it reports the error at the top of the bundled file.

    Also, I had a similar issue and found that bundling failed for toastr.js. If you remove that file from the bundle and add it regularly it might work.

    You can force bundling in development by adding BundleTable.EnableOptimizations = true; at the end of the RegisterBundles method.