How can I access a strongly typed partial view model from the parent view model? - asp.net-mvc-4

I have a strongly typed partial view that consists of one form field. I would like to add this partial view into all of the existing forms on a website(around 25 forms). I am having trouble figuring out how to reference the model information from the existing form controllers. I am adding the partial view like so. #{Html.RenderPartial("_HoneyPotFormField");} what I am looking to do is something to the effect of if HoneyPotFormFieldModel.Comments is null do something.
Here is my View code.
#model Web.Models.HoneyPotFormFieldModel
<div class="form-comments">
<div class="title">
<span>Comments</span>
</div>
<div class="col-md-10">
#Html.EditorFor(model => model.Comments)
</div>
</div>
here is my Model code
public class HoneyPotFormFieldModel
{
public string Comments { get; set; }
}

Related

sitefinity update view from action method

I am using this form to post data to the controller once the data is saved I wanted to display this Success view but I am getting a 404 page not found. Any idea why I am getting this error?
View
#using (Html.BeginFormSitefinity("Save", "Preference", FormMethod.Post, new { id = "preferencesForm" }))
{
<div class="row">
<div class="text-center">
<button type="submit" class="btn btn-primary px-4 float-center">Save</button>
</div>
</div>
controller
public ActionResult Save(PreferenceViewModel model)
{
SaveData(model);
return View("~/Mvc/Views/Preference/Success.cshtml");
}
Does your code hit the Save method? I don't see it marked with the [HttpPost] attribute.
Also, if this is your Preference widget, then you can simply use this:
return View("Success");
Sitefinity will look for success.cshtml in the correct folder.

ASP.NET Core - Data values not bound when trying to use a partial view to lay out form controls

I'm trying to create a partial view to save on the amount of boilerplate code I need when creating forms. A simple version of what I have is as follows...
#model FormRowViewModel
<div class="form-group row">
<label for="#Model.PropertyName" class="col-lg-2 col-form-label">#Model.Label</label>
<div class="col-lg-10 input-group">
<input type="text" asp-for="#Model.PropertyName" class="form-control">
</div>
</div>
...where FormRowViewModel looks like this...
public class FormRowViewModel {
public FormRowViewModel(string propertyName, string label) {
PropertyName = propertyName;
Label = label;
}
public string PropertyName { get; set; }
public string Label { get; set; }
}
The idea is to use it in a view like this...
#model ContactViewModel
<form method="post" asp-controller="Home" asp-action="Index">
<div asp-validation-summary="All" class="text-danger"></div>
#await Html.PartialAsync("_FormRow", new FormRowViewModel("UserName", "Your name"))
#await Html.PartialAsync("_FormRow", new FormRowViewModel("Email", "Email"))
#await Html.PartialAsync("_FormRow", new FormRowViewModel("Telephone", "Telephone"))
<div class="form-group row">
<div class="offset-sm-2 col-lg-10">
<button type="submit" class="btn btn-primarySubmit</button>
</div>
</div>
</form>
This works, in that it creates the HTML (almost) as expected, but has two problems...
1) The generated HTML includes value attributes that set the content of the textboxes to the property names...
<input type="text" class="form-control" id="PropertyName"
name="PropertyName" value="UserName">
2) Whatever I put in the textboxes, when the form is posted back to the server, the view model properties are all empty strings. Even the property names that were added don't come through.
In case it helps, here is the controller action that handles the view...
public IActionResult Index() =>
View();
[HttpPost]
public IActionResult Index(ContactViewModel vm) {
if (!ModelState.IsValid) {
return View(vm);
}
// Next line added so I can see when it worked
return RedirectToAction(nameof(Privacy));
}
Anyone know what I'm doing wrong? Thanks
Your whole approach here is incorrect. It seems what you're looking for is editor templates. Essentially, you need to create partial views in Views\Shared\EditorTemplates that correspond with types or members of the DataType enum, and add your custom HTML there. For example, you can create a String.cshtml view:
#model string
<div class="form-group row">
<label asp-for="#Model" class="col-lg-2 col-form-label"></label>
<div class="col-lg-10 input-group">
<input asp-for="#Model" class="form-control">
</div>
</div>
Then, for any string property:
#Html.EditorFor(x => x.MyStringProp)
And your custom template will be used, with the proper name binding.
Alternatively, you can create custom taghelpers, but the methodology for that is a bit more complicated, since you'll need to handle the HTML generation in code. If you're interested in that approach, though, look at the source for the built-in tag helpers and create your own based on that.

