Rails 6 + Webpack、Datatables、jQuery

5

我有一个“全选”按钮,使用以下代码:

<script type='text/javascript'>
  $('#check_all').on("click", function() {
    $('input[type="checkbox"]').click();
  });
</script>

自从我升级到Rails 6 + Webpacker之后,它就停止工作了。 控制台显示以下错误:
Uncaught ReferenceError: $ is not defined

我通过修改environment.js文件来解决这个问题,将其从以下内容改为:

environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
  })
)

收件人:

environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: ['popper.js', 'default']
  })
)

但是,一旦这个问题得到解决,datatables 就会出故障。

你有什么想法让它们同时正常工作吗? 谢谢!


你的 environment.js 是正确的。哪一行代码导致了 ReferenceError?“全选”按钮的代码在哪里,它是如何被引入到 application.js 包中的? - Lyzard Kyng
1
@MaayanNaveh,你在app/views/layouts/application.html.erb中将javascript_include_tag更改为javascript_pack_tag了吗?我重复了你的代码,没有看到任何错误,并且复选框按预期被选中。 - Lyzard Kyng
@LyzardKyng 没错,我刚刚再次确认了一下,它是 <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> - Maayan Naveh
2
https://inopinatus.org/2019/09/14/webpacker-jquery-and-jquery-plugins/ - inopinatus
1
@inopinatus 很好的系统化阅读! - Lyzard Kyng
显示剩余3条评论
3个回答

6
将自己的Javascript代码移入打包文件是可维护性的好选择。然而,我猜这些是动态生成的复选框。当绑定运行时,它们可能不存在。您可以通过绑定到父元素并使用event delegation来解决问题。对于Turbolinks,document.body是常用的绑定选择。
我不喜欢在复选框上调用click()。结果对用户来说并不总是一致的,并且会在浏览器中触发大量不必要的事件。反转checked属性更清晰、更一致。
将DataTables作为模块加载需要一个导入shim。这是一个较旧的包,更喜欢AMD而不是CommonJS,并在Webpack环境中出现问题。幸运的是,有一个标准的解决方案,使用imports-loader来解决旧代码的问题。不幸的是,即使这样,它也有一个稍微奇怪的工厂导出,你需要注入windowjQuery变量。幸运的是,这也在此处记录

将所有这些内容组合起来,这里是一个建议的application.js

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

import $ from 'jquery'

// Add DataTables jQuery plugin
require('imports-loader?define=>false!datatables.net')(window, $)
require('imports-loader?define=>false!datatables.net-select')(window, $)

// Load datatables styles
import 'datatables.net-dt/css/jquery.dataTables.css'
import 'datatables.net-select-dt/css/select.dataTables.css'

$(document).on('turbolinks:load', () => {
  $(document.body).on('click', '#check_all', () => {
    var checkBoxes = $('input[type="checkbox"]')
    checkBoxes.prop("checked", !checkBoxes.prop("checked"))
  })

  // placeholder example for datatable with checkboxes
  $('#example').DataTable({
    columnDefs: [{
      render: (data,type,row) => `<input type="checkbox" value="${row[0]}">`,
      orderable: false,
      targets: 0
    }],
    order: [[ 1, 'asc' ]]
  })
})

由于这是Webpack选项,所以您需要yarn add imports-loader

对于所有这些内容,都不需要使用ProvidePlugin。除非您依赖它来将导入注入到第三方代码中,否则可以安全地删除它。


哇,非常感谢您写的回复!我真的很感激您花时间 :) 我已经尝试过了,但没能让它正常工作。我已经解决了所有问题,似乎编译也没有问题,但没有分页/搜索(也就是说,dt不会加载)。控制台显示一个错误,但没有指示哪个代码行是罪犯。错误:Uncaught ReferenceError: $ is not defined。这是我的application.js文件:https://gist.github.com/maayannaveh/51de9d29d89181b104ae2076d17a08e1(我已经注释掉了样式,因为我还不确定如何使它正常工作) - Maayan Naveh
好的,成功让样式起作用了。同样的问题。一个错误,没有冒犯的代码行,dt无法加载 :( - Maayan Naveh
1
您有未公开的脚本元素或事件属性,它们试图使用 $ 全局变量,但因为没有这个变量而失败。将所有此类代码移入包中。我看不到您已添加任何代码来实际调用 DataTables - 那个“占位符示例”部分只是一个示例,请根据自己的应用程序进行调整。 - inopinatus
您还有一个重复导入jquery的操作。请删除 require('jquery')。这可能不会造成伤害,但肯定是多余和令人困惑的。 - inopinatus
2
经过三天的谷歌搜索,终于让我在Rails 6中使我的自定义jQuery代码正常工作了。感谢你。 - phil
@inopinatus 我遇到了相同的错误,但是你的解决方案在我的情况下不起作用。 - Hassam Saeed

2

以上方法都没能帮到我。最终,我通过遵循这个指南使它工作起来:https://inopinatus.org/2019/09/14/webpacker-jquery-and-jquery-plugins/

yarn add datatables.net-bs4 imports-loader

application.js

require('@rails/ujs').start()
require('@rails/activestorage').start()
require('channels')
require('jquery')
require('bootstrap/dist/js/bootstrap')
window.$ = $

require('imports-loader?define=>false!datatables.net')(window, $)
require('imports-loader?define=>false!datatables.net-bs4')(window, $)

1
这解决了我的问题(当我使用jQuery版本3.4.1时,甚至不存在这个问题,但只有在我升级到jQuery v3.5.0时才出现)。而且这是提供的答案中最简单和最清晰的。 - Scott Schupbach
自从我编写了那篇指南和上面排名第一的答案后,我会补充我的想法 :)你已经应用了相同的原则,并且做得正确,但是针对不同的版本和/或导入集。我怀疑发生的事情是某些外部组件改变了它们的行为或打包方式。 - inopinatus
window.$ = $ 对我进行了排序 - Iain Watt

2

运行 yarn add imports-loader

我使用的是bootstrap4数据表,如果您使用的是bootstrap3或其他CSS框架,请按照此链接中的安装步骤进行安装: https://datatables.net/download/

在我的config/webpack/loaders/datatable.js文件中

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

在我的config/webpack/environment.js文件中。
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
const coffee =  require('./loaders/coffee')
const datatable =  require('./loaders/datatable')

environment.plugins.append('Provide', new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery',
  jquery: 'jquery',
  'window.jQuery': 'jquery',
  Popper: ['popper.js', 'default']
}))

/**
 * To use jQuery in views
 */
environment.loaders.append('expose', {
  test: require.resolve('jquery'),
  use: [{
    loader: 'expose-loader',
    options: '$'
  }]
})

environment.loaders.prepend('coffee', coffee)
environment.loaders.prepend('coffee', datatable)

module.exports = environment

在我的app/javascript/packs/dashboard.js

require( 'jszip' );

require("datatables.net-bs4")(window, $);
require("datatables.net-responsive-bs4")(window, $);
require("datatables.net-buttons-bs4")(window, $);
require("datatables.net-select-bs4")(window, $);

require("datatables.net-bs4/css/dataTables.bootstrap4.css");
require("datatables.net-responsive-bs4/css/responsive.bootstrap4.css");
require("datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css");
require("datatables.net-select-bs4/css/select.bootstrap4.css");

随意在app/javascript/packs中的任何.js文件中使用import './datatable'


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接