2017-10-25 1 views
0

私は見つけることができるすべての同様の投稿を見てきましたが、私の問題を解決する答えはありません。具体的には、idが "table"のテーブルを更新しません。このインスタンスでVueJSがDOMの更新を停止する原因は何ですか?

HTML:

<section id="body"> 
    <div class="container-fluid"> 
     <div class="row"> 
      <div class="col-xs-12"> 
       <div class="panel panel-primary"> 
        <div class="panel-heading" id="panel"> 
         <div class="row"> 
          <div class="col-sm-12"> 
           <h3 class="panel-title">Filters</h3> 
          </div> 
         </div> 
        </div> 
        <div class="panel-body" id="panel-body"> 
         <div class="row"> 
          <div class="col-sm-12"> 
           <form id="filterForm" class="form-horizontal"> 
            <div class="form-group"> 
             <div class="col-sm-12"> 
              <label class="control-label" for="focusedInput">Category:</label> 
              <select id="category" class="js-example-basic-single form-control"> 
               <option value="">Any</option> 
               <option v-for="category in categories" value="category.categoryTitle"> 
               {{category.categoryTitle}}</option> 
              </select> 
             </div> 
            </div> 
            <div class="form-inline row"> 
             <div class="col-sm-12"> 
              <label class="control-label" style="margin-right:20px;">Air Date:</label> 
              <div style="width:35%" class="form-group"> 
               <div class='input-group date' id='datetimepicker1'> 
                <input type='text' class="form-control" v-model="airDate"/> 
                <span class="input-group-addon"> 
                 <span class="glyphicon glyphicon-calendar"></span> 
                </span> 
               </div> 
              </div> 
              <label class="control-label">Show Number:</label> 
              <input style="width:35%" class="form-control" type="number" id="showNumber" v-model="showNumber"> 
             </div> 
            </div> 
            <div class="form-inline row"> 
             <div class="col-sm-12"> 
              <label class="control-label">Question contains:</label> 
              <input style="width:35%" class="form-control" type="text" v-model="questionText"> 
              <label class="control-label">Dollar Value:</label> 
              <input style="width:35%" class="form-control" type="number" id="showNumber" v-model="dollarValue"> 
             </div> 
            </div> 
           </form> 
          </div> 
         </div> 
         <div class="row"> 
          <div class="col-sm-offset-9 col-sm-3" style="margin-top:5px;">         
           <button type="button" class="btn btn-warning" v-on:click="reset">Reset Filters</button> 
           <button type="button" class="btn btn-primary" v-on:click="filter">Filter</button> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
     <div class="row"> 
      <div class="col-xs-12"> 
       <div class="panel panel-primary" id="tableCard" style="margin-bottom:20px; margin-top:40px;"> 
        <div class="panel-heading"> 
         <div class="row"> 
          <div class="col-sm-10"> 
           <h3 class="panel-title">Jeopardy Questions</h3> 
          </div> 
          <div class="col-sm-2"> 
           <span id="totalQuestionsSpan">Total Entries: {{entries.length}} entries</span> 
          </div> 
         </div> 
        </div> 
        <div class="panel-body" style="padding-top:45px;"> 
         <div class="wrapper"> 
          <table id="tableScroll" class="table table-striped table-fixed"> 
           <thead style="background-color:white;"> 
            <tr> 
             <th style="cursor:pointer; min-width: 110px;"> 
              Question 
              <span v-if="questionSort == 1" id="questionUp">&#9650;</span> 
              <span v-else-if="questionDown == -1" id="questionDown">&#9660;</span> 
             </th> 
             <th style="cursor:pointer; min-width: 120px; "> 
              Answer 
              <span v-if="answerSort == 1" id="answerUp">&#9650;</span> 
              <span v-else-if="answerDown == -1" id="answerDown">&#9660;</span> 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Value 
              <span v-if="valueSort == 1" id="valueUp">&#9650;</span> 
              <span v-else-if="valueDown == -1" id="valueDown">&#9660;</span> 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Show Number 
              <span v-if="showNumberSort == 1" id="showNumberUp">&#9650;</span> 
              <span v-else-if="showNumberDown == -1" id="showNumberDown">&#9660;</span> 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Category 
              <span v-if="categorySort == 1" id="categoryUp">&#9650;</span> 
              <span v-else-if="categoryDown == -1" id="categoryDown">&#9660;</span> 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Air Date 
              <span v-if="airDateSort == 1" id="airDateUp">&#9650;</span> 
              <span v-else-if="airDateDown == -1" id="airDateDown">&#9660;</span> 
             </th> 
            </tr> 
           </thead> 
           <tbody id="table"> 
            <tr v-for="entry in entries"> 
             <td>{{entry.questionText}}</td> 
             <td>{{entry.answerText}}</td> 
             <td>{{entry.dollarValue}}</td> 
             <td>{{entry.showNumber}}</td> 
             <td>{{entry.categoryTitle}}</td> 
             <td>{{entry.airDate}}</td> 
            </tr> 
            <tr v-if="entries.length == 0"> 
             <td colspan="6" style="text-align: center;"> No entries to display </td> 
            </tr> 
           </tbody> 
          </table> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
