So I am developing my first webpage using ASP.NET MVC and I managed to create a fully working registration page which send the data to the database and stored the user. Simple.
However I didn't really like the look and feel of the element it created for me so I thought I could change it out.
Original code WORKING
<div class="form-group">
#Html.LabelFor(model => model.Firstname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Firstname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Firstname, "", new { #class = "text-danger" })
</div>
</div>
My new code NOT WORKING
<div class="row">
<div class="input-group bb-none">
<i class="fas fa-address-card"></i>
<input type="text" placeholder="Firstname">
</div>
</div>
I am 99.9% sure that it's a binding issue. I want the data I put into my new textbox
<input type="text" placeholder="Firstname">
To carry over the data to the model.
What's the part that binds it in the first option?
Tag helpers will resolve down to html and put the property name as both the id and name within the input. The model binder then binds to that.
#Html.TextBoxFor( m => m.Firstname, new { placeholder = "Firstname" })
Related
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
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've been working on MVC project, and I've been trying to integrate (jquery) datetimepicker so far if I add it as a simple HTML control it works as expected:
_layout.cshtm
#Scripts.Render("~/bundles/jquery")
BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
View
>
<p>Date: <input type="text" id="datetimepicker" /></p>
<script type="text/javascript">
jQuery('#datetimepicker').datetimepicker({});
</script>
But when I try to used embeded on my code it don't work:
<div class="form-group">
#Html.LabelFor(model => model.deliveryDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.deliveryDate, new { #id = "datetimepicker", #type="text" })
#Html.ValidationMessageFor(model => model.deliveryDate)
</div>
</div>
Any suggestion?
Please let me know if you need more code, I would gladly to share it.
jQuery datetimepicker is an extension of jQuery which comes with jQuery UI. As far as I can tell, and as pointed out by Stephen Muecke, it doesn't seem like you are including any jQuery UI code. Here is a link to the jQuery UI download page to get the minimum code required to get the datepicker to work: http://jqueryui.com/download/#!version=1.11.2&themeParams=none&components=1000000000001000000000000000000000000
I had a similar problem before and the problem is the { #id = "datetimepicker", #type="text" } the reference: jQuery('#datetimepicker').datetimepicker({}); it's ok, but you need replace the type=text for type="datatime" that should works
<div class="form-group">
#Html.LabelFor(model => model.deliveryDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.deliveryDate, new { #id = "datetimepicker", #type="datetime" })
#Html.ValidationMessageFor(model => model.deliveryDate)
</div>
</div>
I've been following the nerd dinner tutorial. I branched off to create my own project based on it and I'm having trouble getting UpdateModel to work. It seems pretty complicated so I'll try to explain it in as much detail below.
In ServersController.cs:
public ActionResult Create(FormCollection formValues)
{
Server server = new Server();
try
{
UpdateModel(server); <----- This is not working
// server.Name = "testAdd";
// server.OS = "2008 R2";
serverRepository.Add(server);
serverRepository.Save();
return RedirectToAction("Details", new { id = server.ServerID });
}
catch
{
**not important**
}
If I try to use UpdateModel(Server), nothing gets saved to the database table. However, If I comment out that line, and use the commented lines in the code that sets the server.Name and server.OS, this DOES save it to the table. However, any other form input that's being posted doesn't save..
For example, if I explicitly set the server.Name and server.OS as in the code above, but then set other properties such as LastBackedUp and Model through the form, none of the properties set from the form are saved to the database table, nor are they reflected in the "details" view when the page gets redirected.
Here's the code for the "Details" GET method, also in ServersController.cs:
public ActionResult Details(int id)
{
Server server = serverRepository.GetServer(id);
RackInfo rackInfo = rackRepository.GetRack(id);
if (server == null)
return View("NotFound");
else
return View(new ServerDetailViewModel(rackInfo, server));
}
Basically, After the new server is created and saved, it's supposed to load the above "Detail" view, which uses a "ServerDetailViewModel" class to generate some data to pass to the view.
Here's the ServerDetailViewModel() code:
public class ServerDetailViewModel
{
public RackInfo RackInfo { get; private set; }
public Server Server { get; private set; }
public string Name { get; private set; }
public ServerDetailViewModel(RackInfo rackInfo, Server server)
{
Server = server;
RackInfo = rackInfo;
*more code here that sets stuff*
}
}
I think my problem has something to do with how my form parameters are passed around.
It seems odd that I can explicitly code in some server properties, and then save those into the database table. But when I try to do anything with UpdateModel, nothing seems to go through. When I use UpdateModel, it will redirect me to the details page, but none of the values I input for the properties seem to appear. Additionally, none of the properties I put in through the form gets saved to the database table.
If any of you have walked through the Nerd Dinner tutorial (http://weblogs.asp.net/scottgu/archive/2009/04/28/free-asp-net-mvc-nerddinner-tutorial-now-in-html.aspx), that's what I've been using. When I got through about halfway, I decided to start a new project that implemented what I was using.
I was initially able to get Create to work, but after adding another separate repository to the controller, the create method broke..
Any input or insight on this would be much appreciated. Please let me know if you need any additional information.
Thanks S.O.!!
EDIT (Including the "Create" Form):
#model PACSSL.Models.ServerFormViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Server</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Server.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Name)
#Html.ValidationMessageFor(model => model.Server.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Domain, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Domain, Model.Domain)
#Html.ValidationMessageFor(model => model.Domain)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BackedUp, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.BackedUp, Model.BackedUp)
#Html.ValidationMessageFor(model => model.BackedUp)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Role, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Role)
#Html.ValidationMessageFor(model => model.Server.Role)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.GroupOwner, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.GroupOwner)
#Html.ValidationMessageFor(model => model.Server.GroupOwner)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.PatchNotes, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.PatchNotes)
#Html.ValidationMessageFor(model => model.Server.PatchNotes)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.LastPatched, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.LastPatched) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.LastPatched)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PatchedBy, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.PatchedBy, Model.PatchedBy)
#Html.ValidationMessageFor(model => model.PatchedBy)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VP, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.VP, Model.VP)
#Html.ValidationMessageFor(model => model.VP)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.VMHost, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.VMHost)
#Html.ValidationMessageFor(model => model.Server.VMHost)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Location, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Location)
#Html.ValidationMessageFor(model => model.Server.Location)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.PurchaseDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.PurchaseDate) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.PurchaseDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.OS, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.OS)
#Html.ValidationMessageFor(model => model.Server.OS)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.Model, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.Model)
#Html.ValidationMessageFor(model => model.Server.Model)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.DellST, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.DellST)
#Html.ValidationMessageFor(model => model.Server.DellST)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.ServiceContract, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.ServiceContract) Format: yyyy-mm-dd
#Html.ValidationMessageFor(model => model.Server.ServiceContract)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Server.IsLive, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Server.IsLive)
#Html.ValidationMessageFor(model => model.Server.IsLive)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Here's your problem.
When you generate a form field with the expression model => model.Server.OS, you produce a field that has a 'name' attribute like this:
"Server.OS"
Then, when you try and bind it to a model, it will bind to a model property matching the expression "Server.OS" - so, if your model object is server, it will bind to the following:
server.Server.OS
When, I presume, you want to bind to server.OS. My suggestion would be to flatten out your view model so instead of having Model.Server.OS you just have Model.OS. Then when you do...
UpdateModel(server);
... it should bind the "OS" field to the "OS" property.
In short: your view model has an extra level of property nesting compared to your server object, so there is a mismatch in the generated field names and the properties you're trying to bind to.
Better still, bind back to the same view model by modifying your controller action to have the signature:
public ActionResult Create(ServerDetailViewModel model)
And then do the mapping manually in the controller (or some static mapping class) - your view models and domain model should be completely independent.
You are trying to update a "empty" Model. It is empty because you are creating a new instance.
Server server = new Server();
try
{
//At this point you have an empty model because you just
//created a new Instance of your Server class,
//It is updating the Model with all Null values because they aren't assigned to anything
UpdateModel(server); <----- This is not working
//Here you assign values to your model, hence why they are not null anymore
// Your other values aren't getting saved because they still don't have a value.
server.Name = "testAdd";
server.OS = "2008 R2";
serverRepository.Add(server);
serverRepository.Save();
return RedirectToAction("Details", new { id = server.ServerID });
}
I want to fill textboxes which take data from database. When I select any value using dropdownlist, I need to get ID from dropdownlist and I call a function which fill #Html.EditorFor(model => model.taskName). The page musn't change. How is it possible?
<div class="form-group">
#Html.LabelFor(model => model.jobID, "jobID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("jobID", String.Empty)
#Html.ValidationMessageFor(model => model.jobID)
</div>
</div>
<div> #Html.Partial("../Location/taskname") </div>
</div>
taskname.cshtml
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.taskName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.taskName)
#Html.ValidationMessageFor(model => model.taskName)
</div>
</div>
</div>
Make your dropdown like this:
#Html.DropDownList("jobID", null, new {#id="job"})
and taskname text box :
#Html.EditorFor(model => model.taskName, new {#id="taskname"})
do like this, write jquery event for dropdown index change event, and send ajax call to get Task Name against the job Id selected from the dropdown list:
$('select#job').change(function(){
var JobId =$(this).val();
// Send Ajax call and get Task name
var Url = 'http://example.com/Controller/Action/?jobid='+JobId ;
$.ajax({
url: Url ,
success: function(result) {
$('input#taskname').val(result);
},
error: function(error) {
alert(errorss);
}
});
});