SelectList, ASP.NET MVC - asp.net-mvc

I'm working with a SelectList, and populating it with the data from a table. I'm trying to bind it to the ID of another object.
EDIT
Updated the Schema to Reflect something I neglected. I have updated it to show the exact names of each item. I think the problem comes in the fact that each Unit has a sheet, and each sheet has a product. (The sheet will hold more information for the product, but a Unit will have a great deal of other information, so I wanted to separate them in order to keep it clear what was what.)
I think something is happening and the "Sheet" isn't being initialized as an object, and when the binding occurs, it doesn't have an object to bind to, since it is one-level deep. Tell me if this makes sense, or if I am just completely off base.
**Unit**
UnitID (PK)
**ProductSheet**
UnitId (FK)(PK)
ItemId (FK)
**Items**
ItemId (PK)
ItemTitle
It just ...isn't working though. I have this code.
DatabaseDataContext db = new DatabaseDataContext();
Unit unit = new Unit();
ViewData["Items"] = new SelectList( db.Items, "Id", "ItemTitle", unit.ProductSheet.ItemId);
But in the postback, the selectList is always null and empty! This is the View code. I'm really getting lost here, I've followed a lot of examples and it still comes up with bunk.
<%= Html.DropDownList("Items") %>

Your view code should read:
<% var selectItems = ViewData["Items"] as SelectList; %>
<%= Html.DropDownList("ProductSheet.ItemId", selectItems) %>

An entire sample of the project is available at this url
These are the action methods.
public ActionResult Create()
{
DatabaseDataContext database = new DatabaseDataContext();
Unit u = new Unit();
u.Sheet = new Sheet();
ViewData["ProductListing"] = new SelectList(database.Products, "ProductId", "ProductName", u.Sheet.ProductId);
return View();
}
//
// POST: /Home/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Unit u)
{
try
{
DatabaseDataContext database = new DatabaseDataContext();
database.Units.InsertOnSubmit(u);
database.SubmitChanges();
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Here is the Create View.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Models.Contexts.Unit>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Create
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Create</h2>
<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<%= Html.DropDownList("ProductListing") %>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ScriptContent" runat="server">
</asp:Content>

I've marked the answer that seems to have made some progress now, I think I'm starting to understand it better.
When I passed the 'path' of the object to assign as a string in the name field of DropDownList, it seems to work. But this doesn't really make a lot of sense to me. Can you explain what is going on any better?

Related

Make a ASP.Net MVC Site, filtering the content

I recently started an MVC project to query and to report the company's users, everything seemed to be fine, except when I made a finduser form, I got all stuck!
you see I want the operator to be able to find the appropriate user by entering either hos pin,serial or calling number but the action links I make for the search operation all fail because they are made at the form_load time and so the empty string of text boxes get injected to them.
So my requests are:
How to make this filters work.
Now a little Ajax textbox suggester on user pin or serial would be great, please gimme a hint or two.
<table>
<tr>
<td>
PIN:</td>
<td>
<asp:TextBox ID="txt_pin" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
Serial Number:</td>
<td>
<asp:TextBox ID="txt_sn" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
CallingNumber:</td>
<td>
<asp:TextBox ID="txt_callingNo" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
CalledThisNumberToday:</td>
<td>
<asp:TextBox ID="txt_calledNo" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td>
</td>
<td>
</td>
</tr>
</table>
<%:Html.ActionLink("Search for user", "Details", new { pin = txt_pin.Text })%>
<asp:TextBox>? In an ASP.NET MVC application? I am afraid you got it all wrong.
I would recommend you going through the getting started tutorials here in order to learn the basic concepts of ASP.NET MVC: http://asp.net/mvc
In ASP.NET MVC you use models and in the views you use helpers in order to generate input fields.
So in your case you could design a view model:
public class SearchViewModel
{
public string Pin { get; set; }
public string SerialNumber { get; set; }
public string CallingNumber { get; set; }
public string CalledThisNumberToday { get; set; }
}
then you could design a controller action which will pass this view model to the view for rendering the search form:
public ActionResult Index()
{
var model = new SearchViewModel();
return View(model);
}
and finally in your strongly typed view you would use HTML helpers:
<%# Page
Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AppName.Models.SearchViewModel>" %>
<asp:Content ID="MainContent" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
<div>
<%= Html.LabelFor(x => x.Pin) %>
<%= Html.EditorFor(x => x.Pin) %>
</div>
<div>
<%= Html.LabelFor(x => x.SerialNumber) %>
<%= Html.EditorFor(x => x.SerialNumber) %>
</div>
<div>
<%= Html.LabelFor(x => x.CallingNumber) %>
<%= Html.EditorFor(x => x.CallingNumber) %>
</div>
<div>
<%= Html.LabelFor(x => x.CalledThisNumberToday) %>
<%= Html.EditorFor(x => x.CalledThisNumberToday) %>
</div>
<p><input type="submit" value="Search for user" /></p>
<% } %>
</asp:Content>
and the final step would be to implement the controller action that will perform the search and to which this form will be subimtted:
[HttpPost]
public ActionResult Index(SearchViewModel model)
{
if (!ModelState.IsValid)
{
// the model was not valid => redisplay the form
// so that the user can fix his errors
return View(model);
}
// TODO: perform the search
...
}
Along with Darin's excellent answer (which you really need to follow in order to do things the "MVC" way...), you can also do AJAX filtering on a table using jQuery. There's even a plugin for jQuery that makes live table filtering as simple as adding a script reference and a textbox, then a couple lines of Javascript code to wire up the search. This will end up looking something like this:
<script language="javascript" type="text/javascript" src="/Scripts/jquery.js"></script>
<script language="javascript" type="text/javascript" src="/Scripts/jquery.uitablefilter.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$("#myFilter").keyup(function () {
$.uiTableFilter($("#myTable"), $(this).val());
});
});
</script>
<input type="text" id="myFilter" />
<table id="myTable">
...
</table>
As you start typing in the filter box, the table will be automatically filtered to only show rows that contain the specified value.
As for auto-complete suggestions, you might want to look into jQUery UI - they've got
support for auto-complete using several different mechanisms to provide the hint values.