</section> 

JS

var app = new Vue({ 
     el: '#body', 
     data: { 
      loggedIn: false, 
      questionSort: 0, 
      answerSort: 0, 
      valueSort: 0, 
      showNumberSort: 0, 
      categorySort: 0, 
      airDateSort: 0, 
      entries: [], 
      url: "/questions", 
      categories: [], 

      // form model data 
      categoryTitle: '', 
      airDate: '', 
      questionText: '', 
      dollarValue: '', 
      showNumber: '', 
     }, 
     mounted: function() { 
      $.get("/api/categories", function(result) { 
       Vue.set(app, "categories", result.data); 
       $('.js-example-basic-single').select2(); 
      }, "json").fail(function(err) { 
       showErrorMessage(err.responseJSON.message_prettified); 
      }); 
     }, 
     methods: { 
      filter : function() { 
       var queryParams = "?"; 
       var params = 0; 
       app.categoryTitle = $('#category :selected').text().trim(); 
       if (typeof app.categoryTitle !== "undefined" && app.categoryTitle != null) { 
        params++; 
        queryParams += "categoryTitle=" + app.categoryTitle 
       } 
       if (app.airDate.length > 0) { 
        params++; 
        if (params > 0) { 
         queryParams += "&"; 
        } 
        queryParams += "airDate=" + app.airDate 
       } 
       if (app.questionText.length > 0) { 
        params++; 
        if (params > 0) { 
         queryParams += "&"; 
        } 
        queryParams += "questionText=" + app.questionText 
       } 
       if (app.dollarValue.length > 0) { 
        params++; 
        if (params > 0) { 
         queryParams += "&"; 
        } 
        queryParams += "dollarValue=" + app.dollarValue 
       } 
       if (app.showNumber.length > 0) { 
        params++; 
        if (params > 0) { 
         queryParams += "&"; 
        } 
        queryParams += "showNumber=" + app.showNumber 
       } 
       if (queryParams.length == 1) { 
        queryParams = ""; 
       } 
       var url = "/questions" 
       var URL = url + queryParams; 
       $.get(URL, result => { 
         Vue.set(app, "entries", result.data); 
         app.$forceUpdate(); 
        }, "json").fail(function(err) { 
         showErrorMessage(err.responseJSON.message_prettified); 
        }).always(function() { 
         $("#loader").addClass("toggled"); 
       }); 
      } 
     } 
    }); 

現在の行動:

/API /カテゴリへのAJAX呼び出しが正しく、私はカテゴリを選択することができ、DOMのドロップダウンを更新。アプリケーションがマウントされると、表が更新され、colspan 6「表示する項目がありません」というセルが表示されます。ただし、フィルタ要求が送信されて返された後、テーブルは更新されたデータを反映するように更新されません(コンソールでチェックされたときにデータが正しく変更されたとして表示されます)。

期待される動作:

AJAX呼び出しクエリのparams解決さとの質問/へとテーブルの更新は、変更を反映するために、アプリ内のエントリのデータフィールドを更新します。

未遂修正:

探検$ forceUpdate、$セット、Vue.set、および手動でループに使用して配列を上書きします。

編集:

スヌーピングともVueXの統合の多くを行った後(@WaldemarIceによって以下示唆されているように)助けたが、関係なく、私がきた、私のミニプログラムの全体的なコードの構造を改善しましたたかもしれません解決策に到着しました。

Laracast上のこの投稿は、私はおそらく、データに問題があったかどうかを疑問に思う行わ:その後、私は問題を実現させhttps://laracasts.com/discuss/channels/vue/v-for-loop-rendering-keeps-throwing-undefined-error

