Chris James Champeau Chris James Champeau - 4 months ago 88
jQuery Question

Trumboqyg WYSIWYG editor does not work with Jquery.Validate plugin, "Uncaught TypeError: Cannot read property 'nodeName' of undefined"

I have been pulling my hair out trying to figure this out.

I am running jquery 2.2.2 at the moment with the jquery validation plugin. https://jqueryvalidation.org/
And Trumbowyg WYSIWYG Editor. https://alex-d.github.io/Trumbowyg/

It's great mostly everything works however, every time a use clicks or does anything really. You get the console error

Uncaught TypeError: Cannot read property 'nodeName' of undefined
. It also creates certain parts of Trumbowyg to not work properly.

So my solution was to use the ignore class on the jquery validation plugin. But it does not work. I have tried ignoring almost every class labeling for different fields and no matter what I do it is never ignored.

So how do I use the jquery validation plugin, with the trumbowyg text editor?

Here is my validation code.

$('form').validate({
errorPlacement: function (error, element) {
if ($(element).parent('.input-group').length) {
error.insertAfter(element.parent().siblings('label'));
error.addClass('alert alert-danger validate');
} else {
error.insertAfter(element.siblings('label'));
error.addClass('alert alert-danger validate');
}
},
errorElement: 'div',
highlight: function (element) {
$(element).parent().addClass("has-error");
},
unhighlight: function (element) {
$(element).parent().removeClass("has-error");
},
ignore: '.advanced',
rules: {
password_confirm: {
equalTo: 'input[name=password]'
},
user_username: {
remote: {
url: 'action/check/',
type: 'POST',
data: {
id: function () {
return $('input[name=id]').val();
}
}
}
},
nav_name: {
remote: {
url: 'action/check/',
type: 'POST',
data: {
id: function () {
return $('input[name=id]').val();
}
}
}
}
},
messages: {
password_confirm: {
equalTo: "Passwords must match"
},
user_username: {
remote: "This Username already exists"
},
nav_name: {
remote: "This Nav Item Name already exists"
}
},
submitHandler: function (form) {
$('button[type="submit"]').addClass('disabled').prop('disabled', true).prepend('<span class="bootstrap-dialog-button-icon glyphicon glyphicon-asterisk icon-spin"></span>');
form.submit();
}
});


I did remove the validation plugin and everything with trumbowyg did work. So maybe it's time to find a new validation plugin, I really would like to avoid that.

Update: I did notice that firefox is giving me a different error, so I figured I would share that as well.

TypeError: owner is undefined
owner[ this.expando ] && owner[ this.expando ][ key ];


An example of the problem should be available to demo here: http://develop.chrischampeau.com/admin/test.php

Answer

This is a known issue with the jQuery Validation plugin where content editable elements in forms would cause exceptions when an event is triggered.

You can find this issue describing the exact same problems:

  • Breaks your WYSIWYG.
  • Undefined errors.
  • All toolbar buttons in your WYSIWYG take two clicks to trigger.

A modification / hack is proposed in this thread to resolve the issue but a pull request fixing this same issue has already been merged into the project in May.

The problem is that the latest release is from February so this merge is not available at the moment. According to this other issue, a maintainer stated 15 hours ago that a release is coming very soon and it includes the fix for your problem.

If you can't wait for the new release, you can always get the latest version from their repository or cherry pick yourself the fix included in this pull request.

Regarding the second issue you described in a comment after applying the fix from the pull request, jQuery Validation check on various events (onfocusout especially in this case) if an element should be ignored or not by checking if it has a class specified in the settings.

You're adding to your textarea class="advanced" to ignore it, unfortunately, when Trumbowyg is initialized, the wrapper created will be the following:

<div class="trumbowyg-editor trumbowyg-reset-css" contenteditable="true" dir="ltr" placeholder="">

It does not propagates the advanced class to the wrapper. A potential fix is to add yourself this class when Trumbowyg is initialized. To do that, you can rely on the tbwinit event by modifying your constructor.

// Setup WYSIWYG
$('textarea.advanced').trumbowyg( {
    resetCss: true,
    removeformatPasted: true,
    autogrow: true,
    btnsDef: {
    // Customizables dropdowns
        image: {
            dropdown: ['insertImage', 'upload', 'base64', 'noEmbed'],
            ico: 'insertImage'
        }
    },
    btns: [
        ['viewHTML'],
        ['undo', 'redo'],
        ['formatting'],
        'btnGrp-design',
        ['link'],
        ['image'],
        'btnGrp-justify',
        'btnGrp-lists',
        ['foreColor', 'backColor'],
        ['preformatted'],
        ['horizontalRule'],
        ['fullscreen']
    ],
    plugins: {
        // Add imagur parameters to upload plugin
        upload: {
            serverPath: 'https://api.imgur.com/3/image',
            fileFieldName: 'image',
            headers: {
                'Authorization': 'Client-ID 9e57cb1c4791cea'
            },
            urlPropertyName: 'data.link'
        }
    }
}).on('tbwinit', function(){
  $('.trumbowyg-editor').addClass('advanced');
});

After initialization, your wrapper will have the advanced class so that jQuery Validation can use it.

<div class="trumbowyg-editor trumbowyg-reset-css advanced" contenteditable="true" dir="ltr" placeholder="">

Regarding the second issue, it's triggered because some libraries like Trumbowyg when they open a popup (like the ones your mentioned in your comment: Insert Link, Insert Image, etc.), they are actually appending a <form> in the DOM but inside another <form> which leads to nested forms.

In the case of nested forms, the second error you mentioned is triggered by jQuery Validation. You can check the comment of the jQuery Validation plugin owner regarding this problem on this message:

Nesting forms is invalid HTML. Either the [...] plugin doesn't generate a form if there is already one, or it has to append it outside the current form.

There is already an issue opened on the Trumbowyg Github regarding this problem, but it's a large modification on the core of the plugin and at this moment, it's moved from milestone to milestone since 2015.