So I decided to make an auction house web application as my first asp.net mvc project and I cannot figure out how to pass a parameter between two views that belong to different controllers. In the first view, Details of AuctionHouseController, I have:
<a class="btn btn-default" href="#Url.Action("Create", "Auctions", new { id = Model.ItemId })">Start Auction »</a>
and a URL: http://localhost:2142/AuctionHouse/Details/123
And here is the Details method:
public ActionResult Details(int id)
{
var item = _auctionhDbc.Items.Find(id);
return View(item);
}
I want to pass the id part of the URL - the "123" to the view where the button leads - Create of AuctionsController, where I have:
<div class="form-group">
#Html.LabelFor(model => model.Item.ItemId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Item.ItemId, new { htmlAttributes = new { #class = "form-control", #Value = " " } })
#Html.ValidationMessageFor(model => model.Item.ItemId, "", new { #class = "text-danger" })
</div>
</div>
I want to place the "123" as the default value (#Value) of the Html Editor field. How can I do that?
Assuming you are using strongly typed views, your model for the Create view will already have the value of 123 in ItemID. The problem is, your model is of type Items, yet you are trying to use EditorFor for model.Item.ItemID.
Thus, instead of your line
#Html.EditorFor(model => model.Item.ItemId,
new { htmlAttributes = new { #class = "form-control", #Value = " " } })
if you use
#Html.EditorFor(model => model.ItemId,
new { htmlAttributes = new { #class = "form-control" } })
you will already have passed the value there. Make sure you use strongly typed views by putting:
#model YourNameSpace.Items
in the beginning of your view.
Related
I'm using C#/.NET in Visual Studio and the MVC framework.
I have a form that I'm working with, and I was able to get it to output the correct error message at the appropriate time. My issue is that the input field of the form is supposed to highlight red with a has-error class when the field is either not filled in or filled in incorrectly. I could do this if I was using regular form tags, but because this is connected to an Umbraco project, I have to use Html.EditorFor and Html.ValidationMessageFor.
Is there a way (either using jQuery or modifying the existing code) to add a class to the Html.EditorFor field upon Html.ValidationMessageFor deciding it should display the message?
Here is a portion of my View:
<div class="name-field">
<label>Name</label>
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
#if (#Html.ValidationMessageFor(model => model.Name) != null)
{
#Html.ValidationMessageFor(model => model.Name, null, new { #class = "contact-form-error-msg text-danger small-sized", #id = "contact-form-name-error-1", #style = "display:block;" })
}
</div>
and here is the attribute in my Model:
[Required(ErrorMessage = "Please enter a contact name.")]
public string Name { get; set; }
Like I said, the error message shown in the model is showing up correctly. My issue is just applying the has-error class to the Html.EditorFor field which I have a feeling is going to require jQuery; however, I'm not sure how to access the existing code in a jQuery block.
Thank you.
Edit: I was notified that my question could be a possible duplicate of the question here (How can I check if my model is valid from inside the razor view?). With some modification I was able to find the solution to my problem.
#if (!ViewData.ModelState.IsValidField("Name")) {
<div class="name-field has-error">
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
#if (#Html.ValidationMessageFor(model => model.Name) != null)
{
#Html.ValidationMessageFor(model => model.Name, null, new { #class = "contact-form-error-msg text-danger small-sized", #id = "contact-form-name-error-1", #style = "display:block;" })
}
</div>
} else {
<div class="name-field">
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
</div>
}
Hit a strange issue where my model is not binding and shows up on the controller as null.
I have a form doing a httppost. My breakpoint in the controller is hit and the parameter I expect to be my model is null.
Looking at some example code on another page that works, I copied and pasted it and the only difference was the name of the parameter was 'model' instead of message.
View
#model Site.Models.ContactMessage
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ContactMessage</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Message, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Message, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Message, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.To, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.To, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.To, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
public ActionResult Contact()
{
return View();
}
[HttpPost]
public ActionResult Contact(ContactMessage message)
{
var m = message;
return View();
}
and it worked. I thought I must have entirely missed something about naming convention. Found you can use Bind, from reading a heap of other posts, to change the prefix like;
public ActionResult Contact([Bind(Prefix = "model")] ContactMessage message)
but that didn't work, still null. Going to rename it to model so it works and I can move on but would like to know why it's not binding if not called model.
public ActionResult Contact(ContactMessage message)
Changed back to this as above but still returns a null.
Interestingly, if I open up another MVC app, that one has whatever parameter names I want and works fine. It's using an older version of MVC 5 (not updated it yet but I will do that and see if anything happens. I don't expect it will.)
Your problem is that you model contains a property named Message and you also have a parameter named message The DefaultModelBinder reads the form values which will include message = "someTextValue" and searches for model properties that have the name message. It finds the one in you model and sets it value (all OK so far) but then it finds another one (your parameter) and tries to set the value of a complex object string value (in effect ContactMessage message = "someTextValue";) which fails so the model becomes null
I'm trying to add a required to my TextAreaFor, but it won't give the error message when i post it. I'm trying to do it on the followinng line:
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
And this is my full code:
#using (Html.BeginForm("_Create", "Comments", FormMethod.Post))
{
#Html.HiddenFor(m => m.ThreadId)
<div class="form-group">
<div class="col-md-10">
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger"})
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Post" class="btn btn-default" />
</div>
</div>
}
If anyone wanst to do it with html attribute,
#Html.TextAreaFor(model => model.Content, new { required = "required", htmlAttributes = new { #class = "form-control"} })
You don't need required as a html attribute. It should be a data annotation on the model.
[Required]
public string Content { get; set; }
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
Should be:
#Html.TextAreaFor(model => model.Content, new { #class = "form-control", required = "required" })
Or if you want to explicitly name the parameter your anonymous object is for:
#Html.TextAreaFor(model => model.Content, htmlAttributes: new { #class = "form-control", required = "" } })
But, if you do not use data-annotation, it could be even easier this way:
<textarea id="Content" name="Content" required class="form-control">#Model.Content</textarea>
(id attribute may be optional, depending on your usages.)
Side note: I tend to minimize uses of html helpers methods. For me, MVC is also about letting you control very precisely the browser client code, which is imo better done by writing it yourself. WebForm is, on this subject, about hiding most of browser client code handling.
Using extensively html helpers, built-in validation logic, and so on, may cause you to lose the precise control of how your page should work.
This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 7 years ago.
I have discovered the Foolproof library that seems very nice but I am having problems to put it working.
I want to create a required field only if the dropdown has the selected value = 7.
Simple Model:
[RequiredIf("LeadSource_Id","7", ErrorMessage = "Campo obrigatório")]
public string SourceDescription { get; set; }
[Display(Name = "Origem")]
public virtual int LeadSource_Id { get; set; }
The way I create the Dropdown in the Controller:
ViewBag.LeadSource_Id = new SelectList(db.LeadSources.ToList(), "Id", "Name");
The View:
<div class="form-group">
#Html.LabelFor(model => model.LeadSource_Id, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("LeadSource_Id", null, htmlAttributes: new { #class = "form-control ld-lead-source" })
#Html.ValidationMessageFor(model => model.LeadSource_Id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group collapse">
#Html.LabelFor(model => model.SourceDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SourceDescription, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SourceDescription, "", new { #class = "text-danger" })
</div>
</div>
When I try to see if the validation is working when I select the value 7, I get the error:
The ViewData item that has the key 'LeadSource_Id' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
EDIT:
The libraries I include are:
<script src="~/Scripts/jquery/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery/jquery.validate.unobtrusive.min.js"></script>
<script src="~/Scripts/jquery/jquery.validate.globalize.min.js"></script>
<script src="~/Scripts/mvcfoolproof.unobtrusive.min.js"></script>
The error occurs because the value ofViewBag.LeadSource_Id is null. Since you have set its value in the GET method, then presumably this error is occurring when you return the view in your POST method (which you have omitted) but have not reassigned the value. In addition you cannot give the ViewBag property the same name as your model property.
Change your controller code to (say)
ViewBag.LeadSourceList = new SelectList(db.LeadSources.ToList(), "Id", "Name");
and ensure this code appears in both the GET method and POST method is you return the view, and modify the view to
#Html.DropDownList("LeadSource_Id", IEnumerable<SelectListItem>ViewBag.LeadSourceList , { #class = "form-control" })
However the recommended approach is to use a view model containing a property public IEnumerable<SelectListItem> LeadSourceList { get; set;}
Currently I have a view which takes an IEnumerable model which I use to display data on the view. However on the same view I also have a modal popup in which I want to add to the model rather than separating them out into different views. I tried to follow the suggestion at the bottom of this question How to access model property in Razor view of IEnumerable Type? but got an exception
The expression compiler was unable to evaluate the indexer expression '(model.Count - 1)' because it references the model parameter 'model' which is unavailable.
At the top of the view I have
#model IList<Test.Models.DashModel>
and within my modal body I have
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DashboardModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model[model.Count - 1].DashName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model[model.Count - 1].DashName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model[model.Count - 1].DashName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model[model.Count - 1].CreatedDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model[model.Count - 1].CreatedDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model[model.Count - 1].CreatedDate, "", new { #class = "text-danger" })
</div>
</div>
</div>
}
I agree that overuse of the word Model, i.e. the #model keyword, the Model instance variable of the same type, and the default name model given to the lambda parameter name of the HtmlHelper methods is really confusing.
Unfortunately model in this case is the parameter passed by the Html.*For extension methods into your lambda. IMO the scaffolded views could have chosen a less conflicting parameter variable name for the lambdas, e.g. m or x etc.
To access the actual ViewModel instance passed to the view (i.e. #model defined at the top of your razor .cshtml, viz #model IList<Test.Models.DashModel>), what you want to do is to access Model (note the case difference):
#Html.LabelFor(model => Model.Last().CreatedDate, ...
I would also recommend using the Linq extension methods such as Last() / First() etc rather than using the array indexers.
Out of interest, you can of course change the parameter name to anything you like, e.g.
#Html.LabelFor(_ => Model.Last().CreatedDate, ...