は、ここでのコード行にあった:

原因となった
<option v-for="category in categories" value="category.categoryTitle"> 
              {{category.categoryTitle}}</option> 

value = category.categoryTitleのカテゴリは、ライフサイクルの後半まで定義されていなかったため、問題が発生しました。私はそれをv-bindに変更しました:value = "category.categoryTitle"そしてJSを更新して今すぐ動作させました。 @Kaicuiの投稿に関するフォローアップの議論で投稿したTypeErrorは、Vueにデータの反応性を失わせていました。私がその問題を解決すると、Vueは再び適切に反応し始めました。

更新HTML:

<section id="body"> 
    <div class="container-fluid"> 
     <div class="row"> 
      <div class="col-xs-12"> 
       <div class="panel panel-primary"> 
        <div class="panel-heading" id="panel"> 
         <div class="row"> 
          <div class="col-sm-11"> 
           <h3 class="panel-title">Filters</h3> 
          </div> 
          <div class="col-sm-1"> 
           <i id="toggleFilter" class="fa fa-chevron-down filter-collapsed" style="cursor:pointer; display:none;" aria-hidden="true"></i> 
           <i id="toggleFilter" class="fa fa-chevron-up filter-collapsed" aria-hidden="true" style="cursor:pointer;"></i> 
          </div> 
         </div> 
        </div> 
        <div class="panel-body" id="panel-body"> 
         <div class="row"> 
          <div class="col-sm-12"> 
           <form id="filterForm" method="GET" action="/questions" class="form-horizontal"> 
            <div class="form-inline"> 
             <div class="col-sm-12" style="margin-bottom:15px;"> 
              <input type="hidden" name="categoryTitle" id="categoryTitleHidden"> 
              <label class="control-label" for="focusedInput">Category:</label> 
              <select style="width:90%; height:120% !important;" v-model="categorySelect" id="category" class="js-example-basic-single form-control"> 
               <option value="">Any</option> 
               <option v-for="category in categories" v-bind:value="category.categoryTitle"> 
               {{category.categoryTitle}}</option> 
              </select> 
             </div> 
            </div> 
            <div class="form-inline"> 
             <div class="col-sm-12" style="margin-bottom:15px;"> 
              <label class="control-label" style="margin-right:20px;">Air Date:</label> 
              <div style="width:35%; margin-right:10px" class="form-group"> 
               <div style="width:100%" class='input-group date' id='datetimepicker1'> 
                <input type='text' class="form-control" name="airDate"/> 
                <span class="input-group-addon"> 
                 <span class="glyphicon glyphicon-calendar"></span> 
                </span> 
               </div> 
              </div> 
              <label class="control-label">Show Number:</label> 
              <input style="width:35%" class="form-control" type="number" id="showNumber" name="showNumber"> 
             </div> 
            </div> 
            <div class="form-inline"> 
             <div class="col-sm-12"> 
              <label class="control-label">Question contains:</label> 
              <input style="width:35%" class="form-control" type="text" id="questionText" name="questionText"> 
              <label class="control-label">Dollar Value:</label> 
              <input style="width:35%" class="form-control" type="number" id="dollarValue" name="dollarValue"> 
             </div> 
            </div> 
           </form> 
          </div> 
         </div> 
         <div class="row"> 
          <div class="col-sm-offset-9 col-sm-3" style="margin-top:5px;"> 
           <button type="button" class="btn btn-warning" v-on:click="reset">Reset Filters</button> 
           <button type="button" class="btn btn-primary" v-on:click="filter">Filter</button> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
     <div class="row"> 
      <div class="col-xs-12"> 
       <div class="panel panel-primary" id="tableCard" style="margin-bottom:20px; margin-top:40px;"> 
        <div class="panel-heading"> 
         <div class="row"> 
          <div class="col-sm-10"> 
           <h3 class="panel-title">Jeopardy Questions</h3> 
          </div> 
          <div class="col-sm-2"> 
           <span id="totalQuestionsSpan">Total Entries: {{entryCount}} entries</span> 
          </div> 
         </div> 
        </div> 
        <div class="panel-body" style="padding-top:45px;"> 
         <div class="wrapper"> 
          <table id="tableScroll" class="table table-striped table-fixed"> 
           <thead style="background-color:white;"> 
            <tr> 
             <th style="cursor:pointer; min-width: 110px;"> 
              Question 
             </th> 
             <th style="cursor:pointer; min-width: 120px; "> 
              Answer 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Value 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Show Number 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Category 
             </th> 
             <th style="cursor:pointer; min-width: 80px;"> 
              Air Date 
             </th> 
            </tr> 
           </thead> 
           <tbody id="table"> 
            <tr v-if="entriesValid" v-for="entry in entries"> 
             <td>{{entry.questionText}}</td> 
             <td>{{entry.answerText}}</td> 
             <td>{{entry.dollarValue}}</td> 
             <td>{{entry.showNumber}}</td> 
             <td>{{entry.categoryTitle}}</td> 
             <td>{{entry.airDate}}</td> 
            </tr> 
            <tr v-if="!entriesValid"> 
             <td colspan="6" style="text-align: center;"> No entries to display </td> 
            </tr> 
           </tbody> 
          </table> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
    <div style="position: absolute; left: 45%; top:25%; z-index:3;"> 
     <i id="loader" class="fa fa-circle-o-notch fa-spin fa-5x fa-fw toggled" style="z-index:3"></i> 
    </div> 