Subsonic 5 Minute Demo newbie problems

I have looked at the "Subsonic 5 Minute Demo", and got my data objects generated from the database after some initial problems. I am using Visual Web Developer Express 2010 and my project is, as in the demo, an ASP.NET MVC 2 Web Application.
So, I've written this code in my HomeController:
public ActionResult Index()
{
ViewData["Message"] = "Welcome to Food Recipe Web!";
//lets get some data
var db = new FoodRecipeWeb.Data.FoodRecipeWebDB();
var recipes = from r in db.Recipes
select r;
return View(recipes);
}
My View looks like this:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2><%: ViewData["Message"] %></h2>
<ul>
<%foreach (var recipe in Model)
{ %>
<li><%= recipe.Name %></li>
<% } %>
</ul>
</asp:Content>
This is quite like the demo, but when I try to look at the page, I get this message:
Compiler Error Message: CS1579: foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'
Source Error:
Line 6: <h2><%: ViewData["Message"] %></h2>
Line 7: <ul>
Line 8: <%foreach (var recipe in Model)
Line 9: { %>
Line 10:
So what am I doing wrong here?
Your View needs to know about the Model.
Change it from:
Inherits="System.Web.Mvc.ViewPage"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<Recipe>>"

ASP.net mvc EntityCollection is null when saving

I've been trying to figure this out for over a day now but I just can't get this to work.
I have an asp.net MVC website which uses the entityframework for its datamodel.
I need to be able to edit a complex Release entity which contains a List<ReleaseDescription>
I have the following model (Apparantly I cannot upload pictures so I'll just type it out):
public class Release
{
public string Version
..some other primitive properties
public EntityCollection<ReleaseDescription>
}
public class ReleaseDescription
{
public string Description
public Language Language
}
public class Language
{
public string ISOCode
public string Description
}
When looking for a solution for this problem on the web. I found out that using an EntityCollection (see list Release.ReleaseDescription) is not a good idea so in the partial class Release I made an extra property ReleaseDescriptionList which transforms this entityCollection into a List<ReleaseDescription> through the getter, it has no setter.
The problem is that, when saving, my release.ReleaseDescription or even the release.ReleaseDescriptionList is always empty when items should be in it.
Here follows the rest of my code:
My Edit.aspx code looks like this
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Server.DM.Release>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
... (Code for the primitive properties (works all fine)
<fieldset>
<legend>Descriptions</legend>
<% for(var i =0; i<Model.ListReleaseDescriptions.Count; i++)
{%>
<%: Html.EditorFor(x => Model.ListReleaseDescriptions[i], "ReleaseDescriptionRow")%>
<%} %>
<%= Html.ActionLink("Add another...", "AddDescription", Model) %>
</fieldset>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
The asp code in the DescriptionRelease looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Server.DM.ReleaseDescription>" %>Language: <%= Html.TextBoxFor(x => x.Language.ISOCode) %>Qty: <%=Html.TextBoxFor(x => x.Description)%>
(I couldn't get above codeblock on multiple lines sorry)
When I click the save button in the edit screen and I get to my ActionController
[HttpPost]
public ActionResult Edit(Release release)
release.DescriptionRelease does not contain any data when 3 items should be in it.
Any help is appreciated in resolving this issue!
(ps: yes I know there are similar threads on this forum and others but none of it seems to work for me.)
OK, After a lot of searching I finally found an answer for my problem.
I already made an extra property to make up for the EntityCollection but it looked like this:
public IList<ReleaseDescription> ListReleaseDescription
{
get
{
return ReleaseDescription.ToList();
}
}
That didn't work so I made a simple property out of it like so:
public IList<ReleaseDescription> ListReleaseDescription{get; set;}
and I populated this property in my controller. This finally fixed my problem and I got all the data back when saving! I can't believe I wasted 1,5 days on this when the solution was this simple.

partial views in ASP.NET MVC

How create View page which is composed of three partial view pages? I am using ASP.NET MVC
//
// GET: /Partial/
public ActionResult View1()
{
var upit = from i in proba.name
select i;
return PartialView("upit",proba.name);
}
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<div><%Html.RenderPartial("View1",proba.name); %></div>
</asp:Content>
Why this code return error: Object reference not set to an instance of an object.
I think you want to use RenderAction, not RenderPartial. View1 is an action, not a view. It returns the partial view, upit. Note that this requires MVC2 (or MVC1 + futures). You also probably want to decorate the action with the ChildActionOnlyAttribute unless you intend to call it from AJAX as well.
[ChildActionOnly]
public ActionResult View1()
{
var upit = from i in proba.name
select i;
return PartialView("upit",proba.name);
}
asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<div><%= Html.Action("View1"); %></div>
</asp:Content>
The reason you are getting the specific error is that the proba variable isn't defined in the view, nor does it need to be. In your case, the action determines the model being passed to the partial view so there's no need for any data to be passed. You could only pass it via query parameters anyway when rendering an action.
Inside your view page you would want to make use of the RenderPartial method.
Example
Say I had 3 partial views called "View1", "View2" and "View3". If I wanted to render all 3 of these views to make up the content of my view then I would do something like:
<div id="section1">
<% Html.RenderPartial("View1", Model.Table1) %>
</div>
<div id="section2">
<% Html.RenderPartial("View2", Model.Table2) %>
</div>
<div id="section3">
<% Html.RenderPartial("View3", Model.Table3) %>
</div>
I assume you would have a MasterPage which your view derives from in order to take care of the other necessary markup. The above would just be placed inside the Content section of your derived view.

How to make update panel in ASP.NET MVC

How do I make an update panel in the ASP.NET Model-View-Contoller (MVC) framework?
You could use a partial view in ASP.NET MVC to get similar behavior. The partial view can still build the HTML on the server, and you just need to plug the HTML into the proper location (in fact, the MVC Ajax helpers can set this up for you if you are willing to include the MSFT Ajax libraries).
In the main view you could use the Ajax.Begin form to setup the asynch request.
<% using (Ajax.BeginForm("Index", "Movie",
new AjaxOptions {
OnFailure="searchFailed",
HttpMethod="GET",
UpdateTargetId="movieTable",
}))
{ %>
<input id="searchBox" type="text" name="query" />
<input type="submit" value="Search" />
<% } %>
<div id="movieTable">
<% Html.RenderPartial("_MovieTable", Model); %>
</div>
A partial view encapsulates the section of the page you want to update.
<%# Control Language="C#" Inherits="ViewUserControl<IEnumerable<Movie>>" %>
<table>
<tr>
<th>
Title
</th>
<th>
ReleaseDate
</th>
</tr>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%= Html.Encode(item.Title) %>
</td>
<td>
<%= Html.Encode(item.ReleaseDate.Year) %>
</td>
</tr>
<% } %>
</table>
Then setup your controller action to handle both cases. A partial view result works well with the asych request.
public ActionResult Index(string query)
{
var movies = ...
if (Request.IsAjaxRequest())
{
return PartialView("_MovieTable", movies);
}
return View("Index", movies);
}
Basically the 'traditional' server-controls (including the ASP.NET AJAX ones) won't work out-of-the-box with MVC... the page lifecycle is pretty different. With MVC you are rendering your Html stream much more directly than the abstracted/pseudo-stateful box that WebForms wraps you up in.
To 'simulate' an UpdatePanel in MVC, you might consider populating a <DIV> using jQuery to achieve a similar result. A really simple, read-only example is on this 'search' page
The HTML is simple:
<input name="query" id="query" value="dollar" />
<input type="button" onclick="search();" value="search" />
The data for the 'panel' is in JSON format - MVC can do this automagically see NerdDinner SearchController.cs
public ActionResult SearchByLocation(float latitude, float longitude) {
// code removed for clarity ...
return Json(jsonDinners.ToList());
}
and the jQuery/javascript is too
<script type="text/javascript" src="javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
// bit of jquery help
// http://shashankshetty.wordpress.com/2009/03/04/using-jsonresult-with-jquery-in-aspnet-mvc/
function search()
{
var q = $('#query').attr("value")
$('#results').html(""); // clear previous
var u = "http://"+location.host+"/SearchJson.aspx?searchfor=" + q;
$("#contentLoading").css('visibility',''); // from tinisles.blogspot.com
$.getJSON(u,
function(data){
$.each(data, function(i,result){
$("<div/>").html(''+result.name +''
+'<br />'+ result.description
+'<br /><span class="little">'+ result.url +' - '
+ result.size +' bytes - '
+ result.date +'</span>').appendTo("#results");
});
$("#contentLoading").css('visibility','hidden');
});
}
</script>
Of course UpdatePanel can be used in much more complex scenarios than this (it can contain INPUTS, supports ViewState and triggers across different panels and other controls). If you need that sort of complexity in your MVC app, I'm afraid you might be up for some custom development...
If you are new to asp.mvc I recommend you to download the NerdDinner (source) sample application. You will find in there enough information to start working effectively with mvc. They also have ajax examples. You will find out you don't need and update panel.

Resources