I created a drop down list in a partial view and I am trying to render that on my aspx page. I am getting an error:
{"Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'."}
This is my aspx page where I am using the ascx control:
<td>
<% Html.RenderAction("getFilterdData");%>
</td>
My ascx control looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<assist>>" %>
<%=Html.DropDownList("Assists", (SelectList)ViewData["Assists"], "--Select One--")%>
and my controller code is like this:
public ActionResult getFilterdData()
{
scorerep sc = new scorerep();
ViewData["Assists"] = new SelectList(sc.FilterData(), "assist_a","");
return View();
}
Why am I getting this error and how can I fix it?
It is difficult to help without seeing the entire exception stacktrace. Here are a few tips:
Make sure that your partial Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<assist>>" and not Inherits="System.Web.Mvc.ViewPage<IEnumerable<assist>>". You are using an ASCX partial and inheriting from System.Web.Mvc.ViewPage which is wrong.
Make sure that your partial view is called exactly the same as the controller action: getFilterdData.ascx (I see a typo here)
Make sure that the Assist class contains a property called assist_a as that's what you are using when rendering the dropdown
Make sure there is no exception being thrown inside the getFilterdData controller action while you are fetching the data.
Here's a working example:
Model:
public class Assist
{
public string Id { get; set; }
public string Value { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult GetFilteredData()
{
// TODO: replace with your repository logic
ViewData["Assists"] = new SelectList(new[] {
new Assist { Id = "1", Value = "Assist 1" },
new Assist { Id = "2", Value = "Assist 2" },
new Assist { Id = "3", Value = "Assist 3" },
}, "Id", "Value");
return View();
}
}
View (~/Views/Home/Index.aspx):
<% Html.RenderAction("GetFilteredData"); %>
Partial: (~/Views/Home/GetFilteredData.ascx):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Assist>>" %>
<%= Html.DropDownList("Assists", (SelectList)ViewData["Assists"], "--Select One--") %>
Related
I develop a web application using ASP.NET MVC4 in VS2012, in that a HomeController as Views/Home/Index.aspx.
I created a user control as UC/UC_Menu.ascx in Views Folder.
In Index.aspx page, I coded in below and run ok.
<% Html.RenderPartial("~/Views/UC/UC_Menu.ascx"); %>
Now, I want to UC/UC_Menu.ascx load data in database. How could I do?
In ASP.NET MVC, views and partials are not supposed to be retrieving any data. They are designed for displaying data that has been retrieved by the corresponding controller under the form of a view model.
So basically you should create a view model that will be a projection of your data. For example:
public class MyViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and then have your controller action fetch the data from the database and project it to the view model:
public class HomeController: Controller
{
public ActionResult Index()
{
MyViewModel model = ... go fetch from db
return View(model);
}
}
and now your Index.aspx view will be strongly typed to this view model and pass the model to your partial view:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyNs.MyViewModel>" %>
and then pass the model to the partial for displaying:
<% Html.RenderPartial("~/Views/UC/UC_Menu.ascx", Model); %>
and your partial can now display the data:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyNs.MyViewModel>" %>
<%= Html.DisplayFor(x => x.Foo) %>
<%= Html.DisplayFor(x => x.Bar) %>
Invoking "Child Actions" gives you encapsulation similar to "UserControls".
Note: "UserControls" is a term used in ASP.NET Web Forms. In MVC, you would call it a "PartialView".
You could create a child action on your controller, for example:
public class HomeController : Controller
{
[ChildActionOnly]
public ActionResult Menu()
{
var model = BuildModelFromDB();
return PartialView(model);
}
}
Then invoke it in your view, passing in the ActionName and ControllerName:
<%= Html.Action("Menu", "Home") %>
ViewData.Model
i know that Viewdata contains the data that has been returned by view via
return view(//data);
but what does this .Model represents ?
Controller:
using Testing_linq.Models;
namespace Testing_linq.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
var DataContext = new RegistrationDataContext();
var Registration = DataContext.SelectRegistration_sp();
return View(Registration);
}
View:
<table>
#foreach(SelectRegistration_spResult reg in (IEnumerable<Object>)ViewData.Model)
{
<tr>
<td>#reg.userEmail </td>
</tr>
}
</table>
I'm using LInq to Sql classes in model.
The Model represents whatever dynamic information is required to render the page, and is something you provide to your view. For example, if you were going to create a View that shows a person's First name and Last name, you might come up with the following model:
public sealed class PersonViewModel
{
public string FirstName {get; set; }
public string LastName {get; set; }
}
It's preferable to use strongly-typed views, so the first line in your .cshtml file would be:
#model MyNameSpace.PersonViewModel
And when your controller returns the view, you would pass what needs to be rendered in to it:
public ActionResult Index()
{
return View(new PersonViewModel() { FirstName = "Moo", LastName = "Juice" });
}
ViewData.Model refers to the instance of the PersonViewModel passed in, and is accessed in your view via Model shortcut:
<body>
<p>
Hello #Model.FirstName !!
</p>
</body>
"Object reference not set to an instance of an object" Exception occurs with the following code
VIEW Code
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Hello_World_MVC.Models.ModelProperty>" %>
<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">.
<%using (Html.BeginForm())
{ %>
<%foreach (var cbName in Model.Obj)//Exception throws here NullreferenceException
{%>
<input id="cbID" type="checkbox" name="SelectedObject" value="<%=cbName.OptionID%>"/>
<%} %>
<%} %>
</asp:Content>
Control page
public ActionResult About()
{
AboutModels ObjAM = new AboutModels();//model class name
ModelProperty ObjMP = new ModelProperty();
ObjMP.Obj = ObjAM.dbValue();
return View();
}
Model Page
#region ModelsDTO
public class ModelProperty
{
private List<double> cbvalues = new List<double>();
public List<double> cbValues { get; set; }
private List<Option> obj = new List<Option>();
public List<Option> Obj { get; set; }
}
#endregion
public class AboutModels
{
DataClasses1DataContext dbObj = new DataClasses1DataContext();
public List<PollOption> dbValue()
{
List<Option> opValue = new List<Option>();
opValue = (from Value in dbObj.Options
select Value).ToList<Option>();
return opValue;
}
}
Please help..Thanks in advance
Change return View(); in AboutAction with return View(ObjMP);. Your mistake is that you forget to pass generated model to view, and it is null.
you should enter the model/object as paramter for returning the view
so in your case it is
return View(ObjMP);
hth
You need to pass the model to the view. Try this..
public ActionResult About()
{
AboutModels ObjAM = new AboutModels();//model class name
ModelProperty ObjMP = new ModelProperty();
ObjMP.Obj = ObjAM.dbValue();
return View(ObjAM);
}
I have a view model with a collection of other objects in it.
public ParentViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Child { get; set; }
}
public ChildViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
}
In one of my views I pass in a ParentViewModel as the model, and then use
<%: Html.EditorFor(x => x) %>
Which display a form for the Id and Name properties.
When the user clicks a button I call an action via Ajax to load in a partial view which takes a collection of Child:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
<%: Html.EditorFor(x => x) %>
which then uses the custom template Child to display a form for each Child passed in.
The problem I'm having is that the form created by the Child custom template does not use the naming conventions used by the DefaultModelBinder.
ie the field name is (when loaded by Ajax):
[0].FirstName
instead of:
Child[0].FirstName
So the Edit action in my controller:
[HttpPost]
public virtual ActionResult Edit(int id, FormCollection formValues)
{
ParentViewModel parent = new ParentViewModel();
UpdateModel(parent);
return View(parent);
}
to recreate a ParentViewModel from the submitted form does not work.
I'm wondering what the best way to accomplish loading in Custom Templates via Ajax and then being able to use UpdateModel is.
Couple of things to start with is that you need to remember the default ModelBinder is recursive and it will try and work out what it needs to do ... so quite clever. The other thing to remember is you don't need to use the html helpers, actual html works fine as well :-)
So, first with the Model, nothing different here ..
public class ParentViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Child { get; set; }
}
public class ChildViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
}
Parent partial view - this takes an instance of the ParentViewModel
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ParentViewModel>" %>
<h2>Parent</h2>
<%: Html.TextBox("parent.Name", Model.Name) %>
<%: Html.Hidden("parent.Id", Model.Id) %>
<% foreach (ChildViewModel childViewModel in Model.Child)
{
Html.RenderPartial("Child", childViewModel);
}
%>
Child partial view - this takes a single instance of the ChildViewModel
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ChildViewModel>" %>
<h3>Child</h3>
<%: Html.Hidden("parent.Child.index", Model.Id) %>
<%: Html.Hidden(string.Format("parent.Child[{0}].Id", Model.Id), Model.Id)%>
<%: Html.TextBox(string.Format("parent.Child[{0}].FirstName", Model.Id), Model.FirstName) %>
Something to note at this point is that the index value is what is used for working out the unique record in the list. This does not need to be incremental value.
So, how do you call this? Well in the Index action which is going to display the data it needs to be passed in. I have setup some demo data and returned it in the ViewData dictionary to the index view.
So controller action ...
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ViewData["Parent"] = GetData();
return View();
}
private ParentViewModel GetData()
{
var result = new ParentViewModel
{
Id = 1,
Name = "Parent name",
Child = new List<ChildViewModel>
{
new ChildViewModel {Id = 2, FirstName = "first child"},
new ChildViewModel {Id = 3, FirstName = "second child"}
}
};
return result;
}
In the real world you would call a data service etc.
And finally the contents of the Index view:
<form action="<%: Url.Action("Edit") %>" method="post">
<% if (ViewData["Parent"] != null) { %>
<%
Html.RenderPartial("Parent", ViewData["Parent"]); %>
<% } %>
<input type="submit" />
</form>
Saving
So now we have the data displayed how do we get it back into an action? Well this is something which the default model binder will do for you on simple data types in relatively complex formations. So you can setup the basic format of the action which you want to post to as:
[HttpPost]
public ActionResult Edit(ParentViewModel parent)
{
}
This will give you the updated details with the original ids (from the hidden fields) so you can update/edit as required.
New children through Ajax
You mentioned in your question loading in custom templates via ajax, do you mean how to give the user an option of adding in another child without postback?
If so, you do something like this ...
Add action - Need an action which will return a new ChildViewModel
[HttpPost]
public ActionResult Add()
{
var result = new ChildViewModel();
result.Id = 4;
result.FirstName = "** to update **";
return View("Child", result);
}
I've given it an id for easy of demo purposes.
You then need a way of calling the code, so the only view you need to update is the main Index view. This will include the javascript to get the action result, the link to call the code and a target HTML tag for the html to be appended to. Also don't forget to add your reference to jQuery in the master page or at the top of the view.
Index view - updated!
<script type="text/javascript">
function add() {
$.ajax(
{
type: "POST",
url: "<%: Url.Action("Add", "Home") %>",
success: function(result) {
$('#newchild').after(result);
},
error: function(req, status, error) {
}
});
}
</script>
<form action="<%: Url.Action("Edit") %>" method="post">
<% if (ViewData["Parent"] != null) { %>
<%
Html.RenderPartial("Parent", ViewData["Parent"]); %>
<% } %>
<div id="newchild"></div>
<br /><br />
<input type="submit" /> add child
</form>
This will call the add action, and append the response when it returns to the newChild div above the submit button.
I hope the long post is useful.
Enjoy :-)
Hmm... i personally would recommend to use a JSON result, instead of a HTML result, that you fiddle in the page...
makes the system cleaner. and your postback working ;-)
I found another way to accomplish this which works in my particular situation.
Instead of loading in a partial via via Ajax that is strongly typed to a child collection like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
I created a strongly typed view to the parent type and then called EditorFor on the list like so:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Parent>" %>
<%: Html.EditorFor(x => x.ChildList) %>
This then calls a Custom Display Template and the result is that all the HTML elements get named correctly and the Default Model binder can put everything back together.
How do I create a partial view that has a form with assigned id?
I got as far as:
using (Html.BeginForm(?action?,"Candidate",FormMethod.Post,new {id="blah"}))
Partial view is used for both Create and Edit so first parameter ?action? will be different. I can't figure out what value of ?action? supposed to be.
UPDATE:
I guess I was not clear enough with the question. What I ended up doing is splitting Request.RawUrl to get controller name and action name:
string[] actionUrlParts = ViewContext.HttpContext.Request.RawUrl.Split('/');
using (Html.BeginForm(actionUrlParts.Length >= 2? actionUrlParts[2] : "",
actionUrlParts.Length >= 1 ? actionUrlParts[1] : "", FormMethod.Post, new { id = "blah" }))
Kind of ugly but it works. Is there a better way to get an action name inside the partial view?
Pass in the action to be performed via ViewData.
In your action that renders the view, create a ViewData item for the postback action. In your form reference this ViewData item to fill in the action parameter. Alternatively, you can create a view-only model that includes the action and the actual model as properties and reference it from there.
Example using ViewData:
using (Html.BeginForm( (string)ViewData["PostBackAction"], "Candidate", ...
Rendering actions:
public ActionResult Create()
{
ViewData["PostBackAction"] = "New";
...
}
public ActionResult Edit( int id )
{
ViewData["PostBackAction'] = "Update";
...
}
Example using Model
public class UpdateModel
{
public string Action {get; set;}
public Candidate CandidateModel { get; set; }
}
using (Html.BeginForm( Model.Action, "Candidate", ...
Rendering actions:
public ActionResult Create()
{
var model = new UpdateModel { Action = "New" };
...
return View(model);
}
public ActionResult Edit( int id )
{
var model = new UpdateModel { Action = "Update" };
model.CandidateModel = ...find corresponding model from id...
return View(model);
}
EDIT: Based on your comment, if you feel that this should be done in the view (though I disagree), you could try some logic based off the ViewContext.RouteData
<%
var action = "Create";
if (this.ViewContext.RouteData.Values["action"] == "Edit")
{
action = "Update";
}
using (Html.BeginForm( action, "Candidate", ...
{
%>
Pass nulls as action and controller. Extension will use just current action and current controller
using (Html.BeginForm(null, null, FormMethod.Post, new { id="Model" }))
Action generated for form will be the same as parent view of this partial view.
It generates
<form action="/Orders/Edit/1" id="Model" method="post">
for url http://localhost:1214/Orders/Edit/1
... and this
<form action="/Orders/Create" id="Model" method="post">
for url http://localhost:1214/Orders/Create
<% html.RenderPartial("MyUserControl", Model.ID) %>