Customizing checkbox/radio labels in HTML format - vue-formulate

Using the options attribute when setting up an array of checkbox and/or radio elements, how can one customize the label in HTML format for each radio/checkbox? For example, I want to style the Date/Time with break returns -- see output example below:
[ ] Tuesday, Jan 1
5:00pm to 7:30pm
[ ] Wednesday, Jan 2
6:00am to 8:00am
[ ] Friday, Jan 4
1:00pm to 3:30pm
Here's the vue code:
<FormulateInput
type="checkbox"
label="Select dates that applies"
:options="options"
v-model="dates"
>

Vue Formulate, by default, does not use v-html for labels (for security reasons). However, you can choose to implement your own slotComponent for labels that does.
import VueFormulate from '#braid/vue-formulate'
import MyLabel from './MyLabel.vue'
Vue.component('MyLabel', MyLabel)
Vue.use(VueFormulate, {
slotComponents: {
label: 'MyLabel'
}
})
// MyLabel.vue
<template>
<label
class="context.classes.label"
for="context.id"
v-html="context.label"
/>
</template>
<script>
export default {
props: {
context: {
type: Object,
required: true
}
}
}
</script>
Then in your options objects, you would be able to use HTML strings as the keys:
const dates = [
{ label: 'Tuesday, Jan 1<br>5:00pm to 7:30pm': value: '01-01-2020' }
{ label: 'Wednesday, Jan 2<br>6:00am to 8:00am': value: '01-02-2020' }
]

Related

Vue El-Select doesn't work as expected while passing value from parent to child using watch

Component A
<el-select v-model="value" placeholder="Select Action" #change="updateDropdowns($event)" prop="action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
<script>
export default {
name: 'warehouseAdd',
components: {
tableview
},
props: [
'component'
],
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: '',
Component B
<script>
props: [
'action'
],
watch: {
'action': function (value) {
console.log(value);
//Select value from dropdown doesn't pass the value at 1st attempt.
//If I again select the value from dropdown then I get the value.
}
}
Here whenever I try to get value.. I am unable to get value on first event. I need value once I select value from dropdown. I might be doing something wrong not exactly sure.. new to VueJs.
Please let me know how do I pass value at 1st instance to Component B.
Although I am getting the value in Component A on first attempt just not getting at Component B
I am able to fetch dropdown value in parent component but unable to fetch the same in child component when I initially select the value for 1st time. When I change the value of dropdown 2nd time then I get the value in child component.
Thanks!
In your question title you said that El-Select doesn't work as expected. Actually it works as expected. When you reload the page, all Vue data come back to their initial values. So when you set value: '' in component A (that I called it parentTable in my following codes), then after reloading the page the value of '' comes back to that value data. If you want to store the value of selected item before reloading page, there are some solutions to that. One of them is using Window localStorage. Here is the codes that works for me:
parentTable.vue component:
<template>
<div>
<el-select v-model="value" placeholder="Select Action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
</div>
</template>
<script>
import tableview from "./tableview";
export default {
name: "parentTable",
components: {
tableview
},
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: null,
}
},
watch: {
value: function (newVal) {
this.getValueOf(newVal);
}
},
methods: {
getValueOf: function (storeValue) {
localStorage.setItem("option", storeValue);
}
},
mounted() {
/* Here we get the previous selected item from localStorage */
this.value = localStorage.getItem("option");
}
}
</script>
<style scoped>
</style>
tableview.vue component:
<template>
</template>
<script>
export default {
name: "tableview",
props: [
'action'
],
watch: {
action: function (value) {
console.log(value);
}
}
}
</script>
<style scoped>
</style>

How to remove preselected tag in vue-multiselect

I need a dropdown that supports tagging and can be styled easily, so I decided to implement vue-multiselect. It works but the problem is that I have a predefined tag in my dropdown when the page loads and I don't what that, how can I remove it? Here is how it looks now:
and here is how I want it to look:
Here is my html code:
<div>
<multiselect v-model="value" tag-placeholder="Add this as new tag" placeholder="Assesors" label="name" track-by="code" :options="options" :multiple="true" :taggable="true" #tag="addTag"></multiselect>
</div>
and here is my js:
data () {
return {
showAddUserDialog: false,
value: [
{ name: 'Assesors', code: 'as' }
],
options: [
{ name: 'Assesors', code: 'as' },
{ name: 'Finance', code: 'fi' },
{ name: 'Sales', code: 'sa' }
]
}
},
methods: {
addTag (newTag) {
const tag = {
name: newTag,
code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
}
this.options.push(tag)
this.value.push(tag)
}
}
Well, by the <multiselect> configuration you used and the expected behavior your showed...
You have this https://imgur.com/a/D9nEKfD to become this https://imgur.com/a/baTYXht
I looks like you want to load your page only showing the placeholder, but if you'd like to only show your placeholder, you shouldn't have a value in the value variable, as you have:
data () {
return {
showAddUserDialog: false,
value: [
{ name: 'Assesors', code: 'as' } // <- remove this
],
options: [
{ name: 'Assesors', code: 'as' },
{ name: 'Finance', code: 'fi' },
{ name: 'Sales', code: 'sa' }
]
}
}
Because the behavior of the component is show your current tags, right?
So if this tag is the placeholder, you can add it to the value when the user submits the form without choosing any other tag.
But if you want to have it there as the value and trickery the component to only show it as a placeholder, I suggest you to deep dive in the docs about custom templating...
Here talks about it https://vue-multiselect.js.org/#sub-custom-option-template
And here talks about the tags slots
https://vue-multiselect.js.org/#sub-slots
Here is an example:

