Rails 6 + Webpack, Datatables, jQuery

У меня есть кнопка «Выбрать все», в которой используется этот код:

<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']
  })
)

To:

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

Но как только это исправлено, таблицы данных ломаются.

Есть идеи, как заставить их обоих работать вместе? Спасибо!


person Maayan Naveh    schedule 16.09.2019    source источник
comment
Ваш environment.js был правильным. Какая исходная строка вызвала ReferenceError? Где находится код кнопки «Выбрать все» и как он попал в пакет application.js?   -  person Lyzard Kyng    schedule 17.09.2019
comment
Подробнее об этой ошибке в таблицах данных?   -  person overlox    schedule 17.09.2019
comment
@LyzardKyng эту строку: $('#check_all').on("click", function(){ $('input[type="checkbox"]').click(); }); Код находится в соответствующем представлении. Когда я пытаюсь переместить его в application.js, он больше не выдает ошибок, но кнопка также ничего не делает. Любые идеи? Вот как это выглядит в application.js: $(document).on('turbolinks:load', function() { $('#check_all').on("click", function(){ $('input[type="checkbox"]').click(); }); }) - Я новичок во всем этом, поэтому я, вероятно, ошибаюсь   -  person Maayan Naveh    schedule 17.09.2019
comment
@overlox вот ошибка: Uncaught TypeError: Cannot set property '$' of undefined а вот оскорбительная строка: `this. $ = function (sSelector, oOpts) {` реальная проблема в том, что dt не загружается вообще. Без поиска, без разбивки на страницы и т. Д.   -  person Maayan Naveh    schedule 17.09.2019
comment
@MaayanNaveh, вы меняли javascript_include_tag на javascript_pack_tag в app/views/layouts/application.html.erb? Я повторяю ваш код и не вижу ошибок, а флажок установлен должным образом.   -  person Lyzard Kyng    schedule 18.09.2019
comment
@LyzardKyng Ага, только что проверил дважды, и это <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>   -  person Maayan Naveh    schedule 18.09.2019
comment
inopinatus.org/2019/09/14/webpacker-jquery -and-jquery-plugins   -  person inopinatus    schedule 18.09.2019
comment
@inopinatus Отличное систематизированное чтение!   -  person Lyzard Kyng    schedule 19.09.2019


Ответы (3)


Перемещение вашего собственного Javascript в файл пакета было хорошим выбором для удобства сопровождения. Однако я предполагаю, что это динамически генерируемые флажки. Они могут не существовать, когда выполняется привязка. Вы можете решить эту проблему, привязав к родительскому элементу и используя делегирование событий. document.body - это общий выбор привязки для делегированных событий с Turbolinks.

Я не поклонник вызова click () для флажка. Результат не всегда согласован для пользователей и запускает кучу ненужных событий в браузере. Инвертирование checked опоры более чистое и последовательное.

Для загрузки DataTables в качестве модуля требуется прокладка для импорта. Это более старый пакет, который предпочитает AMD CommonJS и переключается на себя в среде Webpack. К счастью, есть стандартное исправление для старого кода, использующее загрузчик импорта. К сожалению, даже в этом случае у него есть немного странный заводской экспорт, в который вы должны вставить переменные window и jQuery. К счастью, это также задокументировано здесь.

Собирая все вместе, вот предлагаемый 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' ]]
  })
})

Вам понадобится yarn add imports-loader, поскольку это вариант Webpack.

ProvidePlugin для этого не требуется. Если вы не зависите от него при импорте в сторонний код, его можно безопасно удалить.

person inopinatus    schedule 18.09.2019
comment
Вау, большое спасибо за хорошо написанный ответ! Я очень ценю, что вы потратили время :) Я попробовал, но не смог заставить его работать. Я решил все проблемы и, похоже, компилируется нормально, но нет разбивки на страницы / поиска (это означает, что dt не загружается). Консоль показывает 1 ошибку, но без указания того, какая строка кода является нарушителем. Ошибка: Uncaught ReferenceError: $ is not defined. Вот мой application,js: gist.github.com/maayannaveh/51de9d29d89181b104ae20eated1 стили, потому что я еще не уверен, как заставить его работать) - person Maayan Naveh; 18.09.2019
comment
Хорошо, удалось заставить стили работать. То же самое. Одна ошибка, нет проблемных строк, dt не загружается :( - person Maayan Naveh; 18.09.2019
comment
У вас есть нераскрытые элементы сценария или атрибуты событий, которые пытаются использовать $ global и терпят неудачу, потому что его нет. Переместите весь такой код в пакеты. Я не вижу, чтобы вы добавили какой-либо код для фактического вызова DataTables - этот раздел примеров заполнителей - это просто, адаптируйте его для своего собственного приложения. - person inopinatus; 19.09.2019
comment
У вас также есть дублированный импорт jquery. Удалите require('jquery'). Наверное, не вредно, но, безусловно, излишне и сбивает с толку. - person inopinatus; 19.09.2019
comment
После 3 дней поиска в Google этот ответ наконец получил мой собственный код jquery, работающий в Rails 6. Благослови вас. - person phil; 17.11.2019
comment
@inopinatus Я столкнулся с той же ошибкой, но ваше решение не работает в моем случае - person Hassam Saeed; 10.10.2020

запустить yarn add imports-loader

Я использую bootstrap4 datatable, если вы используете bootstrap3 или другие фреймворки CSS, пожалуйста, следуйте установке по этой ссылке: https://datatables.net/download/

in my config/webpack/loaders/datatable.js

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

in my 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

in my 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");

Не стесняйтесь использовать import './datatable' в любом .js файле в app/javascript/packs, который вам нравится

person Kiry Meas    schedule 16.10.2019

У меня ничего из вышеперечисленного не сработало. Наконец, он заработал, следуя этому руководству: 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, $)
person Jeremy Kirchhoff    schedule 15.04.2020
comment
Это решило мою проблему (которой даже не существовало, когда я был на jQuery версии 3.4.1, но она появилась только после обновления jQuery до v3.5.0). И это, безусловно, самый простой и ясный из предоставленных ответов. - person Scott Schupbach; 04.05.2020
comment
Поскольку я написал это руководство, и ответ с самым высоким рейтингом выше, я добавлю свои мысли :) Вы применили тот же принцип и правильно, но для другой версии и / или набора импорт. Я подозреваю, что произошло то, что некоторые внешние элементы изменили свое поведение или упаковку. - person inopinatus; 21.08.2020
comment
window. $ = $ отсортировал это для меня - person Iain Watt; 02.02.2021