【问题标题】:jquery ajax / django - present form in a bootstrap modal and re-show if validation was not successfuljquery ajax / django - 在引导模式中显示表单并在验证不成功时重新显示
【发布时间】:2012-08-10 07:22:12
【问题描述】:

我的用例是:

a) 在引导模式 fancy overlay effect stuff.. 中显示通过 ajax 加载的表单。我关注了这些instructions

这很好用。 (见下面的代码)

b) 将此表单提交回我的 Django 应用程序,尝试验证它,如果它没有验证,则在精美的引导模式中重新显示带有错误的表单。

我可以通过 ajax 重新加载表单,但我无法在模态中再次表示它。

注意:我没有包含视图,因为它没有什么特别之处。仅实例化和验证表单。

下面有很多要阅读的内容,所以如果您认为用例听起来很有趣,请继续阅读...

我的 taskList.html 如下所示:

<table id="listItemTable" class="table table-bordered">
        <thead>
            <tr>
                <th>Name</th>
                <th>Edit</th>
            </tr>
        </thead>
    <tbody>
        <tr>
            <td>Task 1</td>
            <td><a class="editItem" href="/update/item/1/">edit</a></td>
        </tr>
    </tbody>
</table>

<div class="modal hide" id="itemFormModal"></div>
<div id="modalExtraJsPlaceholder"></div>

.js 用于加载表单 + 显示引导模式 + 绑定表单到 .jquery 提交调用:

$(document).ready(function() {
   modalConnect();
});

<script type="text/javascript">
 //connects the modal load for each <a> with class editItem
 //Functionality 1
     //loads an item edit form from the server and replaces the itemFormModal with the form
     //presents the modal with $("#itemFormModal").modal('show');
 //Functionality 2
     //loads some extra js "modalExtraJsHtml"
     //calls the function "submitItemModalFormBind" which has been loaded via "modalExtraJsHtml"

 function modalConnect(){
    $(".editItem").click(function(ev) { // for each edit item <a>
    ev.preventDefault(); // prevent navigation
    url = ($(this)[0].href); //get the href from <a>
    $.get(url, function(results){
       var itemForm = $("#ajax_form_modal_result", results);
       var modalExtraJs = $("#modalExtraJs", results);
       //get the html content
       var modalExtraJsHtml = modalExtraJs.html();
       //update the dom with the received results
        $('#itemFormModal').html(itemForm);        
        $('#modalExtraJsPlaceholder').html(modalExtraJsHtml);
        $("#itemFormModal").modal('show');
        submitItemModalFormBind(); //bind loaded form to ajax call
     }, "html");
     return false; // prevent the click propagation
   })
}
</script>

从视图返回的 itemForm 如下所示:

<form id="#ajax_form_modal_result" class="well" method="post" action="/update/item/{{ item.id }}">
 <div id="ajax_form_modal_result_div">
     <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal">×</button>
      <h3>Edit Item</h3>
    </div>
    <div class="modal-body">
         {% csrf_token %}
         {{form.as_p}}
    </div>
    <div class="modal-footer">
         <input class="btn btn-primary" type="submit" value="Save" />
         <input name="cancel" class="btn" type="submit" value="Cancel"/>
     </div>
    </div>
</form>

加载和显示模式可以正常工作。 但现在是第二部分,它没有按预期工作。问题如下。如果表单未通过验证,视图将返回表单。返回的表单应在引导模式中再次显示。但结果是只有表单出现在浏览器中,其他一切都丢失了。没有css,没有表格,只有表格。相当难看..因此我没有实现更新ajax_form_modal_result_div。任何人都可以在这里帮我解决我做错了什么......!?

视图还返回 js 函数“submitItemModalFormBind”,它可以防止表单默认行为并通过 ajax 发送表单。

<div id="modalExtraJs">
 //ajax bind for update item form visualized via modal
 function submitItemModalFormBind(){
     var url = "{% url updateItem item.pk %}";
     $('#ajax_form_modal_result').submit(function(){
 $.ajax({
    type: "POST",
    url: "{% url updateTask item.pk %}",
    data: $(this).serialize(),
    success:function(response){
        var div = $("ajax_form_modal_result_div", response);
        $('#ajax_form_modal_result_div').html(div);
     },
     error: function (request, status, error) {
         console.log("failure");
         console.log(request.responseText);
     }

           });
          });
        return false;
       }    
</div> 

