Необработанный TypeError: $(…).froalaEditor не является функцией… Это моя проблема.

Вопросы и ответы
@model List<jcperrestclient.JcpeRwebsitePageContentCommitteeDOA>
@{
    Layout = "_Layout";

    ViewData["Title"] = "Индекс";
}
<h2>Комитет</h2>
<body>
    <div>
        <main role="main" class="pb-3">
            <div class="container-fluid box mt-5">
                <div class="row">
                    @for (var i = 0; i < Model.Count; i++)

                    {
                        <div class="col-md-10" id="section1">
                            @Html.AntiForgeryToken()
                            <input type="hidden" asp-for="@(Model[i].CreatedBy)" />
                            <input type="hidden" asp-for="@(Model[i].CreatedDate)" />
                            <input type="hidden" asp-for="@(Model[i].UpdatedDate)" />
                            <input type="hidden" asp-for="@(Model[i].UpdatedBy)" />
                            <div class="form-group row">
                                <div class="col-md-6">
                                    <strong><label asp-for="@(Model[i].CreatedBy)"></label></strong>
                                    <input asp-for="@(Model[i].CreatedBy)" readonly style="border: none" />
                                    <br />
                                    <strong><label asp-for="@(Model[i].CreatedDate)"></label></strong>
                                    <input asp-for="@(Model[i].CreatedDate)" readonly style="border: none" />
                                </div>
                                <div class="col-md-6">
                                    <strong><label asp-for="@(Model[i].UpdatedBy)"></label></strong>
                                    <input asp-for="@(Model[i].UpdatedBy)" readonly style="border: none" />
                                    <br />
                                    <strong><label asp-for="@(Model[i].UpdatedDate)"></label></strong>
                                    <input asp-for="@(Model[i].UpdatedDate)" readonly style="border: none">
                                </div>
                            </div>
                            <div class="form-group row">
                                <label id="lblSuccess" style="color: red">@ViewBag.lblSuccess</label>
                            </div>
                            <div class="form-group row">
                                <label asp-for="@(Model[i].PageTitle)" class="control-label col-md-1"></label>
                                <div class="col-md-5">
                                    <textarea asp-for="@(Model[i].PageTitle)" class="form-control" placeholder="Введите ваш текст здесь" id="txtEditor"></textarea>
                                </div>
                            </div>
                            <div class="form-group row">
                                <span asp-validation-for="@(Model[i].HtmlContentCurrent)" class="text-danger">это то место?</span>
                                <textarea asp-for="@(Model[i].HtmlContentCurrent)" id="froala-editor" name="Content"></textarea>
                            </div>
                            <div class="form-group row">
                                <div class="col-md-1 offset-md-1">
                                    <input type="button" id="buttonCancel" name="stringValue" value="Отмена" title="Отменить эти изменения" class="btn btn-outline-dark" />
                                </div>
                                <div class="col-md-2">
                                    <input type="button" id="buttonSave" name="stringValue" value="Сохранить" title="Сохранить ваши изменения" class="btn btn-outline-dark" />
                                </div>
                                <div class="col-md-3">
                                    <input type="button" value="Показать/Скрыть предпросмотр" title="Предпросмотр Html" onclick="showDiv()" class="btn btn-outline-dark" />
                                </div>
                            </div>
                        </div>
                        <div class="col-md-2" id="section2" style="font-family: arial; text-align: left;">
                            <h4>Свойства содержимого страницы</h4>
                            <strong><label asp-for="@(Model[i].AdminControllerName)"></label></strong>
                            <input asp-for="@(Model[i].AdminControllerName)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].AdminControllerAction)"></label></strong>
                            <input asp-for="@(Model[i].AdminControllerAction)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].PublicControllerName)"></label></strong>
                            <input asp-for="@(Model[i].PublicControllerName)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].PublicControllerAction)"></label></strong>
                            <input asp-for="@(Model[i].PublicControllerAction)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].PublicViewName)"></label></strong>
                            <input asp-for="@(Model[i].PublicViewName)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].HasRightSideBar)"></label></strong>
                            <input asp-for="@(Model[i].HasRightSideBar)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].RightSideBarName)"></label></strong>
                            <input asp-for="@(Model[i].RightSideBarName)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].HasPartialView)"></label></strong>
                            <input asp-for="@(Model[i].HasPartialView)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].PartialViewName)"></label></strong>
                            <input asp-for="@(Model[i].PartialViewName)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].IsDeleted)"></label></strong>
                            <input asp-for="@(Model[i].IsDeleted)" readonly style="border: none" />
                            <br />
                            <strong><label asp-for="@(Model[i].DateDeleted)"></label></strong>
                            <input asp-for="@(Model[i].DateDeleted)" readonly style="border: none" />
                            <br />
                        </div>

                        <div id="previewDiv" style="display:none; border: 1px solid #ccc; padding: 10px; margin-top: 20px;">
                            <h4>Предпросмотр HTML</h4>
                            <div id="previewContent"></div>
                        </div>

                    }
                </div>
            </div>
        </main>
    </div>
    <!-- Включите CSS Froala Editor -->
    <link href="https://cdn.jsdelivr.net/npm/froala-editor/css/froala_editor.pkgd.min.css" rel="stylesheet" type="text/css" />
    <link href="https://cdn.jsdelivr.net/npm/froala-editor/css/froala_style.min.css" rel="stylesheet" type="text/css" />
    <!-- Включите jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

    <!-- Включите JS Froala Editor -->
    <script src="https://cdn.jsdelivr.net/npm/froala-editor/js/froala_editor.pkgd.min.js"></script>
    <!-- Включите Bootstrap JS (если необходимо) -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <!-- Включите ваш собственный JS -->
    <script src="~/js/site.js" asp-append-version="true"></script>

    <script>
        //Это делает jQuery переменной, и я могу реализовать это как внедрение зависимости, так что это не взаимодействует с Froala-->
        var $j = jQuery.noConflict();

        $j(document).ready(function () {
            setTimeout(function () {
                initializeFroala();
            }, 1000); // 1 секунду задержки, чтобы убедиться, что Froala полностью загружен
            function initializeFroala() {
                new FroalaEditor('#froala-editor', {
                    key: "xxxxxxxxxxxx",
                    attribution: false,
                    heightMin: 300,
                    heightMax: 600,
                    toolbarSticky: true,
                    imageInsertButtons: ["imageBack", "|", "imageUpload", "imageByURL"],
                    quickInsertButtons: ['image', 'table', 'ul', 'ol'],
                    toolbarButtons: {
                        'moreText': {
                            'buttons': ['bold', 'italic', 'underline', 'textColor', 'insertHR', 'strikeThrough', 'subscript', 'superscript', 'fontFamily', 'fontSize', 'clearFormatting'],
                            'buttonsVisible': 5
                        },
                        'moreLink': { 'buttons': ['|', 'insertLink'] },
                        'moreParagraph': {
                            'buttons': ['|', 'outdent', 'indent', 'formatUL', 'formatOLSimple', 'align', 'paragraphFormat', 'paragraphStyle', 'lineHeight', 'quote'],
                            'buttonsVisible': 5
                        },
                        'moreImage': { 'buttons': ['|', 'insertImage'] },
                        'moreRich': {
                            'buttons': ['|', 'insertTable', 'emoticons', 'specialCharacters']
                        },
                        'moreMisc': {
                            'buttons': ['undo', 'redo', 'spellChecker', 'fullscreen', 'selectAll', 'html', 'help'],
                            'align': 'right',
                            'buttonsVisible': 2
                        }
                    },
                    imageUploadURL: getCurrentPath(),
                    imageUploadParams: {
                        id: 'my_editor'
                    },
                    events: {
                        'contentChanged': function () {
                            document.getElementById('previewContent').innerHTML = this.html.get();
                        }
                    }
                });
            }
            function getCurrentPath() {
                var uploadURL;
                switch (window.location.hostname) {
                    case 'intranet':
                        uploadURL = '/EditingPages/JCPeRServiceAPI/UploadFiles';
                        break;
                    case 'devi':
                        uploadURL = '/EditingPages-devi/JCPeRServiceAPI/UploadFiles';
                        break;
                    case 'localhost':
                        uploadURL = '/JCPeRServiceAPI/UploadFiles';
                        break;
                    default:
                        uploadURL = '/default-endpoint'; // URL загрузки по умолчанию
                }
                return uploadURL;
            }
            // Распознавайте событие нажатия кнопки сохранения
            $j('#buttonSave').on('click', function (e) {
                e.preventDefault(); // Это переопределяет стандартную отправку формы, так что может быть реализован следующий код
                var formData = {
                    createdBy: $j('#CreatedBy').val(),
                    createdDate: $j('#CreatedDate').val(),
                    updatedBy: $j('#UpdatedBy').val(),
                    updatedDate: $j('#UpdatedDate').val(),
                    pageTitle: $j('#PageTitle').val(),
                    htmlContentCurrent: $j('#froala-editor').froalaEditor('html.get')
                };
                // Это запрос сохранения с ajax
                $j.ajax({
                    url: '@Url.Action("SaveCommitteeContent", "Home")', // Это конечная точка на сервере
                    type: 'POST', // Какой тип конечной точки
                    data: JSON.stringify(formData), // Преобразует данные в формат JSON, чтобы база данных приняла информацию
                    contentType: 'application/json; charset=utf-8',
                    headers: {
                        'RequestVerificationToken': $j('input[name="__RequestVerificationToken"]').val() // Токен для безопасности
                    },
                    success: function (response) {
                        if (response.success) {
                            $j('#lblSuccess').text('Содержимое сохранено').css('color', 'green');
                        } else {
                            $j('#lblSuccess').text('Не удалось сохранить содержимое').css('color', 'red');
                        }
                    },
                    error: function () {
                        $j('#lblSuccess').text('Произошла ошибка, добро пожаловать в Матрицу, Нео').css('color', 'blue');
                    }
                });
            });
            function showDiv() {
                var previewDiv = document.getElementById('previewDiv');
                var previewContent = document.getElementById('previewContent'); // Добавить ссылку на область содержания
                if (previewDiv) {
                    if (previewDiv.style.display === "none") {
                        previewDiv.style.display = "block";
                        // Обновите содержимое предпросмотра с HTML из Froala
                        previewContent.innerHTML = FroalaEditor.INSTANCES[0].html.get();
                    } else {
                        previewDiv.style.display = "none";
                    }
                } else {
                    console.error("Предпросмотр не найден!");
                }
            }
        });
    </script>

