تایپاسکریپت - جلوگیری/لغو رویداد در Bootstrap Vue
من یک صفحه با کنترل b-form-select از Bootstrap Vue دارم. وقتی مقدار این کنترل را تغییر میدهم، میخواهم یک تابع اجرا شود که ممکن است این رویداد را لغو کند و مقدار را تغییر ندهد.
برای پیچیدهتر شدن اوضاع، انتخاب من در یک کامپوننت فرزند است و تابعی که اجرا میکنم در والد قرار دارد.
کامپوننت فرزند
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>
کامپوننت والد:
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>
وقتی 'ممنوع' را در انتخابکننده انتخاب میکنم، میبینم که جعبه انتخاب به این مقدار تغییر کرده است، اما ویژگی در فرزند و همچنین ویژگی در والد هنوز مقدار قدیمی را دارند، که همان چیزی است که میخواهم. چگونه میتوانم همچنین جعبه انتخاب مقدار قدیمی را داشته باشد؟
به نظر نمیرسد Bootstrap Vue یک modifier prevent روی رویداد change داشته باشد. من همچنین تلاش کردهام از رویداد بومی استفاده کنم اما همان مشکل وجود دارد.
آیا من دارم اشتباهی انجام میدهم؟
پاسخ شماره ۱
احتمالاً تجربه کاربری بهتری خواهد بود اگر گزینههای ممنوعه غیرفعال شوند تا آنکه بهطور مرموز مقدار انتخاب شده را انتخاب نکنند، اما شما میتوانید این رفتار را در هندلر رویداد تغییر خود با ذخیره مقدار قبلی و بازیابی آن در nextTick به دست آورید.
توجه داشته باشید که ساختار options شما برای استفاده با b-form-select مناسب نیست. من یک computed ساختهام که ساختار صحیح را ایجاد میکند و تنظیم disabled را مدیریت میکند، و از آن در 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>پاسخ شماره ۲
میخواهم یک راهحل بر اساس $refs و getter/setter محاسبهشده پیشنهاد دهم (اما همچنین میتوان آن را با v-bind/v-on هم پیادهسازی کرد). برای چنین عملکردی کاربردهای معتبر وجود دارد، به عنوان مثال درخواست تأیید از کاربر.
<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>
ما نیاز داریم از یک setter استفاده کنیم تا تغییرات کاربر به مدل دادهها/ذخیرهسازی منتقل نشود. قبل از اعتبارسنجی، مقدار localValue در b-form-select را به مقداری که قبل از تعامل کاربر بوده است تنظیم میکنیم. اگر اعتبارسنجی مثبت باشد، مقدار را در مدل دادهها بهروزرسانی میکنیم که باعث میشود Vue b-form-select را تازهسازی کند. اگر نه، کاری انجام نمیدهیم.
این عملیات ممکن است باعث شود هشدار Vue در مورد دستکاری مستقیم DOM صادر شود (بسته به اینکه دقیقاً اینجا چه کاری انجام میدهید)، با این حال فکر میکنم این یک استفاده موجه است، زیرا ما قصد نداریم دادهها را جایگزین مدل داده خود نمایش دهیم - برعکس - ما از نمایش دادههایی که هنوز در مدل ذخیره نشدهاند توسط مرورگر جلوگیری میکنیم.
شما همچنین میتوانید راه حل من برای همان مسئله را با استفاده از تگ <select> ساده (نه BootstrapVue - که کمی متفاوت عمل میکند) و v-bind/v-on به جای روش getter/setter اینجا بررسی کنید.
