Html Partial MVC passing a Model - asp.net-mvc

I am trying to pass this Model in the Partial Method
#Html.Partial("_RefillModal",new Refill()
{
PatientId=Model.Id
})
Now in the _RefillModal, I am trying to Read the PatientId by doing Model.PatientId. However, I am not getting a Value.
I can get the Value of the ID by doing this
#Html.Partial("_RefillModal",new Refill(),new ViewDataDictionary(){{"PatientId",Model.Id}})
Here is what I am trying to do in the Partial View
#Html.Hidden("Refill.PatientId",Model.PatientId)
Here is the Html Markup that happens
<input id="PatientId" name="PatientId" type="hidden" value="">
However when I do #Modal.PatientId anywhere on the page I do get the Value
So it looks like, if I put anything inside the Form it gets Overriden. Is there a work around?
#using (Html.BeginForm())
{
//any custom input here gets overriden
}

It's hard to see where the issue is since you didn't post your Partial View but I'll offer a few suggestions. Make sure that you've declared the actual Model to be of type Refill in your _RefillModal.
#model Refill
The next step is to make sure that you're actually passing in a value in this line of code:
#Html.Partial("_RefillModal", new Refill()
{
/** Make sure that Model.Id actually
contains some value. */
PatientId = Model.Id
})

Related

How does #Html.BeginForm() works?