</section> 

更新JS

Vue.use(Vuex) 
    Vue.config.debug = false; 
    Vue.config.silent = true; 
    var URL; 
    const store = new Vuex.Store({ 
     state: { 
      loggedIn: false, 

      // ordering data 
      questionSort: 0, 
      answerSort: 0, 
      valueSort: 0, 
      showNumberSort: 0, 
      categorySort: 0, 
      airDateSort: 0, 

      // server related ata 
      entries: [], 
      url: "/questions", 
      categories: [{ 
       categoryTitle: "Test", 
      }], 
     }, 
     mutations: { 
      categories (state, data) { 
       state.categories = data; 
      }, 
      entries (state, data) { 
       console.log(data); 
       state.entries = data; 
       console.log(state.entries) 
      } 
     }, 
     actions: { 
      fetchCategories ({ commit }) { 
       $("#loader").removeClass("toggled"); 
       $.get("/api/categories", function(result) { 
        commit('categories', result.data); 
       }, "json") 
       .fail(function(err) { 
        if (err.status == 0) { 
         showErrorMessage("Network Problem"); 
        } 
        else { 
         showErrorMessage(err.responseJSON.message_prettified); 
        } 
       }).always(function() { 
        $("#loader").addClass("toggled"); 
       }); 
      }, 
     }, 
    }); 

    var app = new Vue({ 
     el: '#body', 
     store: store, 
     data: { 
      categorySelect: "", 
     }, 
     mounted: function() { 
      store.dispatch("fetchCategories").then(() => { 
       $('.js-example-basic-single').select2(); 
      }); 
     }, 
     computed: { 
      categories: function() { 
       return store.state.categories; 
      }, 
      entryCount: function() { 
       if (store.entries) { 
        if (typeof store.entries.length !== "undefined") { 
         return store.entries.length; 
        } 
        else { 
         return 0; 
        } 
       } 
       else { 
        return 0; 
       } 
      }, 
      entriesValid: function() { 
       if (store.state.entries) { 
        if (typeof store.state.entries.length !== "undefined" && store.state.entries.length > 0) { 
         return true; 
        } 
        else { 
         return false; 
        } 
       } 
       else { 
        return false; 
       } 
      }, 
      entries: function() { 
       return store.state.entries; 
      }, 
      loggedIn: function() { 
       return store.state.loggedIn; 
      }, 
     }, 
     methods: { 
      reset: function() { 
       $('.js-example-basic-single').val('').trigger('change'); 
       $("#datetimepicker1").datetimepicker("clear"); 
       $("#categoryTitleHidden").val(""); 
       $("#showNumber").val(""); 
       $("#questionText").val(""); 
       $("#showNumber").val(""); 
       $("#dollarValue").val(""); 
      }, 
      filter : function() { 
       var value = $('#category :selected').text().trim(); 
       if (value !== "Any") { 
        $("#categoryTitleHidden").val(value); 
       } 
       else { 
        $("#categoryTitleHidden").val(""); 
       } 
       var options = { 
        success: function(responseText, statusText, xhr, $form) { 
         store.commit("entries", JSON.parse(xhr.responseText).data) 
        } 
       }; 
       $("#filterForm").ajaxSubmit(options); 
      } 
     } 
    }); 

答えて

0

IMOの問題により、Vue.set(app、...)が発生しています。 AFAIKでは、Vueインスタンス自体にプロパティを設定することはできません。

