2

I have a partial twice on a view. Partial doesnt use a loop and has basic validation.

Here is the partial view code:

 <div class="col-md-4">
                    @Html.LabelFor(model => model.ZipCode, new { @class = "control-label " })
                    @Html.TextBoxFor(model => model.ZipCode, new { @class = "form-control ",  tabindex = "4" })
                    @Html.ValidationMessageFor(model => model.ZipCode)
                </div>

Here is my main view calling it twice:

<div id="homeaddress">
                                @if (Model == null)
                                {
                                @Html.Partial("~/Views/AddrPartial.cshtml", new Address())
                            }
                            else
                            {
                                @Html.Partial("~/Views/AddrPartial.cshtml", Model.HomeAddress)
                            }
                        </div>

<div id="mailingaddress">
                                @if (Model == null)
                                {
                                    @Html.Partial("~/Views/AddrPartial.cshtml", new Address())
                                }
                                else
                                {
                                    @Html.Partial("~/Views/AddrPartial.cshtml", Model.MailingAddress)
                                }
                            </div>

Then only the "homeadrress" div validation works... here's how my model is setup:

    public class Information
   {
    public Address HomeAddress { get; set; }
    public Address MailingAddress { get; set; }
    }

Then have a separate Address class...

public class Address
{
        [Display(Name = "Address")]
        public string Addr1 { get; set; }
        [Display(Name = "Address 2")]
        public string Addr2 { get; set; }
        [Display(Name = "Zip Code")]
        [RegularExpression(@"^\d{5}(-\d{4})?|^$", ErrorMessage = "Invalid Zip Code")]
        public string ZipCode { get; set; }

}

The html generated shows the problem... the mailingaddress html doesnt have the regex necessary to check validation..

<input class="form-control " data-val="true" data-val-regex="Invalid Zip Code" data-val-regex-pattern="^\d{5}(-\d{4})?|^$" id="ZipCode_home" name="ZipCode_home"  tabindex="4" type="text" value="12345">
<span class="field-validation-valid" data-valmsg-for="ZipCode_home" data-valmsg-replace="true"></span>

<input class="form-control " id="ZipCode_mailing" name="ZipCode_mailing"  tabindex="4" type="text" value="54321">
<span class="field-validation-valid" data-valmsg-for="ZipCode_mailing" data-valmsg-replace="true"></span>

after reviewing this code my question is why is this happening and how can i fix this. Thanks in advance I can answer questions and provide more code if need be.

jgabb
  • 542
  • 1
  • 4
  • 20
tshoemake
  • 1,311
  • 1
  • 17
  • 28
  • Are you asking to provide you an email validation regex? See [*validating email address using regular expression on razor page*](http://stackoverflow.com/questions/9590176/validating-email-address-using-regular-expression-on-razor-page). – Wiktor Stribiżew Mar 18 '16 at 14:53
  • Why would you think that @WiktorStribiżew – tshoemake Mar 18 '16 at 14:55
  • *The html generated shows the problem... the mailingaddress html doesnt have the regex necessary to check validation*... *why is this happening and how can i fix this* – Wiktor Stribiżew Mar 18 '16 at 14:56
  • 1) its a physical address, not email. 2) because of this it requires zip code validation. 3) I have the regex validation in the code provided. It works for the first partial instance. the second it does not. thats where im having trouble. – tshoemake Mar 18 '16 at 14:57
  • Is the `Model.MailingAddress` property `null` by any chance? – Greg Burghardt Mar 18 '16 at 14:58
  • @GregBurghardt i haven't tested for that, in the future it could be, but not in this instance no. – tshoemake Mar 18 '16 at 14:59
  • 1
    If you rename you partial to `/Views/Shared/EditorTemplate/Address.cshtml` (i.e. so thats its an `EditorTemplate`), then its simply `@Html.EditorFor(m => m.HomeAddress)` and `@Html.EditorFor(m => m.MailingAddress)` and all of this is handled correctly out of the box (the correct prefix will be added to your form controls) –  Mar 18 '16 at 21:30

2 Answers2

4

That's because you are rendering two instances of the Address partial page. The model binding framework requires that the HTML fields follow this naming convention for the model binding to work as expected

<input id="ShippingAddress_Street1" 
   name="ShippingAddress.Street1" type="text" value="" />
<input id="BillingAddress_Street1" 
   name="BillingAddress.Street1" type="text" value="" />

As you can see from the above markup the id and name attributes must fully qualify the model property being bound.

The above problem can be solved by using a variation of the Partial() helper while rendering the Address partial page

Html.Partial("_Address", 
new ViewDataDictionary() 
{ 
     TemplateInfo = new TemplateInfo() 
      { HtmlFieldPrefix = "ShippingAddress" } })

<h3>Billing Address</h3>
@Html.Partial("_Address", 
new ViewDataDictionary() 
{ 
    TemplateInfo = new TemplateInfo() 
       { HtmlFieldPrefix = "BillingAddress" } })
jgabb
  • 542
  • 1
  • 4
  • 20
  • Will this work when you update each of the 'Address panels' via `$.ajax({ ... success: function (data) { $("#newPanel").html(data); ... });` ? (Where the Action method called returns a `PartialView("_MyPanel", spPanelVm);`) – Scott Fraley Jun 28 '17 at 21:55
1

For some reason the above code didn't work for me so I ended up writing it as follows:

@Html.Partial("_Address",
                 Model?.Form?.BillingAddress,
                 new ViewDataDictionary(ViewContext.ViewData)
                 {
                     TemplateInfo = { 
                                      HtmlFieldPrefix = "billing",
                                      FormattedModelValue = "Billing address" 
                                    }
                 })

I am using FormattedModelValue to store the label as the same view is used to generate company address and the billing address.

Hope that helps

user3012760
  • 203
  • 2
  • 6
  • ViewDataDictionary() does not have a constructor that takes for 0 arguments!!! So Your constructor has the ViewData requested argument – klingu Dec 06 '19 at 13:28