title: Client side validation not working with reused and nested complex property
body: <p>I have an asp.net MVC 5 application in which I tried to re-use a nested complex view model class in different places in an <code>.cshtml</code> file. The reused complex view model is named as <code>SchoolPersonViewModel</code> that has many properties, and the <code>Phone</code> and <code>Email</code> properties are validated  like "If Phone is not provided, then Email must be provided. If Phone is provided, then Email is optional input". I wrote a custom server and client side validation but it works with server side. But the <strong>client side validation</strong> is not working properly. For example <code>Email</code> text box prompts to be filled even though the associated <code>Phone</code> text box is filled. Please see the attachment. For example.<a href="https://i.stack.imgur.com/WhMXF.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WhMXF.png" alt="enter image description here"></a> Please help. Thank you beforehand.</p>
  
  <p>I know the problem comes from the error: there are 3 validation attributes for the 3 Email text boxes with same value as <code>data-val-emailrequired-stringphoneprop="Phone"</code> . The <code>Phone</code> value at run time causes the ambiguity 
   (it is the uniqueness is missing) for the jQuery validation machine but I do not how to solve it. Please see the rendered attributes below. Please help. Thank you in advance.</p>
  
  <p><strong><em>Details about my codes:</em></strong> </p>
  
  <p>On my <code>cshtml</code> view, I call the view model complex class (<code>SchoolPersonViewModel</code>) 3 times: one for <code>Student</code>, one for <code>Father</code> and one for <code>Mother</code>.</p>
  
  <p>C# MVC model classes</p>
  
  <pre><code>public class SchoolPersonViewModel
  {
      [DisplayName("Phone")]
      public string Phone { get; set; }
      [DisplayName("Email")]
      [EmailRequired(StringPhonePropertyName = "Phone", ErrorMessage = "Email is required if Phone is not provided")]
      public string Email { get; set; }
      .... // other properties
  }
  
  public class StudentEnrollViewModel
  {
      public SchoolPersonViewModel Student { get; set; }
      public SchoolPersonViewModel Father { get; set; }
      public SchoolPersonViewModel Mother { get; set; }
  }
  </code></pre>
  
  <p>Validation attribute</p>
  
  <pre><code>// If Phone is not input then Email is required -- server and client side validation
  public class EmailRequiredAttribute : ValidationAttribute, IClientValidatable
  {
      public string StringPhonePropertyName { get; set; }
  
      protected override ValidationResult IsValid(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext)
      {
          var phone = ValidatorCommon.GetValue&lt;string&gt;(validationContext.ObjectInstance, StringPhonePropertyName);
          var email = (string)value;
          if (!string.IsNullOrWhiteSpace(phone) || (string.IsNullOrWhiteSpace(phone) &amp;&amp; !string.IsNullOrWhiteSpace(email)))
          {
              return ValidationResult.Success;
          }
          if (string.IsNullOrWhiteSpace(phone) &amp;&amp; string.IsNullOrWhiteSpace(email))
          {
              return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
          }
          return ValidationResult.Success;
      }
  
      public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
      {
          var modelClientValidationRule = new ModelClientValidationRule
          {
              ValidationType = "emailrequired",
              ErrorMessage = FormatErrorMessage(metadata.DisplayName)
          };
  
          modelClientValidationRule.ValidationParameters.Add("stringphoneprop", StringPhonePropertyName);
          yield return modelClientValidationRule;
      }
  }
  </code></pre>
  
  <p>Container view model and the jQuery validation codes:</p>
  
  <pre><code>@model ExpandoObjectSerializeDeserialize.Web.Models.StudentEnrollViewModel
  ....
  @using (Html.BeginForm())
  {
      @Html.AntiForgeryToken()
      ....
      @Html.EditorFor(m =&gt; m.Student)
      ....
      @Html.EditorFor(m =&gt; m.Father)
      ....
      @Html.EditorFor(m =&gt; m.Mother)
  
      &lt;input type="submit" value="Create" class="btn btn-default" /&gt;
  }
  
  @section scripts {
      &lt;script type="text/javascript"&gt;
          jQuery.validator.addMethod('emailrequired', function(value, element, params) {
              var phoneTextboxId = $(element).attr('data-val-emailrequired-stringphoneprop');
              var phoneTextboxValue = $('#' + phoneTextboxId).val();
              // empty string is evaluated as ‘false’ and non-empty, non-null string is evaluated as ‘true’ in JavaScript
              return phoneTextboxValue || value;
          });
  
          jQuery.validator.unobtrusive.adapters.add('emailrequired', {}, function(options) {
              options.rules['emailrequired'] = true;
              options.messages['emailrequired'] = options.message;
          });
      &lt;/script&gt;
  }
  </code></pre>
  
  <p>The above view is rendered as follows at running time:</p>
  
  <pre><code>&lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line" id="Father_Phone" name="Father.Phone" type="text" value=""&gt;
      &lt;span class="field-validation-valid text-danger" data-valmsg-for="Father.Phone" data-valmsg-replace="true"&gt;&lt;/span&gt;
  &lt;/div&gt;
  &lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line input-validation-error" data-val="true" data-val-emailrequired="Email is required if Phone is not provided" data-val-emailrequired-stringphoneprop="Phone" id="Student_Email" name="Student.Email" type="text" value=""&gt;
      &lt;span class="text-danger field-validation-error" data-valmsg-for="Student.Email" data-valmsg-replace="true"&gt;&lt;span for="Student_Email" class=""&gt;Email is required if Phone is not provided&lt;/span&gt;&lt;/span&gt;
  &lt;/div&gt;
  &lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line" id="Mother_Phone" name="Mother.Phone" type="text" value=""&gt;
      &lt;span class="field-validation-valid text-danger" data-valmsg-for="Mother.Phone" data-valmsg-replace="true"&gt;&lt;/span&gt;
  &lt;/div&gt;
  &lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line input-validation-error" data-val="true" data-val-emailrequired="Email is required if Phone is not provided" data-val-emailrequired-stringphoneprop="Phone" id="Father_Email" name="Father.Email" type="text" value=""&gt;
      &lt;span class="text-danger field-validation-error" data-valmsg-for="Father.Email" data-valmsg-replace="true"&gt;&lt;span for="Father_Email" class=""&gt;Email is required if Phone is not provided&lt;/span&gt;&lt;/span&gt;
  &lt;/div&gt;
  &lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line" id="Mother_Phone" name="Mother.Phone" type="text" value=""&gt;
      &lt;span class="field-validation-valid text-danger" data-valmsg-for="Mother.Phone" data-valmsg-replace="true"&gt;&lt;/span&gt;
  &lt;/div&gt;      
  &lt;div class="col-md-4"&gt;
      &lt;input class="form-control text-box single-line input-validation-error" data-val="true" data-val-emailrequired="Email is required if Phone is not provided" data-val-emailrequired-stringphoneprop="Phone" id="Mother_Email" name="Mother.Email" type="text" value=""&gt;
      &lt;span class="text-danger field-validation-error" data-valmsg-for="Mother.Email" data-valmsg-replace="true"&gt;&lt;span for="Mother_Email" class=""&gt;Email is required if Phone is not provided&lt;/span&gt;&lt;/span&gt;
  &lt;/div&gt;
  </code></pre>