EDIT:jQueryの

var store = new Vuex.Store({ 
 
    state: { 
 
    // Car manufacturers for datalist will be held here. 
 
    // Cars are globally accessible, in every component, 
 
    // as this.$store.state.cars 
 
    cars: null 
 
    }, 
 
    mutations: { 
 
    // Mutations changes state, but must be sync, 
 
    // so you can't call $.get() or another 
 
    // async function in any mutation. 
 
    updateCars: function (state, payload) { 
 
     state.cars = payload 
 
    } 
 
    }, 
 
    actions: { 
 
    // For async ops there are actions, 
 
    // but they can't change state - for state 
 
    // change fire particular mutation. 
 
    loadCars: function (context, payload) { 
 
     $.get(payload.src).then(function (data) { 
 
     context.commit('updateCars', data) 
 
     }) 
 
    } 
 
    } 
 
}) 
 

 
Vue.component('my-list', { 
 
    template: '#my-list', 
 
    props: ['src'], 
 
    // All components see this.$store.state.cars, but 
 
    // still can have own local data. 
 
    data: function() { 
 
    return { 
 
     manufacturer: '' 
 
    } 
 
    }, 
 
    // Fire async store action 
 
    created: function() { 
 
    this.$store.dispatch({ 
 
     type: 'loadCars', 
 
     src: this.src 
 
    }) 
 
    } 
 
    // Alternatively, you can use this 
 
    // version - w/o action. It's OK to use 
 
    // mutation here, in callback of async function. 
 
    /* created: function() { 
 
    $.get(this.src).then(function (data) { 
 
     this.$store.commit('updateCars', data) 
 
    }) 
 
    } */ 
 
}) 
 

 
new Vue({ 
 
    el: '#app', 
 
    // Inject store state to all components 
 
    store: store 
 
})
<div id="app"> 
 
    <my-list src="https://api.mockaroo.com/api/32318a80?count=20&key=cdbbbcd0"> 
 
    </my-list> 
 
</div> 
 

 
<template id="my-list"> 
 
    <div> 
 
    <label> 
 
     Choose a car manufacturer:<br> 
 
     <input list="cars" name="myCars" v-model="manufacturer"> 
 
    </label> 
 
    <datalist id="cars"> 
 
     <option 
 
     v-for="car in $store.state.cars" 
 
     :value="car.car" 
 
     > 
 
     {{ car.id }} 
 
     </option> 
 
    </datalist> 
 
    <p> 
 
     Selected manufacturer:<br> 
 
     {{ manufacturer }} 
 
    </p> 
 
    </div> 
 
</template> 
 

 
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script> 
 
<script src="https://unpkg.com/[email protected]/dist/vuex.min.js"></script> 
 
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>

+0

私は直接割り当て(app.entries = result.data)を試みましたが、それもうまくいきませんでした。私は、Vue.set関数がDOMの強制的な更新を引き起こすかもしれないという読書を行っていました(うまくいきませんでした)。 代わりに何をお勧めしますか? – Pedro

+0

Vueインスタンスのルートデータオブジェクトにプロパティを設定することはできないため、Vuexを使用することができます。 – WaldemarIce

+0

私はVuexに一発のショットを与え、問題が解決するかどうかを確認します。提案していただきありがとうございます!一度私はそれを与えた私はチェックインします。 – Pedro

0

それはあなたのサーバの応答に依存しているので、あなたのコードを実行することはできません。

しかし、私はentriesに共振データを設定するあなたのコードはいいと思います。

この種の問題は、他のjsコードがvueのレンダリングを中断させる例外を引き起こした場合に発生することがあります。

コンソールを確認してエラーがありますか?

+0

とVuexと非同期データとライブの例では、サーバの応答は、本質的に単にJSONオブジェクトの配列、イリノイポストことを示すコンソールの画像でありますAJAXが解決した後にアプリが持つもの 投稿のAJAXコンテンツ: https://imgur.com/a/Qcuby JSONスキーマの例 https://imgur.com/a/V9F91 – Pedro

+0

残念ながら、DOMにはまだこれが表示されています。https://imgur.com/a/bl38w – Pedro

+0

VueJSエラーがありますが、それは読み込まれる前にデータの参照と関係があるgoogleでした、そして読み込まれるとそれ自身を解決します。私はここでエラーの写真を提供します。 https://imgur.com/a/OEVuF – Pedro

関連する問題