我正在开发一个使用Vue.js和Vue Router作为前端javascript框架的项目,该框架需要在整个应用中使用许多位置的用户选择框。我想使用select2作为选择框。为了尽量使我的代码尽可能干净,我已经实现了一个自定义过滤器来按照select2接受它的方式格式化数据,然后我实现了一个类似于the one found on the Vue.js website的自定义指令。
当应用程序启动时,它会在api中查询用户列表,然后存储该列表供以后使用。然后,我可以在应用程序的其余部分和任何路由中引用用户列表,而无需再次查询后端。我可以成功检索用户列表,通过用户列表过滤器将其传递给select2想要的格式,然后创建一个select2,并将用户列表设置为选项。
但这仅适用于具有select2的路由不是应用程序加载的第一页。例如,如果我进入主页(没有任何select2用户列表),然后转到用户页面(使用select2),它的效果很好。但是,如果我直接进入“用户”页面,则select2将没有任何选项。我想这是因为当Vue正在加载时,它会向服务器发送一个GET请求以获取用户列表,在它收到响应之前,它将继续执行异步执行并创建没有任何选项的select2,但是一旦用户列表从服务器返回,Vue就不知道如何用选项列表更新select2。
以下是我的问题:如何从AJAX调用中检索选项(对于整个应用程序只应该执行一次,无论用户选择框显示多少次),然后将它们加载到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')
}
})
Select2来自模板的示例实施
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.user_ids"
options="globals.users.data | userList"
>
</select>
答案 0 :(得分:2)
我可能已经找到了可以正常工作的东西,虽然我不确定它是最好的方法。这是我更新的代码:
从模板中实施Select2
xMyTextx
xMyTextx
x MyTextx
xMyText x
摘自app.js
<select
multiple="multiple"
style="width: 100%"
v-select="criteria.reporting_type_ids"
options="globals.types.data | typeList 'reporttoauthorities'"
class="select2-users"
>
</select>
这种方式适合我,但它仍然有点像hackish。如果有人对如何做到这一点有任何其他建议,我将不胜感激!
答案 1 :(得分:0)
谢谢,但是我正在从事公司的旧项目,由于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>