【问题讨论】:

    标签: django jquery twitter-bootstrap


    【解决方案1】:

    我编写了这个简单的 AJAX,对我有用,希望对你有帮助:

    $(document).on('submit', 'div.modal-body form', function(e) {
            var form_el = $(this);
            e.preventDefault();
            $.ajax({
                type: $(this).attr('method'),
                url: $(this).attr('action'),
                data: $(this).serialize(),
                success: function (xhr, ajaxOptions, thrownError) {
                    if ( $(xhr).find('.errorlist').length > 0 ) {
                        form_el.parents('.modal-body').html(xhr);
                    } else {
                        form_el.parents('.modal-body').html('<h4>Formulario enviado correctamente</h4>');
                    }
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    form_el.parents('.modal-body').html(xhr);
                }
            });
    });
    

    哦,顺便说一句,您还需要这样的东西才能将表单加载到模态中:

    $('.modal-class').on('click',function(){
        let dataURL = $(this).attr('data-href');
        $('.modal-body').load(dataURL,function(){
            $('#modal_crear').modal({show:true});
        });
    });
    

    【讨论】:

      【解决方案2】:

      找到了一种可行的方法(基于此solution - 并通过处理无效表单对其进行了增强)并将其发布给任何想要在 django 中使用令人惊叹的漂亮引导模式的人。上面代码的主要问题是我没有正确禁用提交按钮的默认行为,并且加载其他 js 的方法不是一个好主意。所以我改变了策略。

      在 documentReady 或 ajaxStop 事件上,将超链接的点击事件绑定到 modalConnect 函数。请注意,如果您有某种更新表格内容的 ajax(我有),则只需要 ajaxStop 函数:

      <script type="text/javascript">
          $(document).ready(function() {
              modalConnect();
          });
      </script>
      
      <script type="text/javascript">
      $( document ).ajaxStop( function() {
          modalConnect();
      });
      </script>
      

      modalConnect 函数,它加载我们想要在 modal 中呈现的表单和一个 formUpdateURLDiv:

      <script type="text/javascript">
          function modalConnect()
              {
                  //unbind the click event. If not done we will end up with multiple click event bindings, since binding is done after each ajax call.
                  $(".editItem").unbind('click');
                  //bind the click event
                  $(".editItem").click(function(ev) { // for each edit item <a>
                      ev.preventDefault(); // prevent navigation
                      var url = this.href; //get the href from the <a> element
                      $.get(url, function(results){
                        //get the form
                        var itemForm = $("#ajax_form_modal_result", results);
                        //get the update URL
                        var formUpdateURLDiv = $("#formUpdateURL", results);
                        //get the inner html of the div
                        var formUpdateURL = formUpdateURLDiv.html();
                        //update the dom with the received form
                        $('#itemFormModal').html(itemForm);
                        //show the bootstrap modal
                        $("#itemFormModal").modal('show');
                        $(document).ready(function () {
                           //bind the form to an ajax call. ajax call will be set to the received update url
                           submitItemModalFormBind(formUpdateURL);
                        });
                      }, "html");
                      return false; // prevent the click propagation
                  })
              }
      </script>
      

      formUpdateURL 包含一个服务器生成的(参见下面包含的视图)的 url,加载的表单必须对其进行表单提交调用。我们使用这个 url 来“初始化” submitItemModalFormBind 函数:

      <script type="text/javascript">
             function submitItemModalFormBind(url){
               //bind the form. prevent default behavior and submit form via ajax instead
               $('#ajax_form_modal_result').submit(function(ev){
                   $.ajax({
                      type: "POST",
                      url: url,
                      data: $(this).serialize(),
                      success:function(response, textStatus, jqXHR){
                           var form = $("#ajax_form_modal_result_div", response);
                           //form is returned if it is not valid. update modal with returned form
                           //change this "if" to check for a specific return code which should be set in the view
                           if (form.html()) {
                              console.log('Form was invalid and was returned');
                              //update modal div
                               $('#ajax_form_modal_result_div').html(form);
                               $("#itemFormModal").modal('show');
                            }
                            //form is not returned if form submission succeeded
                            else{
                              //update the entire document with the response received since we received a entire success page and we want to reload the entire page
                              document.open();
                              document.write(response);
                              document.close();
                              //sort by modified date descending
      
                              //var notificationDiv = $("#notification", response);
                              //$('#notification').html(notificationDiv.html());
                              console.log('Form was valid and was not returned');
                              $("#itemFormModal").modal('hide');
                              }
                      },
                      error: function (request, status, error) {
                                  var div = $("ajax_form_modal_result_div", request.responseText);
                                  $('#ajax_form_modal_result_div').html(div);
                                  //implement proper error handling
                                  console.log("failure");
                                  console.log(request.responseText);
                              }
                          });
                          return false;
                      });
                    }
      </script>
      

      ..要查看服务器上发生了什么,请参见处理逻辑的视图下方:

      class UpdateTaskModalView(LoginRequiredMixin, View):
      template = 'list_management/crud/item/update_via_modal.html'
      
      def get_logic(self, request, task_id, **kwargs):
          task = get_object_or_404(Task.objects, pk=task_id)
          task_form = TaskForm(instance=task)
          context = {
                     'model_form': task_form,
                     'item': task,
          }
          return context
      
      def post_logic(self, request, task_id, **kwargs):
          task = get_object_or_404(Task.objects, pk=task_id)
          task_form = TaskForm(request.POST, instance=task)
          if task_form.is_valid():
              task = task_form.save(commit=False)
              task.modified_by = request.user
              task.save()
              messages.add_message(request, messages.INFO, 'Item "%s" successfully updated' % (task.name))
              return ('redirect', HttpResponseRedirect(reverse('show_list_after_item_update', kwargs={'list_id':task.list.pk, 'item_id':task.pk})))
          context = {
              'model_form' : task_form,
              'list': task.list,
              'item': task,
          }
          return ('context', context)
      
      def get(self, request, task_id, **kwargs):
          context = self.get_logic(request, task_id, **kwargs)
          return render_to_response(
              self.template,
              context,
              context_instance = RequestContext(request),
          )
      
      def post(self, request, task_id, **kwargs):
          post_logic_return = self.post_logic(request, task_id, **kwargs)
          if post_logic_return[0] == 'redirect':
              return post_logic_return[1]
          if post_logic_return[0] == 'context':
              context = post_logic_return[1]
              return render_to_response(
                  self.template,
                  context,
                  context_instance = RequestContext(request),
              )
      

      ..表单模板已包含在我的问题中:ajax_form_modal_result_div,您只需提供 formUpdateURL。我是通过模板完成的,现在我写这篇文章似乎很奇怪。可以通过视图上下文轻松提供。

      瞧 - 带有引导模式的 Django 表单!为您的 UI 增添趣味!

      我希望这可以帮助某人解决类似的问题。

      【讨论】:

      • 嘿,我很难理解包含 formUpdateURL 的内容。
      猜你喜欢
      • 2015-08-05
      • 2017-06-12
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      • 2022-01-09
      • 2014-09-27
      • 2015-06-27
      • 2011-02-18
      相关资源
      最近更新 更多