MVC 4 Model not returned to controller

I have three cascading dropdowns using Ajax to populate themselves on a view. Also in the view I call a partial view that iterates a container in the model and for each item calls another partial to display for editing the model properties appropriate according to the selected items in the dropdowns. I have built a complex model that contains the dropdown choices as well as the properties to be edited, and pass the portion of the model to the lowest level partial necessary to display the properties to be edited.
I want to update the db when the user clicks the submit button, through a normal Html.BeginForm, not by using Ajax. So I must wrap only the partials that display the properties in the form so that the existing Ajax functionality does not post to the controller. The problem is that although I can build this all, and the submit button connects to the controller as expected, the model returns to the controller null.
Does the model not come back from the partials up through the path that built them? Or more correctly stated, does the model not persist on the page even if it is built using partials?
I am sure someone is going to suggest that I post back using Ajax but that is not a best option for me. Or someone might ask what the html looks like on the page. Oddly, I can only see the complete html using browser developer tools, it does not show in a View Source selection.
Any ideas?
Moving this to where it belongs:
I'm not certain I understand. I get that the returning model needs to match the expected model but I don't get the explanation above. You say "So if your controller looks like this:", and of course it does, then what? That's wrong?
I have to look in dev tools for Chrome to see the actual html output and I see this in one case:
<input class="text-box single-line" id="status_Comments" name="status.Comments" type="text" value="Last Install to be completed this weekend">
So if the 'name' tag needs to look proper, I think it does. Am I wrong?
My date fields look like this:
<input type="text" value="8/19/2014" class="datepicker hasDatepicker" id="dp1391795955619">
So there's no 'name' tag but does have an id. Do I need to add a name?
Here's the code that generates the above:
#foreach (Status status in Model) {
string date = status.Date.HasValue ? status.Date.Value.ToShortDateString() : string.Empty;
<tr>
<td style="width: 175px;">#Html.DisplayFor(model => status.Name)</td>
<td style="width: 75px;">#Html.DisplayDropdownColorFor(model => status.StatusValue)</td>
<td style="width: 80px;"><input type="text" value="#date" class="datepicker" /></td>
<td style="width: 80px;"><input type="text" value="" class="datepicker" /></td>
<td style="width: 375px;">#Html.EditorFor(model => status.Comments)</td>
</tr>
}`
Geez, I sound like a desperate moron.
Thanks for your help.
Let's say you had a couple of classes like this:
public class SomeClass1
{
public string Name { get; set; }
public SomeClass2 class2Value { get; set; }
}
public class SomeClass2
{
public string Description { get; set; }
}
And you have a form in a Razor view:
#model SomeClass1
#using (Html.BeginForm()) {
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.class2Value.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.class2Value.Description)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
The actual HTML code is going to look something like this:
<form id="form1" action="/pageurl" method="POST">
<fieldset>
<div class="editor-label">
Name
</div>
<div class="editor-field">
<input type="text" name="Name" id="Name" value="Name val 1" />
</div>
<div class="editor-label">
Description
</div>
<div class="editor-field">
#Html.EditorFor(model => model.class2Value.Description)
<input type="text" name="class2Value.Description" id="class2Value_Description" value="Desc val 2" />
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
If you notice, the name attribute of the form fields are set by MVC to follow the model. In the case of the nested object, it uses the underscore in the ID and period in the name to keep track of the where in the post model the values should go.
So if your controller looks like this:
[HttpPost]
protected ActionResult Save(SomeClass1 model)
{
//Then
// SomeClass1.Name == "Name val 1"
// and
// SomeClass1.class2Value.Description == "Desc val 2"
}
That's what #David was getting at in the comments... No matter how complex your page, when the <form> posts back to the server, the name attributes of the fields you are returning have to line up with the model that the controller action is expecting... or you will get null values.
You can even create a custom class for the post model, and as long as the name attributes line up with the model, and even though it was not the same as the #model at the top of the Razor view, MVC will use the key/value pairs and populate the data in your post model.
UPDATE
I updated the above to reflect a correction. The underscore is the delimiter in the ID attribute, and the period is used in the NAME attribute.
#leemid: An HTML form only posts fields with a name attribute. Only the name'ed inputs, selects, textareas, etc. will be passed back to the server when the form is submitted. And those names have to be inline with the model that is expected by the controller. For the sake of sounding redundant, that date input field you showed the example for, does not have a name attibute, and if the name were the same as the id, there would have to be a property in your model like
public string dp1391795955619 { get; set; }
for it to show up in your in controller action. You can set the name manually, as long as it's named the way MVC is expecting so that it can pass it into the model when posting.
In my example, the parts I was trying to highlight was the relationship between the class and property names, versus the name attributes MVC writes to the HTML document, and how it keeps all that stuff straight. In simple examples, you don't have to think about it. But in your complex scenario, it looks like you're going to have to manage some of the naming conventions manually so that MVC can understand what you're trying to do.

updating object using NHibernate in Asp.net MVC4

I have problem in updating object with nhibernate in ASP.Net MVC4
Im doing the update in this scenario:
the application loads an object in the first session
the object is passed up to the UI tier
some modifications are made to the object
the object is passed back down to the business logic tier
the application persists these modifications by calling SaveOrUpdate()
all this happen only in one session. I have static a class name NHibernateSessionPerRequest
and its constructor is static (singeleton)
[HttpPost]
public ActionResult Edit(Menu menu)
{
if (ModelState.IsValid)
{
repository.SaveOrUpdate(menu);
TempData["message"] = string.Format("{0} has been saved", menu.Name);
return RedirectToAction("Index");
}
else
{
// there is something wrong with the data values
return View(menu);
}
}
but menu ID is zero. and doesnt have its original ID (id is type of GUID). and SaveOrUpdate() alway treat it as a new object and save it not update it.
here is Edit.cshtml:
#model MyApp.Domain.Entities.MenuComponent
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h2>Edit #Model.Name
</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>MenuComponent</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
how can I update the object?
From your comments, I see two problems :
it seems you have removed #Html.HiddenFor(model => model.ID) from your markup. You should put it back, or your ID won't be stored in the page to be posted back to your Controller.
Your ID code is public virtual Guid ID { get; private set; } You should remove the private modifier on the setter. I guess it prevents the ModelBinder to set the property when receiving the posted data
from what you have posted it seems that you are returning the entity to the view and there isn't any concept of view model being used.
Firstly
usually entities are defined with private setters which would prevent the id being posted back to the Edit action if you use the entity itself.
Secondly (i am not certain about this)
since you are getting the object in the post back and using a session per request (assumption since it is quite common) nhibernate might treat it as a new entity. I am highly doubtful for the second point but will try re creating this and update the answer

HttpPost method of PartialView in ASP.NET MVC 4

I have a view that contain two partial views. One of them for creating, and the other is list of created(companies). My problem is that, when I try create HttpPost method does not work and calls only Index method again. Please help me to fix this problem.
This is my Index view
#model InvoiceModel.HelperClasses.CompanyViewModel
#{
ViewBag.Title = "Companies";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="companies">
<div id="create">#Html.Partial("CreateCompany", Model.Create)</div>
<div id="list">#Html.Partial("CompanyTable", Model.Companies)</div>
</div>
Use #Html.BeginForm() to define your Model that you are creating so when you post it is all mapped up properly.
#using (Html.BeginForm("(Action)", "(Controller)", FormMethod.Post, null))
{
(Your model here)
<input type="submit" value="Save" />
}
<div id="list">#Html.Partial("CompanyTable", Model.Companies)</div>