Validations and open-all for Vuetify V-treeview control - vue.js

I am trying to achieve couple of things with Vuetify V-treeview control but no luck.
I am trying to apply mandatory field validation (using veeValidate.js)
I am trying to open all nodes of v-treeview by setting up open-all prop to true but no luck.
The code snippet is like this -
<ValidationProvider name="vp1" :rules="rules.products" slim>
<v-treeview
v-model="selectedProducts"
slot-scope="{ errors }"
:error-messages="errors"
selectable
:items="allProducts"
:open-all="isOpenAll"
></v-treeview>
</ValidationProvider>
<script>
export default {
name: 'Access',
data: () => ({
isOpenAll: false,
allProducts: [],
selectedProducts: [],
rules: {
products: {
required: true,
},
})
}
</script>
I am setting up isOpenAll to true/false depending on certain conditions but "open-all" prop doesnt seem to update and behave as it should.
Please advise.
thank you

Related

Assigning data to fields on opening dialog in vuetify

I've created a dialog box using vuetify and I want it to be prepopulated with data in the v-select but it's blank when I open the dialog modal. I've assigned the propPackage to the selectPackage which is used in v-model in the v-select. How should I prepopulate it when I open the dialog?
Dialog
<template>
<v-row justify="center">
<v-dialog v-model="dialog" max-width="600px" #click:outside="close">
<v-select
:items="['Basic', 'Standard', 'Premium']"
label="Package*"
required
v-model="selectPackage"
></v-select>
<v-btn #click="close"> Close </v-btn>
</v-dialog>
</v-row>
</template>
<script>
export default {
props: {
dialog: {
type: Boolean,
required: false,
default: false,
},
propPackage: {
type: String,
required: true,
},
},
data: () => ({
selectPackage: this.propPackage,
}),
methods: {
close() {
this.$emit("close");
},
},
};
</script>
Parent component
<template>
<v-btn #click="bookDialog('Basic')"></v-btn>
<form-modal :dialog="openDialog" #close="close" :propPackage="propPackage" />
</template>
<script>
import FormModal from "#/components/FormModal.vue";
export default {
components: {
FormModal,
},
data: () => ({
openDialog: false,
propPackage: null,
}),
methods: {
bookDialog(val) {
this.propPackage = val;
this.openDialog = true;
},
close() {
this.openDialog = false;
},
},
};
</script>
Check this codesandbox I made: https://codesandbox.io/s/stack-70077413-943o6?file=/src/components/FormModal.vue
The main issue is that you're trying to access the prop value directly on your data block:
data: () => ({
selectPackage: this.propPackage,
}),
In this case, it would be better to get the prop value by setting up a watcher instead, just like this:
data: () => ({
selectPackage: ''
}),
watch: {
propPackage(val) {
// Be sure to validate default values
if(val !== '') {
this.selectPackage = val
}
}
},
This way, you can also validate the prop value if you need to.
I added a few more comments in the codesanbox on things you could improve. Since the FormModal component works mainly as a dialog, you can use the 'value' prop and set up a computed property to be able to close the dialog directly from the child component, this way you avoid emitting a #close event to the parent component and the prop mutation warning.
Since you are using arrow functions for data section, this.propPackage will be undefined since this won't refer to vue instance. You can fix that in 2 ways:
Change the arrow function to ES6 notation in your dialog component:
data() {
selectPackage: this.propPackage,
},
Pass the vue instance as a parameter to arrow function and access your prop using that:
data: (instance) => ({
selectPackage: instance.propPackage,
}),
Once you populate your selectPackage data property the right way, your v-select will be populated with the value once you open your dialog.

How to make a checkbox selected by default in VueJs?

EDIT: My problem has shifted somewhat, with a different code focus, so I created a new question.
I have a Beufy Form Field Component, with a Boolean Input Checkbox inside, this Form Field Component allows you to select the option "Later" and this disables the Form Field and Checkbox. I would like to have it so that when "Later" is selected, the Boolean Input Checkbox is ticked/enabled by default.
I've read the Buefy checkbox documentation and I can see that I should use
<b-checkbox :value="true"
but when I attempt add it to my FormField template (the checkbox is a child component of the Form Field component) call it throws errors, this is how the template is rendered:
<FormField
:for="param.editableByOperator"
:label="null"
:disabled="param.populationStrategy.value === 'later'"
:checked="checked"
as="Boolean">
</FormField>
How do I best implement this fix? I'll attach the Checkbox Component
Below:
<template>
<b-checkbox
v-model="localValue"
:name="$props.name"
:checked="checked">
{{label}}
</b-checkbox>
</template>
<script>
import BaseInput from './BaseInput';
export default {
name: 'BooleanInput',
mixins: [BaseInput],
props: {
checked: {
type: Boolean,
default: true,
},
}
};
</script>
edit:
In my component I have found these methods, which set the checkbox as unticked by default. Is there something I can do here which would set the checkbox(editableByOperator) to True when 'Later'(populationStrategy) is set to 'Later.
Methods:
drawMonadParams(monadSlug) {
const monad = this.ccMonad(monadSlug);
monad.params.forEach((x, idx) => {
this.addFormFields(['params', idx], {
value: this.defaultMonadParamValue(x.typeSlug),
populationStrategy: 'now',
editableByOperator: false,
ccRequestParamId: null,
name: x.name,
typeSlug: x.typeSlug,
});
});
},
defaultMonadParamValue(typeSlug) {
return typeSlug === 'boolean' ? false : '';
},
May be try not using the checked prop inside the template . Try a data variable and use that instead.
like this
<b-checkbox :checked="checkValue"></b-checkbox>
props(){
checked:{
type:Boolean,
default:true
}
data(){
return{
checkValue : this.checked
}
}

Vue v-model does not select value on checkbox

I'm fairly new to Vue and I've researched as much as I could, but cannot find a solution to this strange issue. I'm building a filter function for an online shop, and one section allows filtering based on values with a checkbox.
My vue template is as following:
<template>
<div>
<h3>{{data.filterLabel}}</h3>
<ul>
<li v-for="(item, index) in data.options" :key="index">
<input v-model="values" type="checkbox" :id="item" :value="item" :index="index" />
<label class="products__label products__capitalize" :for="item">{{ item }}</label>
</li>
</ul>
</div>
</template>
I am getting the options from a database, and loop through the data.options array with v-for. I have created a new empty array in
data() {
return {
values: []
};
},
as in the form-bindings example on the vue.js website here: https://v2.vuejs.org/v2/guide/forms.html#Checkbox
My script is as following:
<script>
export default {
name: "CheckBoxFilter",
data() {
return {
values: []
};
},
props: {
data: Object,
filterCheckBox: Function
},
watch: {
values: function(value) {
const optionRange = JSON.parse(JSON.stringify(this.values));
this.$emit("filterCheckBox", this.data.filterValue, optionRange);
}
}
};
</script>
For some strange reason, the $emit function works perfectly fine, and the array of products is filtered correctly in the UI. But when I check a value in the checkbox, the checkbox is not ticked. How is it possible that the checkbox is not ticked, while at the same time it is clearly correctly filtering the values?
I even looked at the :checked value with $event.target.checked which also correctly returns true or false, but the checkbox is still not ticked in the UI.
I have the same issue with radio buttons.
There are no issues with the <input type="text"> and also no issues with a <select>.
Has anyone experienced this before and if so what is the solution?
Thanks!
I tested and the UI displays the checked/unchecked checkboxes properly. Which version of Vue do you use? I'm not sure of what you want to do, but I think it would be cleaner to expose your values through a computed property:
export default {
name: "CheckBoxFilter",
props: {
data: Object,
},
data() {
return {
internalValues: [],
};
},
computed: {
values: {
get() {
return this.internalValues;
},
set(newVal) {
this.internalValues = newVal;
this.$emit("filterCheckBox", this.data.filterValue, [...newVal]);
},
},
},
};
</script>
With your current implementation, the values change are not observable and the filterCheckBox event is never emitted.
EDIT: I also don't understand why you set a filterCheckBox prop, it is not React ;)

Make Vuetify v-text-field component required by default

Currently, you can set rules that will work once the user changes the value of the input. For example:
Template part
<v-text-field
v-model="title"
label="Title"
></v-text-field>
Logic
export default {
data () {
return {
title: '',
email: '',
rules: {
required: value => !!value || 'Required.'
},
}
}
}
When the user focuses and removes focus from that element, or when the user deletes all its content, the required rule is triggered.
But what happens if we want to start with the rule enabled as soon as the component is mounted or created? Is there a way to achieve this?
I searched around vuetify but I could not find info about this nor examples in my humble google searches. I will appreciate help. I'm new in vue world. Thanks.
You could do the following:
Create a v-form and place your textfields inside the form. Don't forget to give your v-form a v-model and a ref too.
On mounted you can access the v-form via this.$refs and call .validate() just as Jesper described in his answer. In the codesandbox below you can see that the textfields immediately go red and display the "Required." text.
<v-form v-model="formValid" ref="myForm">
<v-text-field label="Field 1" :rules="rules.required"></v-text-field>
<v-text-field label="Field 2" :rules="rules.required"></v-text-field>
</v-form>
<script>
export default {
data() {
return {
formValid: false,
rules: {
required: [value => !!value || "Required."]
}
};
},
mounted() {
this.$refs.myForm.validate();
}
};
</script>
Example:
You should change your validation a little bit to achieve this.
<ValidationProvider rules="required" v-slot="{ errors }" ref="title">
<v-text-field
v-model="title"
label="Title"
></v-text-field>
</ValidationProvider>
And then you should call this.$refs.title.validate()
If you trigger this when mounted() is called, it should validate all the fields right away, as you're requesting.

Why do some of my images placed in a Vue template disappear when content in filtered?

I've been put in charge of a Drupal website that has some content that is placed through a complex set of Vue files. I've never used Vue so I need some help with a critical problem we're facing.
I have a news section on the site that users can filter from a dropdown (by choosing a topic from the menu). This works fine. However, whenever you bring back a previously filtered news story, the featured image fails to load. The Vue template brings back the default image. But this only happens for SOME of the images.
As I mentioned, the Vue.js file is complex - it imports nearly a dozen other files that control other features of the site. This is the code from the the most applicable file:
export default {
props: {
url: {
type: String,
required: true,
},
tag: {
type: String,
required: false,
},
eyebrow: {
type: String,
required: false,
},
title: {
type: String,
required: true,
},
image: {
type: Object,
required: false,
},
},
computed: {
imageUrl() {
return this.image && this.image.url ? this.image.url : '/themes/my-theme/images/no-image.jpg';
}
},
template: `
<a :href="url" class="news-card">
<span class="news-card__image">
<img :src="imageUrl" :alt="image.alt">
</span>
<span class="news-card__text">
<span class="news-card__tag" v-if="tag" v-html="tag">
</span>
<p class="news-card__eyebrow" v-if="eyebrow">
{{ eyebrow }}
</p>
<h2 class="news-card__title">
{{ title }}
</h2>
</span>
</a>
`
};
I would post more, but I don't know what else is needed to diagnose a Vue issue. Sorry, I'm brand new to Vue and it's very confusing!
UPDATE
I've added the view.js code below:
import Vue from '#vue';
import { mapState } from 'vuex';
import ListingGrid from '/components/listing-grid';
import ListingNav from '/components/listing-nav';
import ProgramCard from '/components/program-card';
import ListingCard from '/components/listing-card';
import NewsCard from '/components/news-card';
import ListingFilters from '/components/listing-filters';
import ListingLoader from '/components/listing-loader';
import ListingStickyNav from '/components/listing-sticky-nav';
import TabSelect from '/components/tab-select';
import ajaxStore from './store/ajax';
import staticStore from './store/static';
export default (id) => {
new Vue({
el: `#${id}`,
components: {
ListingFilters,
ListingGrid,
ListingNav,
ProgramCard,
ListingCard,
NewsCard,
ListingLoader,
ListingStickyNav,
TabSelect,
},
data: {
lazy: true
},
store: id === 'listing-static' ? staticStore : ajaxStore,
computed: mapState({
grid() {
return this.$store.getters.filteredGrid;
},
filters: state => state.filters,
tabs: state => state.tabs,
loading: state => state.loading,
showLoader: state => state.infiniteLoading,
cardType: state => state.cardType
}),
image: {
type: Object,
default: function () {
return {
url: '/themes/my-theme/images/no-image.jpg',
alt: 'Default No Image Alt Text'
}
},
},
template: `
<main class="view__content v-listing vue-loaded" id="${id}">
<listing-sticky-nav>
<template slot="tab-content">
<tab-select
:tabs="tabs"
v-if="tabs.items"
>
</tab-select>
</template>
<template slot="panel">
<listing-filters
:filters="filters"
additional-classes="mobile"
>
</listing-filters>
</template>
</listing-sticky-nav>
<listing-filters
:filters="filters"
>
</listing-filters>
<listing-grid
:has-results="grid.length > 0"
:loading="loading"
:lazy="lazy">
<listing-nav
v-if="tabs"
:tabs="tabs"
slot="nav"
>
</listing-nav>
<template slot="grid">
<component
:is="cardType"
v-bind="item"
v-for="item, index in grid"
:key="index">
</component>
</template>
<template slot="empty">
No results found.
</template>
</listing-grid>
<span class="v-listing-footer" v-if="showLoader">
<listing-loader></listing-loader>
<span class="visually-hidden">loading</span>
</span>
</main>
`
});
}
Although I agree with the comments above that there are many lacking elements, I am a huge proponent of VueJS and I would like to help if possible.
First glaring issue I see is that the property image is not required. The computed property imageUrl() is defensive in that it will return a default value of '/themes/my-theme/images/no-image.jpg' if the property image is omitted.
However in your template code in the <img /> you are referencing the object key of 'alt' from the image object which may or may not be present.
I would highly recommend adding a computed property of:
imageAlt() {
return this.image && this.image.alt ? this.image.alt : 'Default No Image Alt Text';
}
Then in your template update the image tag as follows:
<img :src="imageUrl" :alt="imageAlt">
This will harden your code ensuring that error cannot happen. You may want to update the default Alt Text as it was provided for example purposes only.
If this does not work in resolving the issue please comment with the following information for additional assistance.
Are there any JS errors in the console?
Did you download the Vue Devtools extension?
If so what is the computed properties value for imageUrl when working and after you experience this issue?
Update. As an alternative approach (and I prefer this) you could also remove all computed properties and provided a default image object. This would require no observers and looks like this:
image: {
type: Object,
default: function () {
return {
url: '/themes/my-theme/images/no-image.jpg',
alt: 'Default No Image Alt Text'
}
},
}
Your image tag would then look like this:
<img :src="image.url" :alt="image.alt">
For more info visit: https://v2.vuejs.org/v2/guide/components-props.html