9

私のユースケースは次のとおりです。

a) ajax を介して読み込まれたフォームをブートストラップ モーダルに表示します。派手なオーバーレイ効果のものです私はこれらの指示に従いました。

これはうまくいきます。(以下のコードを参照)

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>

モーダルの読み込みと表示は正常に機能します。しかし、今度は期待どおりに機能しない 2 番目の部分が来ます。問題は以下です。フォームが検証されない場合、ビューはフォームを返します。返されたフォームは、ブートストラップ モーダルに再度表示されます。しかし、その結果、ブラウザにはフォームのみが表示され、それ以外はすべて失われます。CSSもテーブルもフォームもありません。かなり醜い..したがって、ajax_form_modal_result_divを更新できませんでした。ここで私が間違っていることを誰か助けてもらえますか..!?

ビューは、フォームのデフォルトの動作を防ぎ、ajax 経由でフォームを送信する js 関数 'submitItemModalFormBind' も返します。

<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> 
4

2 に答える 2

8

(このソリューションに基づいて、無効なフォームの処理で強化された)実用的なアプローチを見つけ、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>

モーダルに表示したいフォームと formUpdateURLDiv をロードする modalConnect 関数:

<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 にスパイスを加えましょう!

これが誰かが同様の問題を解決するのに役立つことを願っています。

于 2012-08-15T15:54:18.157 に答える