I have been in the process of teaching myself Vue.js and really like it so far. I have a project that I finally get the chance to use it on. I am creating a form and wanting to do some validations. I am used to the C# way of doing things, such as String.IsNullOrWhiteSpace() that just hits everything in one swoop. I haven't found a way to do that in Vue yet, if even possible. I do know of simpler ways to do it in regular javascript
This is my app and data
const app = new Vue({
el: '#app',
data() {
return {
errors: [],
parentInfo: {
name: null,
address: null,
city: null,
state: null,
zip: null,
primaryPhone: null,
secondaryPhone: null
}
}
}
...
Here are my validations for the form. This still does not catch if they add a whitespace to every field.
checkParentInfo: function () {
this.errors = [];
for (var i in this.parentInfo) {
if (this.parentInfo[i] === null && i !== 'secondaryPhone' || !this.parentInfo[i] && i !== 'secondaryPhone') {
this.errors.push('All parent info must be filled out, with the exception of a Secondary Phone Number');
return;
}
}
}
Is there a built in way to do my if statement? In one swoop like I can in C#?
Instead of if (this.parentInfo[i] === null) you can easily write if (!this.parentInfo[i]) which will be true when this.parentInfo[i] is anything but undefined, null, NaN, 0, "" (empty string) or false.
A string containing only a whitespace will return true, so you'll have to run if (this.parentInfo[i]===" ") for that.
You can of course create your own method IsNullOrWhiteSpace and use that instead.
Please also note that this is rather a Javascript question than a Vue.js question.
Related
I would like to take the output of one query (a TRPC query on Prisma) and use this as the dependent input in a future query.
I followed the dependent documentation for React Query but running into type errors that the return of the first may possibly be undefined (e.g. product is possibly 'undefined'):
const { data: product } = api.product.getUnique.useQuery({ id: pid });
const options = api.option.getAll.useQuery(
{
product: product.productSize,
region: product.productRegion,
},
{ enabled: !!product }
);
Does the inclusion of enabled not already handle this? If not, what is the correct way to adapt for Typescript.
Just casting the product value as a boolean return any truthy value (f.e if product will be equal to {} it will still result in true, that means that product won't necessarily have the productSize or productRegion properties, I would change it first to:
{ enabled: !!product && product.productSize && product.productRegion }
If that doesn't fix the typescript error, you as a developer can know for sure that the values are actually there so what you can use the as keyword in typescript to tell it that you know for sure that the type is what you want it to be:
(In this example I assumed that the values are string but you can change it to number or whatever the true value of them are)
const options = api.option.getAll.useQuery(
{
product: product.productSize as string,
region: product.productRegion as string,
},
{ enabled: !!product && product.productSize && product.productRegion }
);
This question already has answers here:
Access vue instance/data inside filter method
(3 answers)
Closed 2 years ago.
I'm creating a simple Vuejs div component (to show a specific value) which needs to receive: a lists, a placeholder and a value as props. What I'm trying to do is displaying the value with the data from my database, if the user picks a new value from the lists, it should take that new value and display it. However, if the user never picks a new value and the data from the database is empty, it should display the placeholder.
So I have used filters to achieve this. However, it outputs an error: "Cannot read property 'lists' of undefined", which comes from the filters (I know because it outputs no error if I comment out the filters). When I changed the filter to this:
filters: {
placeholderFilter () {
return this.placeholderText || this.placeholder
}
}
It says:""Cannot read property 'placeholderText' of undefined"". So I was wondering if the filters properties executed before the data and props properties. What is the execution order of them? I have attached some of the relevant code down below. Anyway, If you could come up with a better way to achieve this. I would appreciate it!
Here is my component:
<template>
<div>{{ placeholderText | placeholderFilter }}</div>
<li #click="pickItem(index)" v-for="(list,index) in lists" :key="index">{{ list }}</li>
</template>
<script>
export default {
props: {
lists: {
type: Array,
required: true
},
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: String,
default: ''
}
},
data () {
return {
selected: -1,
placeholderText: this.value || this.placeholder
}
},
methods: {
pickItem (index) {
this.selected = index
}
},
filters: {
placeholderFilter () {
return this.lists[this.selected] || this.placeholderText || this.placeholder
}
}
}
</script>
And this is where I use it:
<my-component
placeholder="Please type something"
value="Data from database"
lists="['option1','option2','option3']"
>
</my-component>
Filters aren't bound to the component instance, so they simply don't have access to it through the this keyword. They are meant to always be passed a parameter and to return a transformed version of that parameter. So in other words, they're just methods. They were removed in Vue 3 entirely probably for that reason.
And yeah, what you're looking for here is a computed!
In a Vue component I have a data() function that returns an object of data – standard stuff really:
data() {
return {
PlaceholderHTML: "",
ProductID: "",
CustomInvalidMessage: "",
Form: {
Price: "",
Currency: ""
},
}
},
When some data (usually a File) is posted to the server using axios, a ProductID is generated on the server and sent back to Vue. I then set the ProductID like
this.ProductID = response.data.ProductID;
All that works fine. In Vue Developer Tools the ProductID value is indeed set to 15005. If I do a console.log(ProductID) then I get back empty string on initial state and when ProductID is set after the axios.post() the console shows 15005.
So why does the following test never succeed?
const formData = new FormData();
if (this.ProductID != null && this.ProductID.length) {
formData.append("ProductID", this.ProductID); // This never happens
console.log(`Appended ${this.ProductID}`) // This too never prints anything
}
So if I remove the if(... && this.ProductID.length) part above, then there is no problem:
if (this.ProductID != null) {
formData.append("ProductID", this.ProductID); // Appended as empty string on initial state and then 15005 after this.ProductID is set
}
What is wrong with the && this.ProductID.length part?
this.ProductID is a number and in js the Number constructor does not have length method only String does so, to fix your problem check it like this:
this.ProductID.toString().length
I have three inputs as externalIP as External Host, externalHttpPort as Port and vendor as Vendor, I want to show error message if any of them is missing. but being specific about the name,
if (!this.externalIP || !this.externalHttpPort || !this.vendor) {
when I do if condition, this works but I am not sure how I can tell if which input is empty. only one way which left is to add 3 multiple if
something like this
let error;
error = !this.externalIP
? "External IP Address (or URL) is incorrect"
: "" || !this.externalHttpPort
? "Port is missing" : "" || !this.vendor
? "Please choose camera vendor or add your camera snapshot URL." : ""
if (!error == "") {
this.setNotification({
text: error,
color: "warning",
snackbar: true
})
return
}
is there any other way of doing it? Also, Eslint show warning on indentations as well
In this way, you can achieve the same result as by your logic without using multiple if. Also, this way will keep your template & logic clean/easily scalable.
new Vue({
el: '#app',
data: {
fields: [
{
key: 'externalIP',
value: '',
validationMessage: 'External IP Address (or URL) is incorrect'
},
{
key: 'externalHttpPort',
value: '',
validationMessage: 'Port is missing'
},
{
key: 'vendor',
value: '',
validationMessage: 'Please choose camera vendor or add your camera snapshot URL.'
}
]
},
computed: {
getError () {
let e = ''
for (let i in this.fields) {
if (!this.fields[i].value) {
e = this.fields[i].validationMessage
break
}
}
return e
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
v-for="(field, i) in fields"
:key="i"
v-model="fields[i].value"
/>
<br>{{ getError }}
</div>
Well, you may assign an error field variable within your error-checking condition.
Example for three variables and an emptyField variable denoting the empty variable name:
if ((!a && (emptyField = "a")) ||
(!b && (emptyField = "b")) ||
(!c && (emptyField = "c"))) {
alert("Field " + emptyField + " is empty...");
}
Since JS lazily evaluates its arguments, emptyField = "a" will get executed only if !a is true.
Just note that lazy evaluation also causes the evaluation of conditions stop once a condition was hit, thus if a is null and also b is null, the alert would announce that "Field a is empty..."
if vuetify you can use rules to check inputs
for example:
in your template:
<v-text-field
rules="[rules.required]"
/>
and in your data:
data() {
return {
rules: {
required: (value) => !!value || 'This field is required.'
}
}
},
you can add any other checking to rules array and just add it to your input by passing it to rules prop
hope it helps you!!!
I'm using VeeValidate to handle all of Validation job, maybe you will be interested in it:
https://logaretm.github.io/vee-validate/
I've got a simple state setup for a component that still throws the error: TypeError: Cannot read property 'year' of undefined with this code:
export default class Login extends Component {
state = {
isLoading: false,
events: this.props.events,
activeDate: {
year: this.props.events[0].year || "",
month: this.props.events[0].months[0].month || "",
}
};
//...
}
I'm having trouble understanding why this errors out instead of just setting the value to null. undefined should render the binary operation as false and default to "". Can anyone explain?
Instead of using year: this.props.events[0].year || "", I found that that this worked just as well, year: "" && this.props.events[0].year. The AND operator will equate to the last true value.
But, as #AlexanderStaroselsky pointed out, this isn't best practice. See this article for more details.
You can validate that the object in the array at position 0 is not null then use && before to access the property of the array object. Finally, add || to specify a default value when both conditions give null or undefined.
this.props.events[0] && this.props.events[0].year || ""