Dynamic Naming of DropDownListFor - asp.net-mvc-5

I have an Address view for users to enter their addresses for both billing and shipping. So on the Address model I have:
public string AddressType { get; set; }
Then on the Create Account view I have:
<div class="pure-control-group">
#Html.Action("Init", "Address", new {AddressType="Billing"})
</div>
<div class="pure-control-group">
#Html.Action("Init", "Address", new {AddressType="Shipping"})
</div>
In the Address View I have a number of input controls that all render as expected but I also have a Country Dropdown List that I want to dynamically name (the only control I am using the html helper for):
#Html.DropDownListFor(m => m.SelectedCountryId, new SelectList(Model.ValidCountries, "CountryId", "CountryName", Model.SelectedCountryId), null, new {name=Model.AddressType + "_SelectedCountryId", id=Model.AddressType + "_SelectedCountryId"})
However when this renders I end up with:
<select id="Billing_SelectedCountryId" name="SelectedCountryId">
I want:
<select id="Billing_SelectedCountryId" name="Billing_SelectedCountryId">
I have read that using an upper case N for Name fixes this but as others have said it just adds another property:
<select id="Billing_SelectedCountryId" name="SelectedCountryId" Name="Billing_SelectedCountryId">
Everything I have read is a bit confusing and I can't make out if anyone found a fix, Is there anyway round this?

Related

How to use DataAnnotations Display attribute for multiple radio button lables

It's handy to use a Display attribute for model properties in MVC:
Model:
[Display(Name="Your Name:")]
public string Name { get; set; }
View:
#Html.LabelFor(m => m.Name)
#Html.EditorFor(m => m.Name)
But ... is it possible to use the Display attribute for naming the individual choices for radio buttons? The following is what I use now, but the 'Label for...' tag is a little inconsistent with the rest of the view. Anyone?
<div class="radio-inline">
#Html.RadioButtonFor(m => m.OpenToPublic, true, new { id = "isOpenToPublic" })
<label for="isOpenToPublic">Open to the Public</label>
</div>
<div class="radio-inline">
#Html.RadioButtonFor(m => m.OpenToPublic, false, new { id = "isInviteesOnly" })
<label for="isInviteesOnly">Invitees Only</label>
</div>
I like the code above, since using the Label tag results in being able to click on the label text to select the radio button, and the styling of the text is correct. I just wonder if there's a way to do this with data annotations on the model's property for the radio button.
Thanks,
Brian

Update #Html.Partial() View only

