Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage with Require JS #829

Closed
skoch opened this issue Feb 24, 2015 · 12 comments
Closed

Usage with Require JS #829

skoch opened this issue Feb 24, 2015 · 12 comments

Comments

@skoch
Copy link

skoch commented Feb 24, 2015

I'm using tablesorter within a project built using require.js and I can get everything to work fine in develop mode however when I attempt to build my project (minimizing JS) I'm consistently getting an error that addWidget is not a function. Below are my apps main entry point as well as the build file (with code removed for brevity.)

Has anyone attempted to build a project using require.js and succeeded?

main.js

require.config({
  baseUrl: 'js/lib',
  ...
  paths: {
    jquery: 'jquery-1.11.1.min',
    ...
    tablesorter: 'jquery.tablesorter',
    tablesorterWidgets: 'jquery.tablesorter.widgets'
  },
  shim: {
    ...
    tablesorter: ['jquery'],
    tablesorterWidgets: ['jquery']
  }
});


require(
  [
    ...
    'jquery',
    'tablesorter',
    'tablesorterWidgets'
  ]
  function( $ )
  {...}
);

build.js

({
  baseUrl: '.',
  paths: {
    jquery: 'lib/jquery-1.11.1.min',
    ...
    tablesorter: 'lib/jquery.tablesorter',
    tablesorterWidgets: 'lib/jquery.tablesorter.widgets'
  },
  name: "main",
  out: "main-built.js"
})

The usage from within one of my components uses the following code:

$( "#test-sortable" ).tablesorter({
  theme : "bootstrap",
  widthFixed: true,
  headerTemplate : '{content} {icon}',
  widgets : [ "uitheme", "zebra" ],
});

Console error

Uncaught TypeError: undefined is not a function

And the cursor is clearly at t.addWidget({id:"uitheme"... from the built JS file.

@Mottie
Copy link
Owner

Mottie commented Feb 24, 2015

Hi @skoch!

I haven't used Require JS, but I wonder if the problem is because the widget code isn't wrapped as an AMD module. Try wrapping the widget code in this:

Replace the first line

;(function ($, window, document) {

with this

(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}(function($, window, document) {

and replace this at the end of the file:

})(jQuery);

with this:

    return ts;
}));

If that fixes the issue, please tell me... I'll need to include that in the build script, and I might end up wrapping every widget individually.

nburlett added a commit to nburlett/tablesorter that referenced this issue Mar 10, 2015
Fixes upstream issue Mottie#829

Update Gruntfile.js to wrap the whole `jquery.tablesorter.widgets.js`
file in a requirejs-compatible factory.
@nburlett
Copy link
Contributor

I ran into this same problem. The suggested fix is close to what's needed, but 'ts' is not actually in scope, so I've used a slightly different footer:

  return $.tablesorter;
}));

This fixes the issue for me, so I've filed a pull request.

@Mottie
Copy link
Owner

Mottie commented Mar 10, 2015

@nburlett Thanks, I did have to remove the window and document parameters because with them included, I was getting undefined errors.

ts should be the same as $.tablesorter, so I'm not sure why it wouldn't be in scope.

@Mottie
Copy link
Owner

Mottie commented Mar 10, 2015

I just pushed v2.21.1 which adds a UMD wrapper to the "jquery.tablesorter.widgets.js" file.

The separate widget files are not wrapped, but I'll look into adding individual wrappers to each if it is needed.

@skoch
Copy link
Author

skoch commented Mar 13, 2015

@Mottie 👍

Apologies for not getting back to you sooner but happy to report that v2.21.1 fixes the issue. (Client finally made a decision!)

Many thanks!

@skoch skoch closed this as completed Mar 13, 2015
@seemikehack
Copy link

I'm using v.2.21.1 of the built widgets file and I'm still seeing this issue, but only intermittently. The only widget I'm using is uitheme. I'm using jQuery v2.1.1, fyi.

@Mottie
Copy link
Owner

Mottie commented Mar 24, 2015

Hi @seemikehack!

