Conditional required validation or field mandatory depends on another field MVC 4

I have experienced this situation that when I need to make a field mandatory if the user has entered a value in another field (or a particular value for that field).

Here is my example, I have two radio buttons says “Do you have the purchase receipt?” with options “yes” or “no”. If the user has selected “yes”, I need them to specify the date of the purchase as well.


Now the headache is, I can’t make “Purchase Date” required field. Because if user selects “no”, they don’t need to enter the “Purchase Date”. After I did some research and lookup from the internet. I find this solution on StackOverflow. It has a few bugs and I fixed them and shared over here in my blog.

I created a RequiredIfAttribute,

public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
    protected RequiredAttribute _innerAttribute;

    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }

    public bool AllowEmptyStrings
            return _innerAttribute.AllowEmptyStrings;
            _innerAttribute.AllowEmptyStrings = value;

    public RequiredIfAttribute(string dependentProperty, object targetValue)
        _innerAttribute = new RequiredAttribute();
        DependentProperty = dependentProperty;
        TargetValue = targetValue;

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        // get a reference to the property this validation depends upon
        var containerType = validationContext.ObjectInstance.GetType();
        var field = containerType.GetProperty(DependentProperty);

        if (field != null)
            // get the value of the dependent property
            var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
            // trim spaces of dependent value
            if (dependentValue != null && dependentValue is string)
                dependentValue = (dependentValue as string).Trim();

                if (!AllowEmptyStrings && (dependentValue as string).Length == 0)
                    dependentValue = null;

            // compare the value against the target value
            if ((dependentValue == null && TargetValue == null) ||
                (dependentValue != null && (TargetValue.Equals("*") || dependentValue.Equals(TargetValue))))
                // match => means we should try validating this field
                if (!_innerAttribute.IsValid(value))
                    // validation failed - return an error
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName });

        return ValidationResult.Success;

    public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        var rule = new ModelClientValidationRule
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "requiredif",

        string depProp = BuildDependentPropertyId(metadata, context as ViewContext);

        // find the value on the control we depend on;
        // if it's a bool, format it javascript style 
        // (the default is True or False!)
        string targetValue = (TargetValue ?? "").ToString();
        if (TargetValue is bool)
            targetValue = targetValue.ToLower();

        rule.ValidationParameters.Add("dependentproperty", depProp);
        rule.ValidationParameters.Add("targetvalue", targetValue);

        yield return rule;

    private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
        // build the ID of the property
        string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(DependentProperty);
        // unfortunately this will have the name of the current field appended to the beginning,
        // because the TemplateInfo's context has had this fieldname appended to it. Instead, we
        // want to get the context as though it was one level higher (i.e. outside the current property,
        // which is the containing object, and hence the same level as the dependent property.
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
            // strip it off again
            depProp = depProp.Substring(thisField.Length);
        return depProp;

2. Create js validation and js unobtrusive validation, (I put them in document.ready() callback)

    function (value, element, parameters) {
        var id = '#' + parameters['dependentproperty'];

        // get the target value (as a string, 
        // as that's what actual value will be)
        var targetvalue = parameters['targetvalue'];
        targetvalue = (targetvalue == null ? '' : targetvalue).toString();

        // get the actual value of the target control
        // note - this probably needs to cater for more 
        // control types, e.g. radios
        var control = $(id);
        var controltype = control.attr('type');
        var actualvalue =
            (controltype === 'checkbox' ||  controltype === 'radio')  ?
            control.attr('checked').toString() :

        // if the condition is true, reuse the existing 
        // required field validator functionality
        if ($.trim(targetvalue) === $.trim(actualvalue) || ($.trim(targetvalue) === '*' && $.trim(actualvalue) !== ''))
            return $
              this, value, element, parameters);

        return true;

    ['dependentproperty', 'targetvalue'],
    function (options) {
        options.rules['requiredif'] = {
            dependentproperty: options.params['dependentproperty'],
            targetvalue: options.params['targetvalue']
        options.messages['requiredif'] = options.message;

3. For the Model,

        public bool HasReceipt { get; set; }

         [RequiredIf("HasReceipt", true, ErrorMessage = "You must enter purchase date")]
        [Display(Name="Purchase Date")]
        public DateTime? PurchaseDate { get; set; }

4. When reference this validation js, I notice that it only works before the unobtrusive javascript,

    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.requiredif.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

5. Now you have your conditional required validations.

There are many scenarios like this,


If you have entered an Address field, you must enter Suburb, City.

If you have selected yes for a credit card, you must enter the credit card digits.

If you have subscribed a service, you must enter a valid email.

And many more.

With YouTube new interface, how to copy YouTube playlist from another user?

With the old YouTube interface, when you play a playlist, there is an option at the bottom “Save as a new playlist”. After YouTube has updated to a completely new interface, this feature is gone.

For myself I am feeling frustrated, so here comes a weekend project It provides you several ways of copying playlists with YouTube.


1. You can search a playlist.

Enter a keyword, it returns the same result from search in YouTube. Or if you know your YouTube playlist URL, you can copy to the search box.


2. You can copy a playlists with selected videos.

After you have selected the playlist, you come to this page and see all the videos from this playlist. Now you can select all videos or only the videos you wanted to copy. (You can preview the video by click the magnifier icon on left corner of the video tile.)  When you are ready, click continue to proceed.

e.g. a NBA playlist


3a. Before you get to the “Target Playlist” page, we will ask you for the permission of accessing your YouTube content, please select “Allow” to proceed.


3b. Select a target playlist (where you want to copy the videos), it can be a brand new playlist in your YouTube. Or the videos can be added to your existing playlists. It also works with your “Favourite’s”, “Watch Later”  and “Likes” lists. (The pink tiles are the special lists, and grey tiles are the normal playlists you have in YouTube )


4. Make the selection above, and you are done. Just wait for the service to copy all the videos to the targeted playlist and you can share them or just go to YouTube and enjoy them.


5. You can also manage your playlists with, register and login, on the top right corner, you can see your logged in email and click it to see a list of options. Click “Manage Playlist”.


You can bulk delete your YouTube playlists. (Please be caution, if you delete a playlist, all the videos under that playlist will be deleted.)


So please enjoy, and if you love it please share with your friends and support us. We will do better to make our lives easier.

Find us on Facebook,

Sending email from gmail smtp server

You can do smtp server setting in either web.config or backend code.


            <network host="" userName="" password="yourpassword" port="587" enableSsl="true"/>


           SmtpClient smtp = new SmtpClient();
            var fromAddress = new MailAddress"", "Your Name");
            const string fromPassword = "yourpassword";            
smtp = new SmtpClient
                Host = "",
                Port = 587,
                EnableSsl = true,
                DeliveryMethod = SmtpDeliveryMethod.Network,
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential(fromAddress.Address, fromPassword)

It is very handy if you don’t have a smtp server setup.