I am not looking for a javascript/jquery answer. I can do that, but I feel like it breaks the purpose. This seems like something that should be possible without javascript.
I'm trying to get a simple listbox selection to update an #Html.Partial section, and I'm not exactly sure what to do. Everything loads initially just fine. After I submit, however, I am not quite sure how to 'attach' to my partial view to update it.
The purpose here is to only load the listbox one time, and let them view or request as many new reports as they want without reloading. If it's not possible, that's fine, I can use one page, reload the listboxes, and it will work. I just don't see why I would need to go to the database to reload the listbox items every time they view or request a report.
"master" html page:
#using TCTReports.Models
#model ReportViewModel
<h2>My Reports</h2>
<div class="row">
<div class="col-md-6">
<h3>Select Report</h3>
#using (Html.BeginForm("GetReport", "Report"))
{
#Html.DropDownListFor(m => m.SelectedMyID, Model.myLB)
<input type="submit" value="View" />
}
</div>
<div class="col-md-6">
<h3>All Reports</h3>
#using (Html.BeginForm("ReqReport", "Report"))
{
#Html.DropDownListFor(m => m.SelectedAllID, Model.allLB)
<input type="submit" value="View" />
}
</div>
</div>
#Html.Partial("_Msg")
_Msg is super simple atm. It would eventually be a report viewer, for now, it looks at #Viewbag...
<h2>#ViewBag.Message</h2>
Controller submit actions (I get my selected value just fine. currently on void but was ActionResult with Views - but I don't feel like that is correct either, as it completely overwrites the page (even with PartialView) and I lose my listboxes and _layout...):
public void GetReport(ReportViewModel model)
{
var myID = model.SelectedMyID;
ViewBag.Message = "Report: " + myID.ToString() + " Selected.";
//return PartialView("_Msg","Test");
}
public void ReqReport(ReportViewModel model)
{
var allID = model.SelectedAllID;
ViewBag.Message = "Report: " + allID.ToString() + " Requested.";
//return PartialView("_Msg", "Test");
}
Ok, so how would I go about updating _Msg and refreshing only the #Html.PartialView() section of my master html page? I played with #sections briefly but didn't make much progress.

MVC 5 / Bind dropdownlist including disabled values

(My first quesion, I'm quite impressed :) )
First, please excuse my English, I'm French ;)
My issue is about DropDownList which is linked(bind) to a required field (F, int) of an object O (edited in a view V) and contains a list of elements (LE), some of them disabled.
The behavior I want in the view :
when I create an object, the validation must trigg if nothing
is selected in the list (OK)
when I create an object, the disabled elements of the list must not be selectable (OK)
when I edit an object, if the field is among enabled values, same behavior (OK)
when I edit an object, if the field is among disabled values, it must be displayed and selected when viewed (OK)
when I edit an object, if the field is among disabled values, when I post data, the client validation must authorize disabled values to be validated (OK with a little javascript)
My issue :
when I edit an object, if the field is among disabled values, when I
post data, the model contains null for the field linked to the
dropdownlist even if I include an hidden field with the Id.
Here is some of my code to help understand my issue.
Any idea of how I could include disabled values of my dropdown list in the model when I post data ?
Thanks for any help !
View :
<div class="col-md-3">
#Html.DropDownListFor(model => model.Currency.Id, (SelectList)ViewBag.Currencies, new { #class = "form-control ignore-desactivated" })
#Html.ValidationMessageFor(model => model.Currency, "", new { #class = "text-danger" })
</div>
JS :
$(function () {
$('form').validate().settings.ignore = '.ignore-desactivated';
});
Source when edition :
<div class="col-md-3">
<select class="form-control ignore-desactivated" data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Currency_Id" name="Currency.Id">
<option value="-1"></option>
<option disabled="disabled" value="9">Angolan kwanza (desactivated)</option>
<option value="10">Argentine peso</option>
<option disabled="disabled" selected="selected" value="1">Euro (desactivated)</option>
<option disabled="disabled" value="56">Gibraltar pound (desactivated)</option>
<option value="3">Great Britain Pound</option>
</select>
<span class="field-validation-valid text-danger" data-valmsg-for="Currency" data-valmsg-[replace][1]="true"></span>
</div>
My model when I want to save data :
https://i.stack.imgur.com/jQ9aH.png
... and I found an answer a few minutes after asking it (thanks to my colleagues)...
I don't know if that's correct, but a little js code to remove disabled items before the post did the trick :
//Delete disabled elements of lists before submit
$('form').submit(function () {
$('.ignore-desactivated').each(function () {
$(this).children().each(function () {
$(this).removeAttr('disabled');
});
})
})

MVC Validation on Subviews

I am working on a Sitecore/MVC application, my first MVC application so I am learning as I go. No doubt I am going wrong somewhere along the line.
I have a Basket that has 2 address views on it, one for billing and another for delivery. There is also a checkbox for "Delivery the same as billing" allowing the user to complete just one address. When you user checks this checkbox the delivery address div collapses.
Main view:
<div class="pure-control-group">
<h2>Billing Address</h2>
#Html.Action("Init", "Address", new {AddressType = "Billing", #Address = Model.Billing})
</div>
<!-- Delivery Address-->
<div class="pure-control-group">
<h2>Delivery Address</h2>
<label for="UseBillingForShipping" class="pure-checkbox">
#Html.CheckBoxFor(x => x.UseBillingForShipping)
Same as Billing Address above
</label>
</div>
<div class="manual-address-entry focus-pane">
#Html.Action("Init", "Address", new {AddressType = "Delivery", #Address = Model.Delivery})
</div>
An example of the Address view:
<div class="pure-u-1 pure-u-sm-1-2 pure-u-lg-2-5">
<label for="#(Model.AddressType).FirstName">First Name<span class="required">*</span></label>
<input type="text" id="#(Model.AddressType).FirstName" name="#(Model.AddressType).FirstName">
#Html.ValidationMessageFor(x=>x.FirstName) //<= How to handle this?
</div>
<div class="pure-u-1 pure-u-sm-1-2 pure-u-lg-2-5">
<label for="#(Model.AddressType).LastName">Last Name<span class="required">*</span></label>
<input type="text" id="#(Model.AddressType).LastName" name="#(Model.AddressType).LastName">
#Html.ValidationMessageFor(x=>x.LastName) //<= How to handle this?
</div>
My problem occurs when I am trying to validate. The id of the controls on the address view are named id="#(Model.AddressType).LastName" so in the case of the Billing address they render like id="Billing.LastName"
On the Address model the fields are annotated, e.g:
[Required(ErrorMessage = "First Name is required")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required")]
public string LastName { get; set; }
So I have 2 problems:
How do I create the #Html.ValidationMessageFor markup. I have tried #Html.ValidationMessageFor(x=>x.FirstName) and something similar to the labelfor (<label for="#(Model.AddressType).LastName">), #Html.ValidationMessageFor(#(Model.AddressType).LastName) and neither work. I am starting to think I have approached this totally the wrong way.
The second is if the user selects the checkbox for same address how would I go about switching off validation for the second address only.
The easiest way to handle this is to use a custom EditorTemplate for your address model. Assuming its public class Address, then create a view in /Views/Shared/EditorTemplates named Address.cshtml (i.e. named to match the name of your type)
#model yourAssembly.Address
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
... // ditto for other properties of Address
Then in the main view
#Html.EditorFor(m => m.Billing)
#Html.CheckBoxFor(x => x.UseBillingForShipping)
#Html.EditorFor(m => m.Delivery)
The EditorFor() method will use your template and correctly name all elements for binding (including the validation message)
Note that because you have a [Required] attribute, the script that hides the 'Delivery' address, should also ensure that it copies the contents of the 'Billing' to the 'Delivery' address controls otherwise validation will fail (alternatively you could use a [RequiredIf] validation attribute)

Craeting Custom Widget in Orchard 1.7

I am new to Orchard. So please forgive me if there is anything looking silly!
I want to create a custom widget for my Orchard website to encourage visitors to sign up for my Newsletter service. I have seen there is an option of using HTML widget but I want to create a new widget type like "Newsletter" which I shall use conditionally at AsideFirst block.
Is this possible to do? I only want to grab visitor's Name and Email address, and the form submission will be done using an action controller.
Do I have to create this widget through by-hand coding in VS? In fact I want to this way, not through the Orchard admin console.
Seeking for help. Any suggestion please?
Edit:
I have managed to create the widget following Sipke Schoorstra's suggestion. The area where I want to display the widget is now showing along with the the title I set from admin at the time of adding it to a zone. But the content (form elements) I created in the view is not displaying.
The View: (Views/NewsLetterSignupPart/NewsletterSignup.cshtml)
#model Emfluence.Intrust.Models.NewsLetterSignupPart
#{
ViewBag.Title = "Newsletter Signup";
}
#using (Html.BeginForm("NewsletterSignup", "NewsLetter", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="row-fluid">
<div class="span6">
<label>Name</label>
<input type="text" name="txtNewsletterUserName" required maxlength="50" style="width: 95%" />
<label>Email</label>
<input name="txtNewsletterUserEmail" type="email" required maxlength="85" style="width: 95%" />
<button class="btn pull-right">Submit</button>
</div>
</div>
}
Migration.cs
public int UpdateFrom15()
{
ContentDefinitionManager.AlterTypeDefinition(
"NewsletterWidget", cfg => cfg
.WithPart("NewsLetterSignupPart")
.WithPart("CommonPart")
.WithPart("WidgetPart")
.WithSetting("Stereotype", "Widget")
);
return 16;
}
NewsLetterSignupPart.cs
public class NewsLetterSignupPart : ContentPart<NewsletterSignupRecord>
{
[Required]
public string Name
{
get { return Record.Name; }
set { Record.Name = value; }
}
[Required]
public string Email
{
get { return Record.Email; }
set { Record.Email = value; }
}
}
And NewsletterSignupRecord.cs
public class NewsletterSignupRecord : ContentPartRecord
{
public virtual string Name { get; set; }
public virtual string Email { get; set; }
}
Where I am doing wrong?
The Custom Forms module is great if you don't want or need to code something yourself. In case you do want to handle form submissions yourself without using Custom Forms, this is what you could do:
Create a custom module
Create a migrations class that defines a new widget content type (see the docs for details on how to do this. Note: you don't need to create a custom part. You don't even need to create a migrations file to create a content type - you could do it using a recipe file. The nice thing about a migration though is that it will execute automatically when your module's feature is enabled).
Create a view specific for content items of your widget type (e.g. Widget-Newsletter.cshtml).
Inside of this view, write markup that includes a form element and input elements. Have this form post back to your controller.
Create your controller.
In the /admin interface, click Modules, on the Features` tab search for Custom Forms and click Enable. This will add a new Forms admin link on the left.
Next, create a custom content type (under Content Definition) called Newsletter, and add two fields (of type Text Field) called Name and E-mail.
Finally, click Forms and add a new Custom Form. Give it a title: this will be the default URL to access e.g. "Newsletter Form" will have a URL of /newsletter-form by Orchard defaults. Under Content Type select your newly created content type, Newsletter, from the dropdown. Customize anything else you want on this page, and click Publish Now
If you want to make this a widget, edit the content type and add the Widget Part. Create a layer with the rules you need and you can add the "Newsletter" widget to any zone you need on that layer.

Resources