</body>

У меня конфликтующие версии jQuery: последняя версия 3.6.0 и, по-моему, Froala 2.4.2. Поскольку процесс загружает jQuery, а затем Froala, они взаимодействуют, и Froala перезаписывает 3.6.0. Мне нужно, чтобы обе версии работали в унисон, чтобы я мог сохранить в свою базу данных. Я видел аналогичные проблемы в прошлом, откуда я получил noConflict и установку тайм-аута. Если я пропустил разговор, который объяснил бы мою проблему лучше, просто укажите мне направление, спасибо.

Я пробовал noConflict() без успеха.
Пробовал переместить весь код на саму страницу без успеха.
Удалил jQuery 3.6.0, и это только ухудшило мой код.
Я установил тайм-аут для Froala без победы.

Ответ

Ошибка Uncaught TypeError: $(...).froalaEditor is not a function возникает из-за конфликтов между версиями jQuery или неправильного инициализации плагина Froala Editor. Давайте рассмотрим несколько шагов, которые могут помочь вам решить эту проблему.

Проверка версий и конфигурации

  1. Версии jQuery и Froala: Убедитесь, что вы используете совместимые версии jQuery и Froala Editor. Если вы используете jQuery 3.6.0, попробуйте также использовать более новую версию Froala Editor, так как версия 2.4.2, вероятно, не поддерживает jQuery 3.6.0. Ознакомьтесь с документацией Froala и проверьте совместимость.

  2. Подключение библиотеки jQuery: Убедитесь, что скрипт jQuery подключён до скрипта Froala Editor в вашем HTML-документе. Таким образом, Froala сможет правильно использовать jQuery.

    <!-- Сначала подключите jQuery -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <!-- Затем подключите Froala Editor -->
    <script src="https://cdn.jsdelivr.net/npm/froala-editor/js/froala_editor.pkgd.min.js"></script>