I'm very new to ASP.NET, just started the MVC tutorial today on asp.net. I got here http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-methods-and-edit-view
So far so good, the problem:
In my View I have the following code
(Model is set to the view with #model MyFirstMVC4.Models.Movie)
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
#Html.HiddenFor(model => model.ID)
//... bla bla html input
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
My MovieController
// Shows the view
public ActionResult Edit(int id = 0)
{
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
//
// POST: /Movie/Edit/5
[HttpPost] // Handles the view above
public ActionResult Edit(Movie movie)
{
if (ModelState.IsValid)
{
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
And here is the question - How the heck does it pass the Movie object to the POST method above?! When I observe the client side there is
<form action = "/Movie/Edit/1" ... />
Here I don't understand why action = url of the very same view page?!1
Also on the server side there is just Html.BeginForm() :(
How does it realize to what action method to post and what route parameters to pass?
It works, I just don't know why
The version of BeginForm in the code,
with no parameters, sends an HTTP POST to the current URL, so if the view is a response to
/Movie/Edit/5, the opening form tag will look like the following:
< form action="/Movie/Edit/5" method="post">
The BeginForm HTML helper asks the routing engine how to reach the Edit action of the
MovieController. Behind the scenes it uses the method named GetVirtualPath on the Routes
property exposed by RouteTable — that’s where your web application registered all its routes in
global.asax. If you did all this without an HTML helper, you’d have to write all the following
code:
#{
var context = this.ViewContext.RequestContext;
var values = new RouteValueDictionary{
{ "controller", "movie" }, { "action", "edit" }
};
var path = RouteTable.Routes.GetVirtualPath(context, values);
}
<form action="#path.VirtualPath" method="get">
...
</form>
You asked how is movie object is passed. That is called model binding.
When you have an action with a parameter, the MVC runtime uses a model binder to build the
parameter. You can have multiple model binders registered in the MVC runtime for different types
of models, but the workhorse by default will be the DefaultModelBinder.
In the case of an Movie
object, the default model binder inspects the Movie and finds all the movie properties available
for binding. Following the naming convention you examined earlier, the default model binder can automatically convert and move values from the request into an movie object (the model binder can
also create an instance of the object to populate).
In other words, when the model binder sees an Movie has a Title property, it looks for a value
named “Title” in the request. Notice the model binder looks “in the request” and not “in the form
collection.” The model binder uses components known as value providers to search for values in
different areas of a request.
The model binder can look at route data, the query string, and the form
collection, and you can add custom value providers if you so desire.
When you call BeginForm() without any parameters it default to using the same controller/action used to render the current page. It assumes you'll have an action with the correct name on your controller that will accept postbacks (which you do). It uses the RouteValues to do this.
It automatically binds each input control (by name) to the parameters of the action accepting the postback - or in your case, the properties of the object parameter for the action accepting the postback.
[HttpPost] attribute is given to the action that you want to be called on the POST submit of the form.
to understand how #using (Html.BeginForm()) works , you need to know what page it is already on . using #using (Html.BeginForm()) in 2 different views will come back to two different controllers
We can create forms by typing simple html or by html helpers.
One of them Html.BeginForm(); it is a little bit odd because you actually can wrap it in a using statement because this particular helper returns an object that implements IDisposable in C#. First it writes out with opening tag. And at the bottom when the generated code calls dispose on that object, that’s when it will write out closing form tag . So BeginForm gives me an object that will write out my opening form tag and my closing from tag. After that you don't worry about anything you can just focus on labels and inputs

Model with List - approaches to add new item to the list from a Razor view

I have a model with various properties but the one of interest is a List of another type of Model.
For example:
public class User
{
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<UserInterest> Interests { get; set; }
}
I then use an Editor Template within my view to render out a view for each item of the model items.
#Html.EditorFor(x => x.Interests)
The EditorFor template looks something like:
#model Interest
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.InterestText)
#Html.CheckBoxFor(x => x.Delete)
....
</div>
Something very similar to the accepted answer here: Model Containing List of Models (MVC-3, Razor)
My question is - how would you from the client-side (jQuery) create a new item within the property without going back to the server. I currently have a rough way of doing it whereby I post the data back to my controller which returns the model back with a new blank item within the Interests property.
This seems to be overkill making a HTTP request and not very elegent. I was thinking of using jQuery .Clone() but not entirely sure on what I'd need to do in terms of naming the elements and clearing existing values.
So does anybody have any suggestions. I'm hoping to get more opinions and different approaches.
You can simply create the Textbox and checkbox on the fly and add that to the DOM. When saving it, Use jQuery ajax to post that data ( new record data) to an action method and save it there. Return a status back (Succcess /Falied) from your action method to your client side code ( your callback function of jQuery ajax/post) and check it there. If it is success, Show a success message to the user and append the new item to the existing list.
Sample jSFiddle : http://jsfiddle.net/carwB/2/
If you want to return some complex data ( ex : All new records with its id etc..) along with the status, you may return JSON from your action method.
EDIT : To keep your Model binding works with the newly added dynamic elements, you need to follow the naming convention of the elements.
The trick is to keep the id property value of the html element in this format.
CollectionName_ItemIndex__PropertyName
and name property value in this format
CollectionName[ItemIndex].PropertyName
I created a sample working program and explained it how it works Here based on your requirements.
In such situations I prefer to use client templating. You send data to server with ajax and then receive JsonResult. Look at JsRender this is javascript lib without jQuery dependency.
1.Create two partial view one is for list item and second one is creation
2.First partail view should be inside the div which has id 'divMdeolList'
3.and Creation view will have the code like that
#using (Ajax.BeginForm("SubmitData", new AjaxOptions { UpdateTargetId = "divMdeolList" }))
{
#Html.TextBoxFor(x => x.InterestText)
<p>
<input type="submit" value="Create" />
</p>
}
4. And then create a ActionResult type action on controller that will render the partialview
public ActionResult SubmitData(YourModel model)
{
//Do : save the record
return PartialView("FirstPartailView", model);
}
This will update the View without postback

hidden form element problem - asp.net mvc

I create a strongly typed form like this in my controller:
return View("BlaForm", Bla);
In the view I use something like this:
(1)
<%= Model.Version %>
(2)
<%= Html.Hidden("Version", Model.Version)%>
Here (1) is just for debugging purposes.
After a successive update of my object this produces something like this:
(1)
10
(2)
<input id="Version" name="Version" type="hidden" value="9" />
The hidden value is out of synch for some strange reason ???!!! The Version value was definitely 10 in this case as established by the debugger. Why is this? Are hidden value somehow cached?
Thanks.
Christian
PS:
I also do:
if (TempData["ViewData"] != null)
{
ViewData = TempData["ViewData"] as ViewDataDictionary;
}
in the controller action to maintain form values in case validation errors happen. This seems to be the reason. But still I explicitely do: <%= Html.Hidden("Version", Model.Version)%> .... ???? Maybe I missunderstand the lif cycle a bit?
Html helper will always use the value in the GET or POST request before the value in your model or ViewData. This means that if you post Version=9 to a controller action and inside this action you try to modify its value to 10, when you return the View, the Html.Hidden helper will use the POSTed value and not the one in your Model. The only workaround is a custom HTML helper or simply:
<input id="Version" name="Version" type="hidden" value="<%= Model.Version %>" />
HTML helper will always look for values in ModelStateDictionary, then in ViewData and after this use the value parameter given into helper method.
The 2 other places are in your case.
ModelState state = this.ViewData.ModelState["Version"];
state.Value; // this is the value out of the ModelStateDictionary
object value = this.ViewData["Version"]; // this is the value if set
// out of the ViewData Collection
The ModelStateDictionary gets its entries, while model binding. If you have the Version as a action method parameter, the Modelbinder (in your case the DefaultModelBinder) will enter the key version with the supplied value of get or post request.
If you change the value, put it in your model, you have to update the ModelStateDictionary too.

ASP.NET MVC Filtering results in a list/grid

For some reason I'm stuck on this. I need to filter results from a View based on a DropDownList in the same view. The basic idea is this: I have a list of providers that belong to various partners, but the provider list contains ALL the providers together (for all partners). I need to be able to display the providers by partner when someone wants to see just that partner (otherwise, the default listing will be ALL providers). My view currently is the "default" (showing all), but for some reason Im sitting here staring at the monitor (for the last 2 hours!) trying to figure out how to filter these results.
Any suggestions where to start/how to do it?!
EDIT: If you want to do this with jQuery and AJAX (which will provide a better user experience because only the subdivisions list will refresh), see this tutorial.
If I understand correctly, you basically want to do a WebForms-style postback.
Let's say you have a control with countries and country subdivisions (e.g. states, provinces, etc). When the country changes, you want the appropriate subdivisions to display.
So this would be view:
<% using (Html.BeginForm()) { %>
<%=Html.DropDownList("Address.CountryId", new SelectList(Country.GetAll(), "Id", "Name"), new { onchange = "this.form.submit();" })%>
<%=Html.DropDownList("Address.CountrySubdivisionId", new SelectList(CountrySubDivision.GetByCountryId(Model.CountryId), "Id", "Name"))%>
<input type="submit" name="btnSubmit" value="Submit"/>
<%} %>
This is the key to getting the dependent list to filter:
new { onchange = "this.form.submit();" }
And in the controller, you'd have something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Index(string btnSubmit)
{
if (btnSubmit == null)
{
// return the view displayed upon GET
}
else
{
// process the submitted data
}
}
In the above code, if the form submission was triggered by changing the value in a dropdown, btnSubmit will be null. Thus, the action you are POSTing to can tell whether or not the user meant to finalize her changes.
To add upon the earlier answers.
To create a drop down (in ASP .NET MVC 3) I did the following:
Add code to Index.cshtml
#using (Html.BeginForm())
{
#Html.DropDownList("EmployeeId", (SelectList)ViewData["EmployeeId"])
<input type="submit" name="btnSubmit" value="Submit"/>
}
Add code to YourModelNameController.cs in the default ActionResult for Index()
public ActionResult Index()
{
//create a selectlist
var employeeList = from el in db.Employee select el;
ViewData["EmployeeId"] = new SelectList(employeeList, "EmployeeId", "TmName");
return View(modelName);
}
There are many ways to skin this cat. Here's one.
Enclose your DropDownList in a form with METHOD=GET.
<form action="" method="get">
<select name="provider">
<option>1</option>
<!-- etc -->
</select>
</form>
Then, in you controller, filter based on the value of provider that was passed in. Remember to treat it as a Nullable parameter so that you can have some kind of behavior when it's empty.
Without posting some of your current code, it's tough to get much more specific than that.
Let's assume that you're probably passing a model to the view and that model is a list or IEnummerable of partners. What you want to do is restrict the list. In order to do that add a drop down list in the view and fill it with some possible partners. This can be done either by putting a list in ViewData or expanding the model passed back to the view. Both have advantages. Now when you change the drop down reload the page but append a parameter which is the filter. In the controller check for that parameter in the action, if it isn't present then return an unfiltered list, if it is then apply a filter and return the list. The view will just dumbly display whatever you give it.
As for the filtering you might want to try using LINQ.
You probably want a parameter to your controller action, maybe a (nullable?) id of the provider, to filter the results already when you get them from DB. Then just use the same view to list them, and request a new list if the dropdownlist changes.
Best solution I know is that one.
http://gridmvc.codeplex.com/SourceControl/latest

Disabled Form Elements ASP.NET MVC Update

I'm wanting to update a record in my database which has two values, one is the ID, and one is the "description". The ID can never be changed, however I'm relying on the use of strongly-typed features to do it. So, I have the following:
Inherits="System.Web.Mvc.ViewPage<Business>"
Which is fine as it allows me to get everything back. The problem is when I use the following line:
<%= Html.TextBox("BusinessID", ViewData.Model.BusinessID, new { disabled = "disabled", style = "width:50px;", #class = "uppercase", maxlength = "4" })%>
With the disabled = "disabled" option it doesn't recognise the BusinessID and therefore doesn't pass it back to the controller which, in turn has problems binding the object up.
Not that you'll need it, but here's the controller action:
[HttpPost]
public ActionResult EditBusiness(Business business)
{
if (!ModelState.IsValid)
return View(business);
// update business here
_contractsControlRepository.UpdateBusiness(business);
return RedirectToAction("Businesses");
}
Any ideas why this is happening? I didn't realise form elements were completely hidden on postback when they're disabled. I don't want the users editing that particular field. I've also tried Html.DisplayFor(b=>b.BusinessID) without any luck.
display the id like this
Html.Hidden("BusinessID", ViewData.Model.BusinessID)
<%=Model.BussinessID %>
this way you will have the id for the binding in the hidden tag
and you will display the value in the label
or you can use anything else that you want yo can do like this also
<input type="text" value="<%=Model.BussinessID %>" contentEditable="false">
and put the hidden somewhere in the form
instead of Html.Textbox you can use Html.Hidden("BusinessID", ViewData.Model.BusinessID)
You always have the option of either "hard-coding" the html element, or writing your own html helper method to do it.
public static string DisabledTextBox(this HtmlHelper helper, string name, object value)
{
return String.Format(#"<input type="text" name="{0}" id="{0}" disabled="disabled" value="{1}" />", name, value);
}
Is there a particular reason you are displaying the id? if not then leave it out and on your controller simply use TryUpdateModel() instead.
or is that not what your asking?
edit
<%= Html.TextBox("name","value", null, new { style="readonly"}) %>
Edit 2
You might think about doing a route like //site/controller/yourbusinessid
then you can use the id as it's passed to your controller and you can then, in your view, simply use <%= Model.BusinessId %> as a string.

Resources