I'm not a well skilled javascript expert. I'm migrating a very old app to webpacker. I have a lot of coffeescript files like this:
class @SectionTable
constructor: ->
@table = $('#site_section')
@_dnd()
_dnd: ->
@table.tableDnD onDrop: (table, row) ->
data = $.tableDnD.serialize()
$.ajax
type: 'POST'
url: '/admin/sections/reorder'
data: data
$ -> new SectionTable()
I already created a structure for my Javascript files in webpacker.
I have some page specific scripts and some global script that I init using a init.js file like this
import timePicker from './timePicker.js';
import Redactor from './redactor.js';
(function init() {
const dtPicker = timePicker();
const redactor = Redactor();
document.addEventListener("turbolinks:load", () => {
dtPicker.init();
redactor.init();
});
}());
And then, inside timePicker.js, I init single components
import 'bootstrap-datetime-picker/js/bootstrap-datetimepicker.js';
import 'bootstrap-datetime-picker/js/locales/bootstrap-datetimepicker.it.js';
const timePicker = () => {
const initDateTimePicker = () => {
const dateTime = $('.datetime');
if (dateTime.length > 0) {
$('.datetime').datetimepicker({
todayHighlight: true,
autoclose: true,
pickerPosition: 'bottom-left',
todayBtn: true,
format: 'hh:ii dd/mm/yyyy'
});
}
};
const init = () => {
initDateTimePicker();
};
return {
init,
};
};
export default timePicker;
I cannot find a way to adjust my coffeescript objects inside the new logic. The coffeescript above is very simple, but I have also some complex objects like this:
@Cover = {}
class Cover.Preview
constructor: ->
@elements = {} # preview elements, for each tab/preview box
@element = $('#cover_format')
@container = $('#cover_preview')
@button = $('#change_format')
@url = @element.data('url')
@setFormat()
@bindChange()
addElement: (element, position) ->
position = element.position
@elements[position] = element
bindChange: ->
@button.click (event) =>
event.preventDefault()
@setFormat()
$.ajax
url: "#{@url}?format=#{@format}"
dataType: 'html'
success: (html) =>
@container.html html
@rebindDrag()
@repopulate()
setFormat: -> @format = @element.val()
rebindDrag: ->
Cover.FormElement.init()
Cover.Preview.Tile.init()
repopulate: ->
for position, tile of Cover.Preview.Tile.all
tile.redraw Cover.preview.elements[position]
$ ->
Cover.preview = new Cover.Preview()
I understand that I have a couple of ways to to this:
1) keep coffeescript and add coffeescript files loader inside webpacker, but I cannot understand how to Init my coffee defined objects inside the init file (and not in the coffee file like now)
2) convert from coffee to ES6, I try with the online tool and I have this result
this.SectionTable = class SectionTable {
constructor() {
this.table = $('#dday_section');
this._dnd();
}
_dnd() {
return this.table.tableDnD({onDrop(table, row) {
const data = $.tableDnD.serialize();
return $.ajax({
type: 'POST',
url: '/admin/sections/reorder',
data
});
}
});
}
};
$(() => new SectionTable());
How can I add a modular approach? So basically I want to create the new SectionTable
in my init file.
Just an example:
import $ from 'jquery';
export class SectionTable {
constructor() {
this.table = $('#site_section');
this._dnd();
}
_dnd() {
this.table.tableDnD.onDrop((table, row) => {
const data = $.tableDnD.serialize();
$.ajax({
type: 'POST',
url: '/admin/sections/reorder',
data: data
});
});
}
}
// if you need a single instance like seems to from your code
export default new SectionTable();
// otherfile.js
// this is just to show you how you can import only some classes from a file when
// export is used
import SectionTableSingleTon, { SectionTable } from './somewhere/SectionTable';
const sectionTable = new SectionTable();
just be cafeful with 'this' with object methods. If you need to pass it around bind it in the constructor.
constructor() {
this.someMethod = this.someMethod.bind(this);
}
attachListener(){
$('button').click(this.someMethod);
}
somemethod(){
// correct this
}
And you don't need iife anymore inside an esm module