5

I'm using Webpack Encore with Symfony 3.4 (part of migration to Symfony 4).

I have Datatables (installed via NPM to node_modules) working with jQuery but the api functions such as .columns are returning: .column is not a function at

Package Versions:

  • jQuery 2.14.4
  • Datatables 1.10.19
  • Webpack Encore 0.27.0

Webpack app.js:

global.$ = global.jQuery = require('jquery');
require('bootstrap');
global.moment = require('moment');
require('datatables.net-dt');
$.fn.dataTable = $.fn.DataTable = global.DataTable = require('datatables.net');

webpack.config.js:

var Encore = require('@symfony/webpack-encore');

Encore
// directory where compiled assets will be stored
    .setOutputPath('code/web/build/')
    // public path used by the web server to access the output path
    .setPublicPath('/build')
    // only needed for CDN's or sub-directory deploy
    //.setManifestKeyPrefix('build/')

    .addEntry('site', './assets/js/site/app.js')

    // will require an extra script tag for runtime.js
    // but, you probably want this, unless you're building a single-page app
    .enableSingleRuntimeChunk()

    .cleanupOutputBeforeBuild()
    .enableSourceMaps(!Encore.isProduction())
    // enables hashed filenames (e.g. app.abc123.css)
    .enableVersioning(Encore.isProduction())

// uncomment if you use TypeScript
//.enableTypeScriptLoader()

// uncomment if you use Sass/SCSS files
//.enableSassLoader()

// uncomment if you're having problems with a jQuery plugin
//.autoProvidejQuery()
;

module.exports = Encore.getWebpackConfig();

Javascript example in template.html.twig (extends base html file):

{{ encore_entry_script_tags('site') }}

<script type="text/javascript">
$(document).ready(function() {
    var $dtable;

    $dtable = $('#simpleTable')
                        .DataTable({
                            data: data,
                            deferRender: true,
                            scrollX: false,
                            searching: true,
                            paging: true,
                            pageLength: 25});

    console.log($dtable);

    // Error occurs here
    var column = $dtable.column(index);
});
</script>

A console log of $dtable immediately after instantiation outputs the following which seems to confirm an Api instance isn't created?

dtable instance

Is it possible this is related to the DataTable loader that uses the AMD method due to Webpack?

jquery.dataTables.js:

(function( factory ) {
    "use strict";
    if ( typeof define === 'function' && define.amd ) {
        define( ['jquery'], function ( $ ) {
            return factory( $, window, document );
        } );
    }
    else if ( typeof exports === 'object' ) {
        module.exports = function (root, $) {
            if ( ! root ) {
                // CommonJS environments without a window global must pass a
                // root. This will give an error otherwise
                root = window;
            }
            if ( ! $ ) {
                $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
                    require('jquery') :
                    require('jquery')( root );
            }
            return factory( $, root, root.document );
        };
    }
    else {
        factory( jQuery, window, document );
    }
}
0

4 Answers 4

5
+100

The AMD loader may be a problem here,

Can you try to disable AMD Loader it to see if it work :

var config = Encore.getWebpackConfig();

config.module.rules.unshift({
  parser: {
    amd: false,
  }
});

module.exports = config;

Otherwise you could try to make it work with AMD Loader : First install DataTables :

npm install datatables.net

Then DataTables style (bootstrap) :

npm install datatables.net-bs

Then the imports-loader plugin

Modify your webpack.config.js to make an exception for datatables:

module: {
  loaders: [
      {
          test: /datatables\.net.*/,
          loader: 'imports?define=>false'
      }
  ]
}

Now you should be able to use DataTables :

import 'datatables.net';
import dt from 'datatables.net-bs';
dt(window, $);


//And now use it
$('#exampleDatatable').DataTable();
Sign up to request clarification or add additional context in comments.

Comments

0

The issue I see is with line:

$.fn.dataTable = $.fn.DataTable = global.DataTable = require('datatables.net');

dataTable() and DataTable() are not equivalent.

The correct functions will be added to Jquery by the factory, no need to set these. Actually, if I can guess, the above code will overwrite DataTable() with dataTable().

Change to:

require('datatables.net');

It should work.

2 Comments

If you remove the above you get Datatable is an undefined function errors, if only it were that simple
@Dan, hm, this "global" variable I am not sure how it is used. You could try require('datatables.net')(global, global.$); to force the factory to use these variables...
0

Maybe it's a stupid idea ... but what is the data value in your template-defined call $('#simpleTable').DataTable({data:data, ...}) call?

According to docs (3rd paragraph) setting the data option (even with an empty value) will override the data from the table. If your value data is undefined, this might turn your data-rich table into a vegetable in the eyes of DataTable.

I assume that your table is fine, the module is loaded fine, ... so the data might be the problem ...

If, however, it does contain useful data, would you mind posting some example of it? ;o)

Comments

0

The DataTables documentation for using with NPM show that the export is a function that returns the DataTable API.

var dt = require( 'datatables.net' )(); // N.b. the extra parenthesis.

So it's likely you'd need to alter your global assignment; something like this might work:

$.fn.dataTable = $.fn.DataTable = global.DataTable = require('datatables.net')(); // N.b. the extra parentheses.

1 Comment

You might also need to be careful of other jQuery plugin libraries attaching themselves to their own instance of jQuery. The Webpack Encore docs have a good page covering how to share jQuery throughout the entire build context.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.