我看过我能找到的每一个类似的帖子,但似乎没有答案可以解决我的问题。具体来说,它不会使用id“table”更新表。
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">▲</span>
<span v-else-if="questionDown == -1" id="questionDown">▼</span>
</th>
<th style="cursor:pointer; min-width: 120px; ">
Answer
<span v-if="answerSort == 1" id="answerUp">▲</span>
<span v-else-if="answerDown == -1" id="answerDown">▼</span>
</th>
<th style="cursor:pointer; min-width: 80px;">
Value
<span v-if="valueSort == 1" id="valueUp">▲</span>
<span v-else-if="valueDown == -1" id="valueDown">▼</span>
</th>
<th style="cursor:pointer; min-width: 80px;">
Show Number
<span v-if="showNumberSort == 1" id="showNumberUp">▲</span>
<span v-else-if="showNumberDown == -1" id="showNumberDown">▼</span>
</th>
<th style="cursor:pointer; min-width: 80px;">
Category
<span v-if="categorySort == 1" id="categoryUp">▲</span>
<span v-else-if="categoryDown == -1" id="categoryDown">▼</span>
</th>
<th style="cursor:pointer; min-width: 80px;">
Air Date
<span v-if="airDateSort == 1" id="airDateUp">▲</span>
<span v-else-if="airDateDown == -1" id="airDateDown">▼</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 / categories的AJAX调用正确地更新了DOM上的下拉列表,允许我选择一个类别。当应用程序安装时,它会更新表格,显示colspan 6“没有要显示的条目”单元格。但是,在发送并返回过滤器请求后,表不会更新以反映更新的数据(尽管在控制台中检查时数据正确显示为已更改)。
预期行为:
当AJAX调用/ question with query params解析并更新app中的条目数据字段时,表格会更新以反映更改。
尝试修复:
探索$ forceUpdate,$ set,Vue.set,并使用for循环手动覆盖数组。
修改
经过大量的窥探并整合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 :(得分:0)
您的代码无法运行,因为它依赖于您的服务器响应。
但我认为将您的共鸣数据设置为entries
的代码很好。
当其他js代码导致异常时,可能会出现这种问题,从而中断了vue的渲染。
所以你可以查看控制台,看看有没有错误?
答案 1 :(得分:0)
IMO问题导致Vue.set(app,...)。 AFAIK您无法在Vue实例本身上设置属性。
编辑:带有Vuex的实例和使用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/vue@2.5.2/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex@3.0.0/dist/vuex.min.js"></script>
<script src="https://unpkg.com/jquery@3.2.1/dist/jquery.min.js"></script>