typescript - Bootstrap Vue ngăn chặn/hủy sự kiện
Tôi có một trang với một điều khiển b-form-select từ Bootstrap Vue. Khi tôi thay đổi giá trị của điều khiển này, tôi muốn thực hiện một hàm có thể hủy sự kiện này và không thay đổi giá trị.
Để làm mọi thứ phức tạp hơn, select của tôi nằm trong một component con và hàm mà tôi thực thi nằm trong component cha.
Thành phần con
public values: any[] = [
{ name: 'default'},
{ name: 'forbidden'},
{ name: 'other option' },
]
<b-form-select :value="property" @change="$emit('onPropertyChange', arguments[0])">
<option v-for="(val, key) in values" :value="val" :key="key">{{val.Name}}</option>
</b-form-select>
Thành phần cha:
this.property = { name: 'default' }
public onPropertyChange(newValue) {
if (newValue.name === 'forbidden') {
// Not changing this.property
} else {
// Changing it
this.property = newValue
}
}
<child :property="property" @onPropertyChange="onPropertyChange"></child>
Khi tôi chọn 'bị cấm' trong ô chọn. Tôi thấy rằng hộp chọn đã thay đổi thành giá trị này, nhưng thuộc tính trong phần tử con cũng như thuộc tính trong phần tử cha vẫn giữ giá trị cũ, điều mà tôi muốn. Làm thế nào để tôi cũng có thể giữ giá trị cũ cho ô chọn?
Bootstrap Vue dường như không có một modifier prevent trên sự kiện change. Tôi cũng đã thử sử dụng sự kiện gốc nhưng vấn đề vẫn giống nhau.
Tôi có đang làm gì sai không?
Câu trả lời #1
Có lẽ trải nghiệm người dùng sẽ tốt hơn nếu vô hiệu hóa các tùy chọn bị cấm thay vì bí ẩn để chúng không chọn giá trị đã chọn, nhưng bạn có thể có hành vi đó trong trình xử lý sự kiện thay đổi của mình bằng cách lưu giá trị cũ và khôi phục nó trên nextTick.
Lưu ý rằng cấu trúc options của bạn không phù hợp để sử dụng với b-form-select. Tôi đã tạo một computed để tạo ra cấu trúc đúng và xử lý việc đặt disabled, và đã sử dụng nó trong b-form-select.
new Vue({
el: '#app',
data: {
selected: 'default',
options: [{
name: 'default',
},
{
name: 'forbidden'
},
{
name: 'other option'
},
{
name: 'what I had before'
},
]
},
computed: {
selectOptions() {
return this.options.map((opt) => ({
text: opt.name,
value: opt.name,
disabled: opt.name === 'forbidden'
}));
}
},
methods: {
onChange(newValue) {
const oldValue = this.selected;
if (newValue === 'what I had before') {
this.$nextTick(() => {
this.selected = oldValue;
});
}
}
}
});<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>
<div id="app">
<b-form-select v-model="selected" :options="selectOptions" @change="onChange">
</b-form-select>
<div>Selected: <strong>{{selected}}</strong></div>
</div>Câu trả lời #2
Tôi muốn đề xuất một giải pháp dựa trên $refs và getter/setter tính toán (nhưng cũng có thể đạt được bằng v-bind/v-on). Có những trường hợp sử dụng hợp lý cho chức năng này, ví dụ như yêu cầu người dùng xác nhận.
<template>
<div>
<b-form-select
ref="mySelect"
v-model="choiceHandler"
:options="selectOptions"
>
</b-form-select>
</div>
</template>
<script>
export default {
data() {
return {
selectOptions: [
{ value: 1, text: "Choice 1" },
{ value: 2, text: "Choice 2" },
{ value: 3, text: "Choice 3" },
],
storedChoice: 3,
};
},
computed: {
choiceHandler: {
get() {
return this.storedChoice;
},
set(newValue) {
this.$refs.typeSelect.localValue = this.storedChoice; // this reverts displayed value to the one resulting from stored value
let confirmDialog = new Promise((resolve) => {
// this promise is a mockup for an asycnc dialog returning true / false
setTimeout(() => {
resolve(true);
}, 1500);
});
confirmDialog.then((res) => {
if (res) {
this.storedChoice = newValue;
} else console.log("No changes");
});
},
},
},
};
</script>
Chúng ta cần sử dụng một setter để ngăn thay đổi từ người dùng được truyền đến mô hình dữ liệu/cửa hàng. Trước khi xác thực, chúng ta đặt localValue của b-form-select bằng giá trị trước khi người dùng tương tác. Nếu xác thực thành công, chúng ta cập nhật giá trị trong mô hình dữ liệu, điều này khiến Vue làm mới b-form-select. Nếu không, chúng ta không làm gì cả.
Hoạt động này có thể kích hoạt Cảnh báo Vue về việc thao tác trực tiếp trên DOM (tùy thuộc vào chính xác những gì bạn làm ở đây), tuy nhiên tôi nghĩ đây là một việc sử dụng hợp lý, vì chúng ta không cố gắng hiển thị dữ liệu ghi đè lên mô hình dữ liệu của mình - ngược lại - chúng ta đang ngăn trình duyệt hiển thị dữ liệu chưa được lưu trong mô hình.
Bạn cũng có thể kiểm tra tại đây giải pháp của tôi cho cùng một vấn đề sử dụng thẻ <select> thuần (không phải BootstrapVue - nó hoạt động hơi khác) và v-bind/v-on thay vì cách tiếp cận getter/setter.
