You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ajax提交含CKEditor5的评论表单:单次提交成功无刷新问题求助

解决CKEditor5与AJAX提交内容不同步问题

核心问题

CKEditor5的CKEditor5Widget会生成一个隐藏的input(name为review),但它默认只在**表单正常提交(非AJAX)**时自动同步编辑器内容。当用AJAX提交并阻止默认行为时,首次提交会因为内容未同步到隐藏字段,导致后端拿不到review值。


方案一:提交前手动同步编辑器内容

修改review.js,在AJAX发送前主动调用CKEditor的同步方法,把编辑器内容写入隐藏input:

console.log("review.js loaded");

$("#commentForm").submit(function(e) {
  e.preventDefault();

  // 关键:手动同步CKEditor内容到隐藏input
  if (window.CKEDITOR) {
    // Django表单默认生成的编辑器ID是id_字段名,这里字段为review,所以是id_review
    const editor = window.CKEDITOR.instances.id_review;
    if (editor) {
      editor.updateSourceElement();
    }
  }

  $.ajax({
    data: $(this).serialize(),
    method: $(this).attr("method"),
    url: $(this).attr("action"),
    dataType: "json",
    success: function(response) {
      console.log("Comment saved to DB")

      if (response.bool) {
        $("#review-response").html("Review saved successfully");
        $("#review-response").addClass("text-success");
        $("#review-response").removeClass("text-danger");
        $(".hide-review-form").hide();
        $(".hide-review-heading").hide();
      }
      else {
        $("#review-response").html(response.error || "Error saving review");
        $("#review-response").addClass("text-danger");
        $("#review-response").removeClass("text-success");
      }

    },
    error: function() {
      $("#review-response").html("Server error, please try again later");
      $("#review-response").addClass("text-danger");
    }
  });
});

说明

  • 如果编辑器ID不是id_review,可以在浏览器控制台输入console.log(window.CKEDITOR.instances)查看所有实例ID。
  • updateSourceElement()方法会将编辑器的HTML内容同步到关联的隐藏input,确保serialize()能拿到最新内容。

方案二:直接从编辑器获取内容(不依赖隐藏input)

跳过隐藏input,直接从CKEditor实例读取内容,手动构造提交数据:

console.log("review.js loaded");

$("#commentForm").submit(function(e) {
  e.preventDefault();
  const form = $(this);
  let formData = form.serializeArray();

  // 从CKEditor获取内容,替换formData中的review项
  if (window.CKEDITOR) {
    const editor = window.CKEDITOR.instances.id_review;
    if (editor) {
      const reviewIndex = formData.findIndex(item => item.name === 'review');
      if (reviewIndex !== -1) {
        formData[reviewIndex].value = editor.getData();
      } else {
        formData.push({name: 'review', value: editor.getData()});
      }
    }
  }

  $.ajax({
    data: $.param(formData),
    method: form.attr("method"),
    url: form.attr("action"),
    dataType: "json",
    success: function(response) {
      console.log("Comment saved to DB")

      if (response.bool) {
        $("#review-response").html("Review saved successfully");
        $("#review-response").addClass("text-success");
        $("#review-response").removeClass("text-danger");
        $(".hide-review-form").hide();
        $(".hide-review-heading").hide();
      }
      else {
        $("#review-response").html(response.error || "Error saving review");
        $("#review-response").addClass("text-danger");
        $("#review-response").removeClass("text-success");
      }

    },
    error: function() {
      $("#review-response").html("Server error, please try again later");
      $("#review-response").addClass("text-danger");
    }
  });
});

额外优化:返回具体错误提示

修改views.py中的ajax_add_review函数,把具体错误信息返回给前端,提升用户体验:

def ajax_add_review(request, pid):
    product = Product.objects.get(pid=pid)
    user = request.user

    review_text = request.POST.get('review')
    rating = request.POST.get('rating')

    print(f"Review is: {review_text}")

    if not review_text:
        print("Review text is missing")
        return JsonResponse({'bool': False, 'error': 'Please enter your review content'})
    if not rating:
        print("Rating is missing")
        return JsonResponse({'bool': False, 'error': 'Please select a rating'})

    review = ProductReview.objects.create(
        user=user,
        product=product,
        review=review_text,
        rating=rating,
    )
    
    context = {
        'user': user.username,
        'review': review.review,
        'rating': review.rating,
    }
    
    average_reviews = ProductReview.objects.filter(product=product).aggregate(Avg('rating'))
    
    return JsonResponse(
        {
        'bool': True,
        'context': context,
        'average_reviews': average_reviews,
        }
    )

针对新版CKEditor5的补充

如果使用的是CKEditor5最新版本(通过ClassicEditor.create初始化),可以用以下方式获取编辑器实例:

const editor = document.querySelector('.django_ckeditor_5').ckeditorInstance;
if (editor) {
  editor.updateSourceElement();
}

内容的提问来源于stack exchange,提问作者Salman Adnan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 03:29:54