[Vue] Props: Custom Validation

Zhentiw發表於2024-12-02

The Shortcomings of Most Prop Definitions


In the last lesson, we learned how to create props that were well documented and helped to prevent common bugs. However, after cleaning up our props in the last lesson, you might have noticed that our image prop is a little bit lacking.

📄 BaseBanner.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
    }
  }
}

While we have a default placeholder image that will help us when movie poster images are missing, the simple data-type-checking of String doesn’t quite cover it when it comes to validation. Simply passing any string won’t suffice; a simple error would result in a broken image.

  • /images/movie-poster.pn
  • /imagesmovie-poster.png
  • images/movie-poster.png

For our MoviePoster component, beyond simply enforcing that the image prop is a String, let’s assume that we want to make sure that:

  1. Images live in the /images directory
  2. Images can only be PNG or JPEG format

When given these requirements, the first instinct might be to create a computed property that checks for these things and generates an error message if it fails. However, what if we could validate our props earlier than that? Let’s explore how we can do this with custom validations!

Custom Validation for Props

While creating custom validations for props sounds complicated initially, Vue makes it quite easy for us to do so by providing the validator property. Here are the basics behind how it works:

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type: String,
      default: '/images/placeholder.png',
      // Validator takes an anonymous function 
      // that receives the passed-down value
      // as its first argument
      validator: propValue => {
        // Return a Boolean that will serve as your validation
        const propExists = propValue.length > 0

	return propExists
      }  
    }
  }
}

Equipped with this knowledge, let’s apply this to our images prop from our MoviePoster scenario!

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type: String,
      default: '/images/placeholder.png'	
    }
  }
}

Requirement 1: Verify that all images come from the /images directory

Our first step is to setup a validator property that takes an anonymous function that receives the prop value as its sole argument.

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
      validator: propValue => {}
    }
  }
}

Next, we want to create a validation rule to verify that the value being passed down contains the images directory. We can do this using the standard JavaScript String method indexOf, which allows us to check whether or not a string of characters exists on a given string by returning the index where it exists. If it doesn’t exist, it will return -1.

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
      validator: propValue => {
        const hasImagesDirectory = propValue.indexOf('/images/') > -1
      }
    }
  }
}

Now that we have our validation rule, all we need to do is return it to validate our prop.

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
      validator: propValue => {
         const hasImagesDirectory = propValue.indexOf('/images/') > -1

	 return hasImagesDirectory
      }
    }
  }
}

And with that, our prop will now throw an error if it doesn’t contain the image directory!


Requirement 2: Image must either be PNG or JPEG format

Now that we have our validator set up, all we need to do for this requirement is setup another validation rule in our validator property. And to do this, we will utilize a helpful String method endsWith to check whether our URL path contains the correct extension.

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
      validator: propValue => {
         const hasImagesDirectory = propValue.indexOf('/images/') > -1
	 const isPNG = propValue.endsWith('.png')
	 const isJPEG = propValue.endsWith('.jpeg') || propValue.endsWith('.jpg')
	 const hasValidExtension = isPNG || isJPEG

	 return hasImagesDirectory
       }
     }
  }
}

Finally, we need to add these new validation rules to our return value.

📄 MoviePoster.vue

export default {
  props: {
    image: {
      type; String,
      default: '/images/placeholder.png'	
      validator: propValue => {
         const hasImagesDirectory = propValue.indexOf('/images/') > -1
	 const isPNG = propValue.endsWith('.png')
	 const isJPEG = propValue.endsWith('.jpeg') || propValue.endsWith('.jpg')
	 const hasValidExtension = isPNG || isJPEG

	 return hasImagesDirectory && hasValidExtension
       }
     }
  }
}

相關文章