How do I bind to a class that is not in my model in asp.net mvc 2? - asp.net-mvc-2

Normally when I design a form, the data I am expecting is part of the viewmodel for the page, and I can put the class in the controller method and the binding works.
However, I am adding a form in a partial view of a master page, so it is not specific to any one viewmodel. I tried just making sure the ID of the form field would match up with what would have normally automatically been generated, but the object values are always null in my controller method.
Here is a snippet form my the partial view of my master page:
<tr>
<td >Current password:</td>
<td><%= Html.Password("PasswordChange.OriginalPassword", "", new RouteValueDictionary { { "class", "required remote" } })%></td>
</tr>
<tr>
<td >New password:</td>
<td><%= Html.Password("PasswordChange.NewPassword", "", new RouteValueDictionary { { "class", "required remote" } })%></td>
</tr>
As you can see can imagine, PasswordChange is not a part of all of my view models (surely it's not necessary to inherit all of my viewmodels from a common base in order to use this form?).
My controller method looks like this:
[HttpPost]
public ActionResult ChangePassword(PasswordChange PasswordChange)
{
I hit the method, but PasswordChange.OriginalPassword and PasswordChange.NewPassword are always null.
I assume there is some easy way to do this, but I cannot figure it out.

Get rid of the prefixes:
<tr>
<td>Current password:</td>
<td><%= Html.Password("OriginalPassword", "", new RouteValueDictionary { { "class", "required remote" } })%></td>
</tr>
<tr>
<td >New password:</td>
<td><%= Html.Password("NewPassword", "", new RouteValueDictionary { { "class", "required remote" } })%></td>
</tr>
or if you want to keep a prefix, make sure you define this prefix:
[HttpPost]
public ActionResult ChangePassword(
[Bind(Prefix = "PasswordChange")] PasswordChange model
)
{
...
}
By the way you might also consider using child actions instead:
public class PasswordChangeController: Controller
{
[ChildActionOnly]
public ActionResult Index()
{
var model = new PasswordChange();
return PartialView(model);
}
}
and then inside your masterpage instead of rendering a partial, render the child action:
<% Html.RenderAction("Index", "PasswordChange"); %>
and of course now you will have a strongly typed ~/Views/PasswordChange/Index.ascx partial where you could generate your form and use the strongly typed versions of the helpers.
For more information about child actions you may take a look at Phil Haack's blog post on this topic.

My PasswordChange class's member's were not set as public.
#%$#$^#%&%
from
public class PasswordChange
{
public OriginalPassword { get; set; }
public NewPassword { get; set; }
}
to
public class PasswordChange
{
public string OriginalPassword { get; set; }
public string NewPassword { get; set; }
}

Related

How to edit nested collections in MVC5?

I have a EF-model which contains a "key" and a "value". The value-table contains a FK to the key. In the EF-model it looks like this:
public partial class dict_key
{
public dict_key()
{
this.dict_value = new HashSet<dict_value>();
}
public int id { get; set; }
public string name { get; set; }
...
public virtual ICollection<dict_value> dict_value { get; set; } //dict_value contains a string "value"
}
My controller is passing the information for editing like this:
// GET: Keys/Texts/5
[Authorize]
public async Task<ActionResult> Texts(int? id)
{
var key = await db.dict_key
.Include(x => x.dict_value)
.Where(x => x.id.Equals(id.Value))
.FirstOrDefaultAsync();
return View(key);
// Debugging 'key' shows that dict_value has 3 correct values.
}
This gets passed to my View which shows the dict_value's correct:
#model Dict.Models.dict_key
#using (Html.BeginForm())
{
<div>Key: #Model.name </div>
<table class="table">
<tr>
<th>Language</th>
<th>Text</th>
</tr>
#for (var i = 0; i < Model.dict_value.Count(); i++)
{
<tr>
<td> #Model.dict_value.ElementAt(i).dict_lang.name_en </td>
<td> #Html.EditorFor(x => x.dict_value.ElementAt(i).value) </td>
</tr>
}
<div class="form-group">
<input type="submit" value="Save" />
</div>
</table>
}
When submitting my changes back to the controller...
[HttpPost]
public async Task<ActionResult> Texts(dict_key dict_key)
{
if (ModelState.IsValid)
{
//Also tried: db.Entry(dict_key).State = EntityState.Modified;
db.Entry(dict_key.dict_value).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Texts");
}
return View(dict_key);
}
..then my "dict_key" is totally different from the object I passed to my edit-view. The passed object contained the collection of dict_value's and the "returned" and edited object returns with the proper key object, but with an empty dict_value collection.
I try to avoid using a userdefined model or the viewbag to do all of that stuff manually. What is the best practise solution for this?
Collection.ElementAt doesn't generate a proper field name in Razor. You need a List. Here you should use a view model instead of your entity directly and simply make your dict_value collection a List<dict_value> there.
Alternatively, you can create an editor template for dict_value and then in your view just do:
#Html.EditorFor(m => m.dict_value)
Where dict_value there is your entire collection. Razor will render an instance of the editor template for each member of the collection and properly index everything.

how get attribute relation from another entity class Java Persistance API and show to JSP through servlet?

I have 2 entities are entities meeting and meetingAgenda.
I write code entity class (EJB) from database like this.
public class Meeting implements Serializable {
......
#XmlTransient
public Collection<MeetingAgenda> getMeetingAgendaCollection() {
return meetingAgendaCollection;
}
public void setMeetingAgendaCollection(Collection<MeetingAgenda> meetingAgendaCollection) {
this.meetingAgendaCollection = meetingAgendaCollection;
}
.......
}
and entity class meeting agenda like this.
.....
public class MeetingAgenda implements Serializable {
....
public String getAgenda() {
return agenda;
}
public void setAgenda(String agenda) {
this.agenda = agenda;
}
....
}
method getMeetingAgendaCollection is a relation from meeting entity . then, in my controller servlet i call EJB like this.
public class ControllerServlet extends HttpServlet {
#EJB
private RapatFacadeLocal rapatFacade;
public void init() throws ServletException {
// store category list in servlet context
getServletContext().setAttribute("meetings", rapatFacade.findAll());
}
......
i want to show data from table entities meeting and meetingAgenda...but i can't..
please help..
i write code in JSP page.. like this..
<c:forEach var="meeting" items="${meetings}">
<td> MeetingCode : ${meeting.meetingCode} </td>
<td> Meeting : ${meeting.meeting} </td>
<td> Agenda : ${meeting.getMeetingAgendaCollection} </td>
</c:forEach>
how do I display data Agenda using getMeetingAgendaCollection ????
thanks for your help.
I finally found the solution,
in my controller servlet
Rapat selectedMeeting = rapatFacade.find(Long.parseLong(id));
request.setAttribute("meetingDetails",selectedMeeting);
Collection<RapatAgenda> agenda = selectedMeeting.getRapatAgendaCollection();
request.setAttribute("meetingAgendas", agenda);
in my JSP client
....
<c:forEach var="agenda" items="${meetingAgendas}">
<td> ${agenda.agenda} </td>
</c:forEach>
...
but I found the problem further.
if I want to display another entity (one to many) that relate to entities meeting.
i write code like this.
Rapat selectedMeeting = rapatFacade.find(Long.parseLong(id));
request.setAttribute("meetingDetails",selectedMeeting);
Collection<RapatAgenda> agenda = selectedMeeting.getRapatAgendaCollection();
request.setAttribute("meetingAgendas", agenda);
Unit selectUnit = unitFacade.find(selectedMeeting.getUnitInisiatorId());
request.setAttribute("initiator", selectUnit);
i wont selectedMeeting.getUnitInisiatorId() value is integer ,
if i write manually,
Unit selectUnit = unitFacade.find(Long.parseLong(1));
request.setAttribute("initiator", selectUnit);
problem solved..
what selectedMeeting.getUnitInisiatorId() syntax is correct ..?
please help.. thank you..

Binding List of KeyValuePair to checkboxes

I am using ASP.Net MVC with C#. I have a model which has a member for filter criteria. This member is a IList>. The key contains value to display and the value tells if this filter is selected or not. I want to bind this to bunch of checkboxes on my view. This is how I did it.
<% for(int i=0;i<Model.customers.filterCriteria.Count;i++) { %>
<%=Html.CheckBoxFor(Model.customers.filterCriteria[i].value)%>
<%=Model.customers.filterCriteria[i].key%>
<% } %>
This displays all checkboxes properly. But when I submit my form, in controller, I get null for filtercriteria no matter what I select on view.
From this post I got a hint for creating separate property. But how will this work for IList..? Any suggestions please?
The problem with the KeyValuePair<TKey, TValue> structure is that it has private setters meaning that the default model binder cannot set their values in the POST action. It has a special constructor that need to be used allowing to pass the key and the value but of course the default model binder has no knowledge of this constructor and it uses the default one, so unless you write a custom model binder for this type you won't be able to use it.
I would recommend you using a custom type instead of KeyValuePair<TKey, TValue>.
So as always we start with a view model:
public class Item
{
public string Name { get; set; }
public bool Value { get; set; }
}
public class MyViewModel
{
public IList<Item> FilterCriteria { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel
{
FilterCriteria = new[]
{
new Item { Name = "Criteria 1", Value = true },
new Item { Name = "Criteria 2", Value = false },
new Item { Name = "Criteria 3", Value = true },
}
});
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// The model will be correctly bound here
return View(model);
}
}
and the corresponding ~/Views/Home/Index.aspx view:
<% using (Html.BeginForm()) { %>
<%= Html.EditorFor(x => x.FilterCriteria) %>
<input type="submit" value="OK" />
<% } %>
and finally we write a customized editor template for the Item type in ~/Views/Shared/EditorTemplates/Item.ascx or ~/Views/Home/EditorTemplates/Item.ascx (if this template is only specific to the Home controller and not reused):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.Item>"
%>
<%= Html.CheckBoxFor(x => x.Value) %>
<%= Html.HiddenFor(x => x.Name) %>
<%= Html.Encode(Model.Name) %>
We have achieved two things: cleaned up the views from ugly for loops and made the model binder successfully bind the checkbox values in the POST action.

Data is empty in Post method asp.net mvc 2

I`m trying to display classes that have properties of type some custom class inside it.
Model:
public class ComplexParent
{
public SimpleChild First { get; set; }
public SimpleChild Second { get; set; }
}
public class SimpleChild
{
public int Id { get; set; }
public string ChildName { get; set; }
public string ChildDescription { get; set; }
}
Controller:
public ActionResult Testify(int id)
{
ComplexParent par = new ComplexParent();
par.First = new SimpleChild() { Id = id };
par.Second = new SimpleChild()
{
Id = id + 1,
ChildName = "Bob",
ChildDescription = "Second"
};
return View("Testify", par);
}
[HttpPost]
public ActionResult Testify(ComplexParent pComplexParent)
{
return View("Testify", pComplexParent);
}
View:
<% using (Html.BeginForm())
{%>
<fieldset>
<legend>Fields</legend>
<%: Html.EditorFor(x => x.First) %>
<br />
<%: Html.EditorFor(x => x.Second.ChildName)%>
<br/>
<br/>
<br/>
<% Html.RenderPartial("SimpleChild", Model.First); %>
<p>
<input type="submit" value="Watch me :-)" />
</p>
</fieldset>
<% } %>
When it comes to Get it works just fine, I can see all the data. But on post pComplexParent parameter is empty (both properties of a complex class are nulls). Probably Im missing something here, but could not get this to work ...
Small addition: view part that only shows editor for name makes Second child not null and name is set to Bob. But I dont understand how to make it just with EditorFor or DisplayFor methods.
UPDATE: Thanks to Darin Dimitrov, who kindly went throught all my code and found what caused this problem. The exact problem was that if you are using display template, asp.net mvc 2 doesnt post any values back and if whole template is has nothing to post back object is null. I still thinking of the way how to get the data, even if you don`t want to edit it. But using editor template does the thing and I have all objects filled with proper data now.
Your view is a bit of a mess. You are using editor templates along with partials for the first child. It is not very clear what fields are included inside the form. I would recommend you using only editor templates:
Model:
public class ComplexParent
{
public SimpleChild First { get; set; }
public SimpleChild Second { get; set; }
}
public class SimpleChild
{
public int Id { get; set; }
public string ChildName { get; set; }
public string ChildDescription { get; set; }
}
Controller:
[HandleError]
public class HomeController : Controller
{
public ActionResult Testify(int id)
{
var par = new ComplexParent();
par.First = new SimpleChild() { Id = id };
par.Second = new SimpleChild()
{
Id = id + 1,
ChildName = "Bob",
ChildDescription = "Second"
};
return View(par);
}
[HttpPost]
public ActionResult Testify(ComplexParent pComplexParent)
{
return View(pComplexParent);
}
}
View:
<% using (Html.BeginForm()) { %>
<%: Html.EditorFor(x => x.First) %>
<%: Html.EditorFor(x => x.Second) %>
<input type="submit" value="Watch me :-)" />
<% } %>
Editor template for SimpleChild (~/Views/Home/EditorTemplates/SimpleChild.ascx):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeNs.Models.SimpleChild>" %>
<%: Html.HiddenFor(x => x.Id) %>
<%: Html.EditorFor(x => x.ChildName) %>
<%: Html.EditorFor(x => x.ChildDescription) %>
Now if you want to have different editor templates for the two child properties you could either specify the editor template name when including it:
<%: Html.EditorFor(x => x.First, "FirstChildEditor") %>
which corresponds to ~/Views/Home/EditorTemplates/FirstChildEditor.ascx or use an [UIHint] attribute at your model:
public class ComplexParent
{
[UIHint("FirstChildEditor")]
public SimpleChild First { get; set; }
public SimpleChild Second { get; set; }
}
My recommendation is not to use Html.RenderPartial for generating input fields because their names will be hardcoded and won't bind properly depending on your objects hierarchy.

Html.EditorFor does not render anything if I use a custom object?

It seems like it's not possible to edit custom object anymore after I upgraded to asp.net mvc 2 rc 2? I use this approach http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html with a custom object like this:
My model has just one property but inherits from an abstract base class
public class Page : ContentItem {
[DataType(DataType.MultilineText)]
public virtual string MainIntro { get;set; } // This property render correct
[DisplayFormat(NullDisplayText="(null value)")]
public virtual DetailCollection Tags { get; set; }
}
My controller looks like this
public ActionResult Edit(string pagePath) {
var page = _repository.GetByUrlSegment(pagePath);
return View(page.EditViewName, new DashboardModel(page, RootPages));
}
And my view looks like this
<% using (Html.BeginForm("update","Dashboard", FormMethod.Post, new { name = "editForm" } )) %>
<% { %>
<div>
<%=Html.EditorFor(model => model.CurrentItem) %>
<div class="editor-button">
<input type="submit" value="Save" />
</div>
</div>
<% } %>
Perhaps it would be better to expose this to the view as a space-separated string and exclude the collection from being displayed in the view. Alternatively, you might be able to define a specific template for how you want to display a collection. It's not clear to me how MVC would be able to determine what to display otherwise.
Try something like:
[ShowForDisplay(false)]
[ShowForEdit(false)]
public virtual DetailCollection Tags { get; set; }
public virtual string TagList
{
get
{
if (tags == null) return "(null value)";
// assumes DetailCollection implements IEnumerable<string>
return string.Join( " ", tags.Select( t => t).ToArray() );
}
set
{
tags = new DetailCollection( value.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries )
.Select( s => s.Trim() ) );
}
}