Использование jQuery.noConflict()

  1. Использование jQuery.noConflict(): В вашем коде вы правильно используете jQuery.noConflict(), однако убедитесь, что вы используете переменную $j consistently во всем вашем скрипте, чтобы избежать конфликтов. Например, замените все $ на $j, чтобы гарантировать, что фреймворк знает, какая именно версия jQuery используется.

Убедитесь, что Froala Editor инициализируется

  1. Инициализация Froala: Убедитесь, что Froala Editor правильно инициализируется. Убедитесь, что ID текстового поля соответствует тому, что вы используете в JavaScript коде для инициализации. На примере кода:

    $j(document).ready(function () {
       new FroalaEditor('#froala-editor', {
           // ваши параметры
       });
    });
  2. Задержка при инициализации: Если вы все еще сталкиваетесь с ошибкой, попробуйте убрать setTimeout. Это гарантирует, что Froala будет инициализирован сразу после загрузки документа. Например:

    $j(document).ready(function () {
       initializeFroala();
    });

Полный пример инициализации

Вот полный пример инициализации редактора, который вы можете использовать:

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/froala-editor/js/froala_editor.pkgd.min.js"></script>

<script>
    var $j = jQuery.noConflict();

    $j(document).ready(function () {
        // Инициализация Froala
        new FroalaEditor('#froala-editor', {
            // Опции конфигурации
        });

        // Обработчик события на кнопку сохранения
        $j('#buttonSave').on('click', function (e) {
            e.preventDefault();
            var htmlContent = $j('#froala-editor').froalaEditor('html.get');
            // ваш ajax запрос для сохранения
        });
    });
</script>

Заключение

Если вы выполните все вышеперечисленные шаги и обеспечите правильную последовательность подключения файлов скриптов, ошибка должна исчезнуть, и Froala Editor должен работать в унисон с jQuery. Если у вас все еще возникают проблемы, проверьте консоль разработчика на наличие других ошибок, которые могут указывать на проблемы с совместимостью или загрузкой файлов. Удачи!

Оцените материал
Добавить комментарий

Капча загружается...