Only the combined jquery.tablesorter.widgets.js file includes an UMD wrapper. That file contains the following widgets:

  • storage
  • uitheme
  • columns
  • filter
  • stickyHeaders
  • resizable
  • saveSort

If you only need the uitheme widget, then create a custom build.

I'll add an option to the custom build, so you can name the output file whatever you want.

@seemikehack
Copy link

I need the AMD wrapper, and was just using the built file out of convenience. The confusion came with the intermittent error: sometimes I would get it, sometimes not. I haven't gotten a reliable repro either, which is frustrating.

I will create a custom build and add my own AMD wrapper (since, assuming I read correctly, individual widgets don't include it) (kidding, it does include it) and go from there. Thanks for the prompt reply!

Update: still intermittently getting the error. Can post config files and usage if it'd help.

@Mottie
Copy link
Owner

Mottie commented Mar 25, 2015

What error?

Hmm, the parsers and "extras" code don't include a wrapper... maybe I can add a UMD wrapper to all minified files.

@seemikehack
Copy link

Sorry for not being very helpful :) I occasionally get Uncaught TypeError: undefined is not a function on page load at line 67 of a custom build only including the uithemes widget. Here's that unexciting config file, with more follow:

{
    "widgets" : "uitheme"
}

main.js:

require.config({
   baseUrl: 'scripts',
   paths: {
      // vendor libs
      ...
      'jquery': 'vendor/jquery',
      ...
      'tablesorter': 'vendor/jquery.tablesorter',
      // 'tablesorter-widgets': 'vendor/jquery.tablesorter.widgets',
      'tablesorter-widgets': 'vendor/jquery.tablesorter.custom-widgets',
      ...
   },
   shim: {
      'backbone': {
         deps: ['underscore', 'jquery'],
         exports: 'Backbone'
      },
      'underscore': {
         exports: '_'
      },
      ...
      'bootstrap': {
         deps: ['jquery'],
         exports: '$.fn.popover' // bootstrap doesn't export a global per se, so just check a module it does define
      }
   }
});

Some controller:

define(function (require) {
   var $                    = require('jquery'),
       _                    = require('underscore'),
       Backbone             = require('backbone');

   // force-load tablesorter jQuery plugin
   require('tablesorter');
   require('tablesorter-widgets');

   var Controller = Backbone.View.extend({
      ...
      render: function () {
         this.$el.html(this.template);

         // initialize table sorter (this.$el is a table)
         this.$el.tablesorter({
            theme          : 'bootstrap',
            headerTemplate : '{content} {icon}',
            widgets        : ['uitheme'],
            sortList       : [[1,'d']],

            headers: {
               '.no-sort' : {
                  sorter : false
               }
            }
         });

         return this;
      }
      ...
   });

   return Controller;
}

Stack trace:

Uncaught TypeError: undefined is not a function [jquery.tablesorter.custom-widgets.js:67]
(anonymous function)                            [jquery.tablesorter.custom-widgets.js:67]
(anonymous function)                            [jquery.tablesorter.custom-widgets.js:197]
context.execCb                                  [require.js:1658]
Module.check                                    [require.js:874]
Module.enable                                   [require.js:1151]
Module.init                                     [require.js:782]
callGetModule                                   [require.js:1178]
context.completeLoad                            [require.js:1552]
context.onScriptLoad                            [require.js:1679]

Where line 197 in the custom widgets file is })(jQuery); and line 67 is ts.addWidget({. Breaking on line 67 when ts.addWidget is undefined reveals that ts is an object like this:

ts: {
    themes: {
        bootstrap: {...},
        jui: {...}
    }
}

@Mottie
Copy link
Owner

Mottie commented Mar 25, 2015

I don't use requirejs, so I'm not familiar with it. I do have some questions, maybe this would work better if you could jump on our IRC channel - it's #tablesorter on freenode.net.

@Mottie
Copy link
Owner

Mottie commented Mar 25, 2015

It appears that the files are loading asynchronously... the widgets need to be added as a dependency of tablesorter. Please see #855 for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants