Vue.js 正在为 Select2 中的选项检索远程数据
Vue.js Retrieving Remote Data for Options in Select2
我正在开发一个使用 Vue.js and Vue Router as the frontend javascript framework that will need to use a select box of users many places throughout the app. I would like to use select2 for the select box. To try to make my code the cleanest I can, I've implemented a custom filter to format the data the way select2 will accept it, and then I've implemented a custom directive similar to the one found on the Vue.js website.
的项目
当应用程序启动时,它会查询 api 以获取用户列表,然后存储该列表供以后使用。然后,我可以在整个应用程序的其余部分以及从任何路径引用用户列表,而无需再次查询后端。我可以成功检索用户列表,通过用户列表过滤器传递它以按照 select2 想要的方式对其进行格式化,然后创建一个 select2 并将用户列表设置为选项。
但这仅在具有 select2 的路由不是应用程序加载的第一个页面时才有效。例如,如果我到达主页(没有任何 select2 用户列表)然后转到用户页面(带有 select2),效果很好。但是如果我直接进入用户页面,select2 将没有任何选项。我想这是因为当 Vue 正在加载时,它会向服务器发送一个 GET 请求以获取用户列表,并且在收到响应之前,它将继续其异步执行并创建 select2 而不任何选项,但是一旦用户列表从服务器返回,Vue 就不知道如何使用选项列表更新 select2。
这是我的问题:如何从 AJAX 调用中检索选项(无论用户 select 框出现多少次,整个应用程序都应该只调用一次显示),然后将它们加载到 select2,即使直接进入带有 select2 的页面?
提前致谢!如果您注意到我应该做的任何其他事情,请告诉我,因为我希望此代码使用最佳实践。
这是我目前的情况:
简体app.js
var App = Vue.extend({
ready: function() {
this.fetchUsers();
},
data: function() {
return {
globals: {
users: {
data: []
},
}
};
},
methods: {
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
});
},
}
});
来自 API
的示例响应
{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Smith",
"active": 1
},
{
"id": 2,
"first_name": "Emily",
"last_name": "Johnson",
"active": 1
}
]
}
用户列表过滤器
Vue.filter('userList', function (users) {
if (users.length == 0) {
return [];
}
var userList = [
{
text : "Active Users",
children : [
// { id : 0, text : "Item One" }, // example
]
},
{
text : "Inactive Users",
children : []
}
];
$.each( users, function( key, user ) {
var option = { id : user.id, text : user.first_name + ' ' + user.last_name };
if (user.active == 1) {
userList[0].children.push(option);
}
else {
userList[1].children.push(option);
}
});
return userList;
});
自定义 Select2 指令(类似于 this)
Vue.directive('select', {
twoWay: true,
bind: function () {
},
update: function (value) {
var optionsData
// retrive the value of the options attribute
var optionsExpression = this.el.getAttribute('options')
if (optionsExpression) {
// if the value is present, evaluate the dynamic data
// using vm.$eval here so that it supports filters too
optionsData = this.vm.$eval(optionsExpression)
}
var self = this
var select2 = $(this.el)
.select2({
data: optionsData
})
.on('change', function () {
// sync the data to the vm on change.
// `self` is the directive instance
// `this` points to the <select> element
self.set(select2.val());
console.log('emitting "select2-change"');
self.vm.$emit('select2-change');
})
// sync vm data change to select2
$(this.el).val(value).trigger('change')
},
unbind: function () {
// don't forget to teardown listeners and stuff.
$(this.el).off().select2('destroy')
}
})
从模板中选择 2 的示例实现
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.user_ids"
options="globals.users.data | userList"
>
</select>
我可能找到了一些可行的方法,尽管我不确定这是解决问题的最佳方法。这是我更新的代码:
从模板中实现 Select2
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.reporting_type_ids"
options="globals.types.data | typeList 'reporttoauthorities'"
class="select2-users"
>
</select>
摘自app.js
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
this.$nextTick(function () {
var optionsData = this.$eval('globals.users.data | userList');
console.log('optionsData', optionsData);
$('.select2-users').select2({
data: optionsData
});
});
});
},
这种方式对我有用,但感觉还是有点老套。如果有人对如何执行此操作有任何其他建议,我将不胜感激!
谢谢,但我正在处理公司遗留项目,由于 select2
的低版本,我遇到了 this issue。而且我不确定 v-select
语法是否来自 vue 标准(也许来自 vue-select
libaray?)。所以这是我基于你的实现。使用 input
标签代替 select
标签,v-model
代替 v-select
。它就像一个魅力,再次感谢@bakerstreetsystems
<input type="text"
multiple="multiple"
style="width: 300px"
v-model="supplier_id"
options="suppliers"
id="select2-suppliers"
>
</input>
<script>
$('#app').ready(function() {
var app = new Vue({
el: "#app",
data: {
supplier_id: '<%= @supplier_id %>', // We are using server rendering(ruby on rails)
suppliers: [],
},
ready: function() {
this.fetchSuppliers();
},
methods: {
fetchSuppliers: function() {
var self = this;
$.ajax({
url: '/admin_sales/suppliers',
method: 'GET',
success: function(res) {
self.suppliers = res.data;
self.$nextTick(function () {
var optionsData = self.suppliers;
$('#select2-suppliers').select2({
placeholder: "Select a supplier",
allowClear: true,
data: optionsData,
});
});
}
});
},
},
});
})
</script>
我正在开发一个使用 Vue.js and Vue Router as the frontend javascript framework that will need to use a select box of users many places throughout the app. I would like to use select2 for the select box. To try to make my code the cleanest I can, I've implemented a custom filter to format the data the way select2 will accept it, and then I've implemented a custom directive similar to the one found on the Vue.js website.
的项目当应用程序启动时,它会查询 api 以获取用户列表,然后存储该列表供以后使用。然后,我可以在整个应用程序的其余部分以及从任何路径引用用户列表,而无需再次查询后端。我可以成功检索用户列表,通过用户列表过滤器传递它以按照 select2 想要的方式对其进行格式化,然后创建一个 select2 并将用户列表设置为选项。
但这仅在具有 select2 的路由不是应用程序加载的第一个页面时才有效。例如,如果我到达主页(没有任何 select2 用户列表)然后转到用户页面(带有 select2),效果很好。但是如果我直接进入用户页面,select2 将没有任何选项。我想这是因为当 Vue 正在加载时,它会向服务器发送一个 GET 请求以获取用户列表,并且在收到响应之前,它将继续其异步执行并创建 select2 而不任何选项,但是一旦用户列表从服务器返回,Vue 就不知道如何使用选项列表更新 select2。
这是我的问题:如何从 AJAX 调用中检索选项(无论用户 select 框出现多少次,整个应用程序都应该只调用一次显示),然后将它们加载到 select2,即使直接进入带有 select2 的页面?
提前致谢!如果您注意到我应该做的任何其他事情,请告诉我,因为我希望此代码使用最佳实践。
这是我目前的情况:
简体app.js
var App = Vue.extend({
ready: function() {
this.fetchUsers();
},
data: function() {
return {
globals: {
users: {
data: []
},
}
};
},
methods: {
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
});
},
}
});
来自 API
的示例响应{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Smith",
"active": 1
},
{
"id": 2,
"first_name": "Emily",
"last_name": "Johnson",
"active": 1
}
]
}
用户列表过滤器
Vue.filter('userList', function (users) {
if (users.length == 0) {
return [];
}
var userList = [
{
text : "Active Users",
children : [
// { id : 0, text : "Item One" }, // example
]
},
{
text : "Inactive Users",
children : []
}
];
$.each( users, function( key, user ) {
var option = { id : user.id, text : user.first_name + ' ' + user.last_name };
if (user.active == 1) {
userList[0].children.push(option);
}
else {
userList[1].children.push(option);
}
});
return userList;
});
自定义 Select2 指令(类似于 this)
Vue.directive('select', {
twoWay: true,
bind: function () {
},
update: function (value) {
var optionsData
// retrive the value of the options attribute
var optionsExpression = this.el.getAttribute('options')
if (optionsExpression) {
// if the value is present, evaluate the dynamic data
// using vm.$eval here so that it supports filters too
optionsData = this.vm.$eval(optionsExpression)
}
var self = this
var select2 = $(this.el)
.select2({
data: optionsData
})
.on('change', function () {
// sync the data to the vm on change.
// `self` is the directive instance
// `this` points to the <select> element
self.set(select2.val());
console.log('emitting "select2-change"');
self.vm.$emit('select2-change');
})
// sync vm data change to select2
$(this.el).val(value).trigger('change')
},
unbind: function () {
// don't forget to teardown listeners and stuff.
$(this.el).off().select2('destroy')
}
})
从模板中选择 2 的示例实现
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.user_ids"
options="globals.users.data | userList"
>
</select>
我可能找到了一些可行的方法,尽管我不确定这是解决问题的最佳方法。这是我更新的代码:
从模板中实现 Select2
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.reporting_type_ids"
options="globals.types.data | typeList 'reporttoauthorities'"
class="select2-users"
>
</select>
摘自app.js
fetchUsers: function() {
this.$http.get('./api/v1/users/list', function(data, status, response) {
this.globals.users = data;
this.$nextTick(function () {
var optionsData = this.$eval('globals.users.data | userList');
console.log('optionsData', optionsData);
$('.select2-users').select2({
data: optionsData
});
});
});
},
这种方式对我有用,但感觉还是有点老套。如果有人对如何执行此操作有任何其他建议,我将不胜感激!
谢谢,但我正在处理公司遗留项目,由于 select2
的低版本,我遇到了 this issue。而且我不确定 v-select
语法是否来自 vue 标准(也许来自 vue-select
libaray?)。所以这是我基于你的实现。使用 input
标签代替 select
标签,v-model
代替 v-select
。它就像一个魅力,再次感谢@bakerstreetsystems
<input type="text"
multiple="multiple"
style="width: 300px"
v-model="supplier_id"
options="suppliers"
id="select2-suppliers"
>
</input>
<script>
$('#app').ready(function() {
var app = new Vue({
el: "#app",
data: {
supplier_id: '<%= @supplier_id %>', // We are using server rendering(ruby on rails)
suppliers: [],
},
ready: function() {
this.fetchSuppliers();
},
methods: {
fetchSuppliers: function() {
var self = this;
$.ajax({
url: '/admin_sales/suppliers',
method: 'GET',
success: function(res) {
self.suppliers = res.data;
self.$nextTick(function () {
var optionsData = self.suppliers;
$('#select2-suppliers').select2({
placeholder: "Select a supplier",
allowClear: true,
data: optionsData,
});
});
}
});
},
},
});
})
</script>