Problem:
I am trying to create a WYSIWYG editor that is modular and reusable for my blog... unfortunately I am having a hard time making it work with more than one text field.
How it works:
The editor enables document.designMode = 'on'
on an Iframe.
First I initialize the object:
init: function(){
this.cacheDOM();
this.renderEditor();
this.enableDesignMode();
this.bindEvents();
},
Then cache the DOM
cacheDOM: function(){
this.$editors = $('.editor-toolbar');
this.$iframes = $('.editor-iframe');
},
Then I render the toolbar with all my editor tools
renderEditor: function(){
var html = '<div class="text-editor">' +
'<div class="btn-group">' +
'<button class="e_bold btn btn-sm btn-secondary" type="button"><i class="fa fa-bold"></i></button>' +
'<button class="e_italic btn btn-sm btn-secondary" type="button"><i class="fa fa-italic"></i></button>' +
'<button class="e_underline btn btn-sm btn-secondary" type="button"><i class="fa fa-underline"></i></button>' +
'</div>' +
'<div class="btn-group">' +
'<button class="e_align_left btn btn-sm btn-secondary" type="button"><i class="fa fa-align-left"></i></button>' +
'<button class="e_align-center btn btn-sm btn-secondary" type="button"><i class="fa fa-align-center"></i></button>' +
'<button class="e_align-right btn btn-sm btn-secondary" type="button"><i class="fa fa-align-right"></i></button>' +
'</div>' +
'<div class="btn-group">' +
'<button class="e_header_2 btn btn-sm btn-secondary" type="button" value="h2">h2</button>' +
'<button class="e_header_3 btn btn-sm btn-secondary" type="button" value="h3">h3</button>' +
'<button class="e_header_4 btn btn-sm btn-secondary" type="button" value="h4">h4</button>' +
'<button class="e_paragraph btn btn-sm btn-secondary" type="button" value="p">p</button>' +
'</div>' +
'<div class="btn-group">' +
'<button class="e_unordered_list btn btn-sm btn-secondary" type="button"><i class="fa fa-list-ul"></i></button>' +
'<button class="e_ordered_list btn btn-sm btn-secondary" type="button"><i class="fa fa-list-ol"></i></button>' +
'<button class="e_table_separator btn btn-sm btn-secondary" type="button">1 | 2</button>' +
'</div>' +
'<div class="btn-group">' +
'<button class="e_unordered_list btn btn-sm btn-outline-success" type="button"><i class="fa fa-tag"></i></button>' +
'<button class="e_ordered_list btn btn-sm btn-outline-info" type="button"><i class="fa fa-tag"></i></button>' +
'<button class="e_table_separator btn btn-sm btn-outline-secondary" type="button"><i class="fa fa-tag"></i></button>' +
'</div>' +
'</div>';
this.$editors.html(html);
},
Next I enable the designMode
. I want to have as many separate editors as I want on a page so I loop through each Iframe and enable design mode on each of them.
enableDesignMode: function(){
for (i = 0; i < this.$iframes.length; i++) {
this.$iframes[i].contentDocument.designMode = 'on';
}
},
Now comes the difficulty. I am trying to bind click events on buttons in this.$editors[0]
to this.$iframes[0]
so that each toolbar is attached to the correct editor iframe.
bindEvents: function(){
for (i = 0; i < this.$iframes.length; i++) {
this.$editors[0].on('click', 'e_bold', function(){
this.$iframes[i].contentDocument.execCommand('bold', false, null);
});
}
},
Problem:
I am getting this error and I don't understand why:
TypeError: this.$editors[0].on is not a function
this.$editors
is an array of classes... so surely the .on
function should apply to this.$editors[i]?
Here is the fiddle: https://jsfiddle.net/7q30tuxo/1/
You are mistaken, this.$editors
is a jQuery object, not "an array of classes". When you do this.$editors[0]
, you are getting an actual HTML element.
on
is a function on jQuery objects, not DOM elements. Wrap your this.$editors[n]
with jQuery: $(this.$editors[0])
EDIT: As Kevin mentioned in the comment below, you're not selecting more than one element for use in this.$editors
, so you don't need to unwrap it: this.$editors.on('click', function(){})
To be clear, you don't generally need to unwrap even if you have selected more than one element. Only if you need to treat the selected elements differently do they need to be unwrapped. That is a smell, however, and I'd recommend refactoring your selectors so that they select only the elements you intend to operate on as one.