Can Vue.js set required props by another props variable.
Ex.
props: {
data: {
required: this.writeable,
type: Array
},
writeable: {
type: Boolean,
default: true
},
},
In this case. I want to set data required ot not by writeable value.
If writeable was not set or set as true, You must to pass data to this component. And If writeable set at false the component will not require data.
It can't be done.
As a workaround, you can validate manually using watcher
watch: {
writeable: {
handler(value) {
if(value && typeof this.data === 'undefined') {
console.error("property 'data' is required. ")
}
},
immediate: true
}
}
Related
I followed the Vue documentation on filtering arrays, but it seems like I must have missed something.
I am testing an array which has three items with two conditions: a name and a boolean. I wanted to test filtering by making a computed property that only returns the name of an item if the boolean value of that item is true.
I am not getting any output, but I am not getting any errors in the console either, so I am unsure of what the issue is.
<div v-for="array in filteredDataTest">
{{ array.name }}
</div>
data() {
return {
testArray: [
{
name: 'Bob',
isTrue: false
},
{
name: 'Mary',
isTrue: true
},
{
name: 'Paul',
isTrue: false
}
]
};
},
computed: {
filteredDataTest() {
this.testArray.filter(user => {
if(user.isTrue) {
return user
}
})
},
},
You should return within the computed getter method. Otherwise you can't see any result from method.
computed: {
filteredDataTest() {
return this.testArray.filter(user => user.isTrue);
},
}
I have a Request Form Component, and within this request form Component I have a Dropdown Menu Component, which I will link both below. All values in my table are pushed into an object upon hitting the Submit Button. However my dropdown selection is only being picked up by my console.log and not being pushed into the Object.
I'm not so familiar with Vue, so I'm not sure what direction to go in for fixing this. I'll attach the relevant (?) pieces of code below.
Parent Component:
<SelectComponent :selected="this.selected" #change="updateSelectedValue" />
export default {
fullScreen: true,
name: 'CcRequestForm',
mixins: [BaseForm],
name: "App",
components: {
SelectComponent,
},
data() {
return {
selected: "A",
};
},
props: {
modelName: {
default: 'CcRequest',
},
parentId: {
type: Number,
default: null,
},
},
mounted() {
this.formFields.requester.value = this.currentRequesterSlug;
},
destroyed() {
if (!this.modelId) return;
let request = this.currentCcRequest;
request.params = request.params.filter(p => p.id)
},
computed: {
...mapGetters(['ccTypesForRequests', 'currentRequesterSlug', 'currentCcRequest']),
ccTypesCollection() {
return this.ccTypesForRequests.map((x)=>[x.slug, this.t(`cc_types.${x.slug}`)]);
}
},
methods: {
addParam() {
this.addFormFields(['params'], {
slug: '',
name: '',
isRequired: true,
description: '',
typeSlug: '',
selected: ''
});
},
deleteParam(idx){
this.removeFormFields(['params', idx]);
},
restoreParam(idx){
this.restoreFormFields(['params', idx])
},
$newObject() {
return {
slug: '',
name: '',
isAbstract: false,
requester: '',
description: '',
status: 'inactive',
params: [],
selected: ''
};
},
$extraPrams() {
return {
parentId: this.parentId,
};
},
updateSelectedValue: function (newValue) {
this.selected = newValue;
},
},
watch: {
selected: function (val) {
console.log("value changed", val);
},
},
};
Child Component:
<script>
export default {
name: "SelectComponent",
props: {
selected: String,
},
computed: {
mutableItem: {
get: function () {
return this.selected;
},
set: function (newValue) {
this.$emit("change", newValue);
},
},
},
};
You have to define the emit property in the parent component, or else it won't know what to expect. That would look like:
<SelectComponent :selected="this.selected" #update-selected-value="updateSelectedValue" />
Check out this tutorial for more information: https://www.telerik.com/blogs/how-to-emit-data-in-vue-beyond-the-vuejs-documentation
To update selected property inside the object, in this constellation, you need to update object property manually upon receiving an event, inside of updateSelectedValue method. Other way could be creating a computed property, since it's reactive, wrapping "selected" property.
computed: {
selectedValue () {
return this.selected
}
}
And inside of object, use selectedValue instead of selected:
return {
...
selected: selectedValue
}
with a template...
<Dropdown
:options="opts"
optionLabel="name"
optionValue="value"
optionDisabled="disabled"
and data:
disabled: true
opts: [
{ name: "Dog", value: "dog"},
{ name: "Cat", value: "cat"},
{ name: "Monkey", value: "monkey", disabled: this.disabled }]
The disabled state is only set when the dropdown is created and is not reactive to any further changes to the disabled attribute in data. Is this by design or is there a way to make this reactive?
You could use a computed prop that maps the original options to a copy, where each option's disabled flag (if it exists) is equal to the value of this.disabled:
export default {
computed: {
computedOpts() {
return this.opts.map(opt => ({
...opt,
disabled: typeof opt.disabled !== 'undefined' ? this.disabled : undefined
}))
}
},
}
Then in your template, replace opts with computedOpts:
<Dropdown :options="computedOpts">
demo
Im using Vuetify, and have a form where im using VeeValidate for form validation...
When im using this:
this.$validator.validateAll().then((result) => {
console.log("result form", result);
//result ? this.onSubmit() : scrollTo(0, 250);
});
It always returns true, even if the validation on my input field isn't valid...
The input looks like:
<v-textarea
filled
name="string"
:label="placeholderText"
auto-grow
single-line
:placeholder="placeholderText"
v-model="answer"
:required="isRequired"
v-validate:computedProp="checkRequired"
:error-messages="errors.collect('string')"
data-vv-name="string"
:hint="hintText"
#blur="updateAnswer"
></v-textarea>
The code for the input component:
export default {
$_veeValidate: {
validator: 'new'
},
name: 'String',
props: {
placeholderText: {
default: 'Add a value'
},
hintText: {
default: 'Add a value'
},
isRequired: {
default: true
}
},
data: () => ({
answer: ''
}),
computed: {
checkRequired() {
return this.isRequired ? 'required' : ''
}
},
methods: {
updateAnswer() {
this.$validator.validateAll();
this.$emit('updateAnswer', this.answer);
}
}
}
Im calling this.$validator.validateAll() in another component... The input component is a standalone component... I have it all wrappet in a form tag, and running the validate function on a submit
You have two choice:
Pass to the component the v-validate from the $attrs
Inject the $validator to the component
Parent
export default {
name: "App",
components: {
YourComponent
},
provide() {
return {
$validator: this.$validator
};
},
Child
$_veeValidate: {
validator: "new"
},
inject: ["$validator"],
name: "String",
You can also simplify your html code, see the VeeValidate Syntax
Html
v-validate="{ required: this.isRequired }"
And you can safely remove
:required="isRequired"
In My laravel + Spark + Vue js project, I have used https://github.com/Vanthink-UED/vue-core-image-upload, They have code like
export default {
props:{
cropBtn: {
type: Object,
default: function() {
return {
ok: '保存',
cancel: '取消',
}
}
}
}
As per their documentationm, If you want to change button text then do following
cropBtn Object {ok:'Save','cancel':'Give Up'} the text of crop
button
I have used like
<vue-core-image-upload
v-bind:class="['pure-button','pure-button-primary','js-btn-crop']"
v-bind:crop="true" url="/process-image"
extensions="png,gif,jpeg,jpg"
cropBtn="[{ok: 'Save',cancel: 'Cancel'}]"
v-on:imageuploaded="imageuploaded">
</vue-core-image-upload>
and
v-bind:cropBtn="items"
js file
module.exports = {
prop:['cropBtn'],
data() {
return {
items: [{
ok: 'Save',
cancel: 'Cancel',
}],
cropBtn: {
type: Object,
default: function() {
return {
ok: 'Save',
cancel: 'Cancel',
}
}
},
src: 'http://img1.vued.vanthink.cn/vued0a233185b6027244f9d43e653227439a.png'
};
}
};
But it is not working. I am getting same default Chinese value.
Any suggestions what can be the solution?
You need to use kebab-case when passing props that are declared in camel case and you must use v-bind or the shorthand : when passing javascript objects through props:
<vue-core-image-upload :crop-btn="{ok: 'Save',cancel: 'Cancel'}" ></vue-core-image-upload>
see: https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case