Kendo-dropdownlist for VUE from array of objects shows "NO DATA FOUND" message

I'm having trouble getting the kendo-dropdownlist for VUE working inside a custom component. The component renders, there's no errors in the console, but no options are shown in the list.
I've broken the code down into this bit:
<template>
<div>
<kendo-dropdownlist
:data-items="months"
:text-field="'text'"
:data-item-key="'value'"
></kendo-dropdownlist>
</div>
</template>
<script>
export default {
name: "demo",
data() {
return {
months: [
{
text: "January",
value: 1,
numDays: 31
},
{
text: "February",
value: 2,
numDays: 28
},
{
text: "March",
value: 3,
numDays: 31
}
]
};
}
};
</script>
Does anyone see what I'm doing wrong?
You are writting wrong props, see docs:
<kendo-dropdownlist
:data-source="months"
:data-text-field="'text'"
:data-value-field="'value'">
</kendo-dropdownlist>

Dynamic form problem in vue2: [TypeError: Cannot read property '_withTask' of undefined]

I have to create a dynamic form in vue2. I want to save the values of the dynamic fields in an named object so that I can pass them along on submit.
The following code is working fine except I get an error in the console when I change the input value the first time (value will be propagated correctly though):
[TypeError: Cannot read property '_withTask' of undefined]
Here is how I define the props:
props: {
fields: {
type: Object,
default: {startWord: 'abc'}
},
},
And this is how I populate the model from the input field:
v-model="fields[field.id]"
Here is the entire code:
<template>
<div>
<!-- Render dynamic form -->
<div v-for="(field, key) in actionStore.currentAction.manifest.input.fields">
<!-- Text -->
<template v-if="field.type == 'string'">
<label>
<span>{{key}} {{field.label}}</span>
<input type="text" v-bind:placeholder="field.placeholder"
v-model="fields[field.id]"/>
</label>
</template>
<!-- Footer -->
<footer class="buttons">
<button uxp-variant="cta" v-on:click="done">Done</button>
</footer>
</div>
</template>
<script>
const Vue = require("vue").default;
const {Bus, Notifications} = require('../../Bus.js');
module.exports = {
props: {
fields: {
type: Object,
default: {startWord: 'abc'}
},
},
computed: {
actionStore() {
return this.$store.state.action;
},
},
methods: {
done() {
console.log('fields', this.fields);
Bus.$emit(Notifications.ACTION_INPUT_DONE, {input: this.fields});
}
},
}
</script>
So again, everything is working just fine (showing initial value in input, propagating the new values to the model etc.). But I get this '_withTask' error when I first enter a new character (literally only on the first keystroke). After that initial error it doesn't pop up again.
-- Appendix --
This is what the manifest/fields look like:
manifest.input = {
fields: [
{ id: 'startWord', type: 'string', label: 'Start word', placeholder: 'Enter start word here...' },
{ id: 'startWordDummy', type: 'string', label: 'Start word dummy', placeholder: 'Enter start word here...' },
{ id: 'wordCount', type: 'integer', label: 'Word count' },
{ id: 'clean', type: 'checkbox', label: 'Clean up before' },
]
}
-- Update --
I just discovered that if I set the dynamic field values initially with static values I don't get the error for those fields set this way:
created() {
this.fields.startWord = 'abc1';
},
But this is not an option since it will be a dynamic list of fields. So what is the best way to handle scenarios like this?
From documentation: Due to the limitations of modern JavaScript (and the abandonment of Object.observe), Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.
As I understand it's bad idea create keys of your object by v-model.
What would I do in HTML:
<input type="text"
:placeholder="field.placeholder"
#input="inputHandler(event, field.id)" />
Then in JS:
methods: {
// ...
inputHandler({ target }, field) {
this.fields[field] = target.value;
}
},

Vue JS date of birth picker

I'm setting up a date of birth field.
How can I set the "Year" as my first popup window? instead of calendar view popup.
The view package I'm using is "vue2-datepicker"
I would like to choose the "YEAR" first and then "Month" and then "Date"
This is what I want to show up first when I click the calendar icon.
At the moment, when I click the calendar icon it show the default calendar.
Here's the code I have at the moment. It's working fine with the default calendar but I just want to default to the year selection first and then Month and then date.
<template>
<div class="styled-form__field">
<label class="styled-form__label">{{ label }}</label>
<span
:class="['styled-form__error', {'is-visible': error}]"
>{{ error }}</span>
<date-picker
:value="value"
lang="en"
:format="'DD MMMM YYYY'"
:placeholder="' '"
:width="'auto'"
:input-class="datePickerClass"
:not-before="datePicker.start"
:not-after="datePicker.finish"
#input="changeHandler"
></date-picker>
</div>
</template>
<script>
import moment from 'moment';
import DatePicker from '../common/DatePicker.vue';
export default {
components: {
DatePicker
},
props: {
value: {
required: true
},
label: String,
error: String
},
data() {
return {
datePicker: {
start: moment().subtract(115, 'years').toDate(),
finish: moment().subtract(1, 'days').toDate()
}
};
},
computed: {
datePickerClass() {
return this.error ? 'styled-form__date-picker is-invalid' : 'styled-form__date-picker';
}
},
methods: {
changeHandler(newValue) {
let parsedValue = '';
if (newValue !== '') {
parsedValue = moment(newValue).format('YYYY-MM-DD');
}
this.$emit('input', parsedValue);
}
}
};
</script>
The standard browser datepicker doesn't let you alter its behaviour like that. You might find another datepicker component that suits you better, but I suspect you will have to write your own, combining separate inputs for year, month and date. The effort will only be worth it if you're super-picky about the result. For most situations, you will be better off with a ready-made component.