Passing data to post method - asp.net-mvc-3

I have a view model that looks like this
public class ViewModelRound2
{
public Bid Bid { get; set; }
public bool SelectedForRound2 { get; set; }
}
I have a get action method that looks like this
public ActionResult Round2Manager(long id)
{
...
return View(round1Ring3Bids);
}
And a post method that looks like this (not implemented it yet)
[HttpPost]
public ActionResult Round2Manager(IEnumerable<ViewModelRound2> viewModelRound2)
{
return View(viewModelRound2);
}
My view looks like this
#for (var x = 0; x < Model.Count(); x++)
{
ViewModelRound2 viewModelRound2 = Model.ElementAt(x);
Bid bid = viewModelRound2.Bid;
string userName = #bid.User.Invitation.Where(i => i.AuctionId == bid.Lot.Lot_Auction_ID).First().User.User_Username;
<tr>
<td>
#userName
</td>
<td>
#bid.Bid_Value
</td>
<td>
#Html.EditorFor(c => c.ElementAt(x).SelectedForRound2)
</td>
</tr>
}
</table>
<div class="buttonwrapper2">
#Ajax.ActionLink("Select", "Round2Manager", new { viewModelRound2 = Model }, new AjaxOptions() { HttpMethod = "POST"} )
</div>
The page this renders, contains checkboxes per row in the rendered table and I want to be able to pass checked/unchecked values to the post method so that it can process them. The problem is that the viewModelRound2 parameter of the post method is always null. What is going on? How can I write this so that it does what I intend?

You should put all that HTML inside a <form>.

Related

MVC and Razor to display integer when value is empty or 0

I have the following code in the View.
<span>#Html.DisplayFor(modelItem => item.comments.comments_id)</span>
<span>#item.comments.comments_id</span>
The code below works if comments_id is not 0 or empty.
<span>#((item.comments.comments_id == 0) ? 0 : #item.comments.comments_id)</span>
If its 0 or empty I get
System.NullReferenceException: Object reference not set to an instance of an object.
The class contains this
public Nullable<int> comments_id { get; set; }
How can overcome this issue? thanks in advance.
---- EDit more code ---
public ActionResult Show()
{
var showItems = db.Projects.Include(p => p.Comments).ToList(); // INCLUDES ITEMS FROM BOTH TABLES
return View(showItems);
}
View
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id) // NOTICE this coming from a different table(Comments tbl).
</td>
<td>
<span>#((item.Comments.comments_id == 0) ? 0 : #item.Comments.comments_id) // HERE when item.Comments.comments_id has no contents it throws an error.
Create
</td>
</tr>
}
Someone posted something similar but I don't understand the answer.
http://forums.asp.net/t/1732717.aspx?How+to+check+if+model+property+is+empty+in+View+page
You need to use HasValue to check if a nullable variable has a value or not.
<span>#((item.comments.comments_id.HasValue) ? #item.comments.comments_id : 0)</span>
EDIT: Added Example
Your view code looks like it should work. Below is code I wrote to test your view. The lambda expression in your controller action won't be executed until it's used. So it's possible it's not executed until the view is rendered. This could cause a problem because the database connection may be closed by then. However, the call to ToList() should execute the lambda expression. So the problem is probably that item.Comments is null. You should test to see if it is as I did in my example.
Controller
public class HomeController : Controller
{
public class Project
{
public string ProjectName { get; set; }
public ProjectComments Comments { get; set; }
}
public class ProjectComments
{
public string Comments { get; set; }
public Nullable<int> comments_id { get; set; }
}
public ActionResult Index()
{
var showItems = new List<Project>();
showItems.Add(new Project()
{
ProjectName = "Project 1",
Comments = new ProjectComments() { Comments = "some comments", comments_id = 1 }
});
showItems.Add(new Project()
{
ProjectName = "Project 2",
Comments = new ProjectComments() { Comments = "more comments", comments_id = null }
});
return View(showItems);
}
}
View
#model IList<MvcApplication2.Controllers.HomeController.Project>
<table border="1">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id)
</td>
<td>
<span>
#((item.Comments != null && item.Comments.comments_id.HasValue) ? #item.Comments.comments_id : 0)
Create
</span>
</td>
</tr>
}
</table>

Null entity when using .find method in entity framework

I have been trying to create a simple portal to track logs from a mobile application. As such, I have used entity framework and MVC3 to help me with this. However recently I have been stuck when trying to retrieve the entity from the database.
Here is the Run class:
namespace LifestyleGuide.Models
{
[DataContract(IsReference = true)]
[KnownType(typeof(User))]
public partial class Run
{
[DataMember]
public string User_ID { get; set; }
[DataMember]
public System.DateTime Date { get; set; }
[DataMember]
public Nullable<int> Distance { get; set; }
[DataMember]
public Nullable<int> Duration { get; set; }
[DataMember]
public Nullable<int> Calories { get; set; }
[DataMember]
public virtual User User { get; set; }
}
}
User_ID and date are form a composite key where User_ID is a foreign key from the User table.
And the following is the "details" method from the controller:
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
Run run = db.Runs.Find(id, date);
return View(run);
}
}
However, when i try to run it, the run object always appears as a null.
Any suggestions are greatly appreciated!
EDIT:
Here are is the view for the homepage.
#model IEnumerable<LifestyleGuide.Models.Run>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
<center>User ID</center>
</th>
<th>
<center>Date</center>
</th>
<th>
<center>Distance</center>
</th>
<th>
<center>Duration</center>
</th>
<th>
<center>Calories</center>
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.User_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Distance)
</td>
<td>
#Html.DisplayFor(modelItem => item.Duration)
</td>
<td>
#Html.DisplayFor(modelItem => item.Calories)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Details", "Details", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Delete", "Delete", new { id = item.User_ID, date = item.Date })
</td>
</tr>
}
</table>
The fields in the table are populated from the database directly and therefore should already exist.
Note: I have no problems with creating and accessing the run objects by using the view. The null run object only occurs when I directly do an insert statement into the database and when i try to retrieve it afterwards using the .find method as shown above.
Find() function returns first occurrence of matching item from the Collection which will be a single item that matched the condition. Since your view is strongly typed to IEnumerable<LifestyleGuide.Models.Run>, it's expecting a collection of Run objects not a single object.
You should modify your controller so that a collection (list) of Run objects are passed to the view. You could use WHERE clause like this :
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
List<Run> run = db.Runs.Where(r=>r.Id==id && r=>r.Date==date);
return View(run);
}
}
Good luck :).
I realized the problem! Each entry to the database has a DateTime object with milliseconds while the query doesn't. I did a work-around to remove the milliseconds from all entries and it works!

MVC passing data to view and looping

I am terribly confused with MVC.
I don't have any code to show because i don't know how to do it.
I have an object
public class Name()
{
String name="balh"
String something="blah blah"
//this object works fine and doesn't look like this it has the appropriate get;set;
//use this as just an example
//please disregard this format
}
Now i have a
List<Name> list;//this just holds all of my objects
I need them to be passed to the View
I keep seeing something about models but i don't see it declared anywhere
How do i loop in the view to create something like this
<div> object1 string</div>
<div> object2 string</div>
<div> object3 string</div>
<div> object4 string</div>
<div> object5 string</div>
Your view would look like this, assuming you use your list as the model:
#model List<Name>
#foreach(var item in Model) {
<div> #item.name #item.something</div>
}
So your controller action method might be:
public ViewResult Index() {
// Somehow build list which is List<Name>
return View(list);
}
EDIT: You seem very new, so I recommend trying this tutorial: http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/intro-to-aspnet-mvc-3
Let's take an example.
Model:
public class MyViewModel
{
public string Name { get; set; }
public string Something { get; set; }
}
Controller:
public class HomeController: Controller
{
public ActionResult Index()
{
List<MyViewModel> model = new List<MyViewModel>();
model.Add(new MyViewModel { Name = "some name", Something = "something" });
model.Add(new MyViewModel { Name = "some other name", Something = "something else" });
return View(mdoel);
}
}
View (~/Views/Home/Index.cshtml):
#model IEnumerable<MyViewModel>
<table>
<thead>
<tr>
<th>Name</th>
<th>Something</th>
</tr>
</thead>
<tbody>
#foreach (vat item in Model)
{
<tr>
<td>#item.Name</td>
<td>#item.Something</td>
</tr>
}
</tbody>
</table>
use this code
#foreach (vat item in Model)
{
<tr>
<td>#item.Name</td>
<td>#item.Something</td>
</tr>
}

MVC4: ViewModel (with radiobuttonlist) is empty after HttpPost

I'm having a hard time getting the values from a small multiple choice questionnaire posted to the Controller in my MVC4 app:
The model looks like this:
public class Evaluation
{
public int Id { get; set; }
public IEnumerable<MultipleChoiceQuestion> Question { get; set; }
public Remark Rem { get; set; }
}
public class MultipleChoiceQuestion
{
public int Id { get; set; }
public string Question { get; set; }
public MultipleChoiceAnswer Answer { get; set; }
}
public enum MultipleChoiceAnswer
{
DISAGREE,
NEUTRAL,
AGREE,
NA,
}
This is the View (leaving out some markup):
#model Models.Evaluation
#using (Html.BeginForm("EvaluationB", "Evaluation", FormMethod.Post))
{
#foreach (var item in Model.Question)
{
#Html.DisplayFor(model => item.Question)
#Html.EditorFor(model => item.Question, "Enum_RadioButtonList", new { Id = item.Id })
}
#Html.Label("Remark")
#Html.TextAreaFor(model => model.Rem)
<input type="submit" value="Next" />
}
The "Enum_RadioButtonList" is a View a grabbed from here: https://gist.github.com/973482. It seems like the best way to show enum values in a radiobuttonlist (tho their should be an easier way in MVC 4)
The Controller looks like this:
public ActionResult EvaluationA()
{
Models.Evaluation evm = new Models.Evaluation();
evm.Question = db.MultipleChoiceQuestions.ToList(); //feeding the View some predefined questions
return View(evm);
}
public ActionResult EvaluationB(Models.Evaluation ev)
{
if (ModelState.IsValid)
{
// TODO: save model
return View("EvaluationB", evm);
}
return View("EvaluationA", ev);
}
The questions are loaded fine in the View, but for some reason, the model posted to the Controller remains empty after an HttpPost, and i don't understand why.
I did not see the form have mapping for the Id like below:
#Html.HiddenFor(model => model.Id)
Each of the inner collection of question should also have Id so that it is posted along with the form. So inside the foreach loop in your form for each question you can have:
#Html.HiddenFor(model => item.Question.Id)
Also the model has a collection of type MultipleChoiceQuestion. For model binding to the collection the name of the collection elements should have name attribute with ordered numbers as explained in this post http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Ive done some more research stumbled upon this post:
http://dotnetslackers.com/articles/aspnet/Understanding-ASP-NET-MVC-Model-Binding.aspx
The problem was in the naming of the html fields. Ive added my View like this and now i can read out the values in the Controller correctly:
#for (int i = 0; i < 6; i++)
{
<tr>
<td>
#Html.DisplayFor(m => m.Question[i].Question)
</td>
<td class="mult_question">
#Html.EditorFor(m => m.Question[i].Answer, "Enum_RadioButtonList" )
</td>
</tr>
}
<tr>
<td>
#Html.Label("Remark")
#Html.TextAreaFor(m => m.Remark)

How can I safely access key groups in the FormCollection?

I have a table where each tr is grouped by having their input elements name set to a value that is unique for each row.
For example,
<td>
<input data-field="opps" type="text" value="somevalue" name="#item.Code" />
</td>
<td>
<input data-field="asc" type="text" value="somevalue2" name="#item.Code" />
</td>
On POST
[HttpPost]
public ActionResult Update(FormCollection collection)
{
try
{
//doin work on collection...order assumed static
return RedirectToAction("Index");
}
catch
{
return View();
}
}
my System.Web.MVC.FormCollection is grouped in the same order I define the <td>. I don't like to assume order, but without access to my data-field, I'm not sure what else I can do (maybe I could append the data-field value as a prefix to the name and put it all together with a custom collection and Regex..but that seems nutty).
Is there a way to access the data-field? This way I'm not fragile to re-ordering or adding new columns in the View.
Let's say you have a class (model) defined like this:
public class MyModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
In you controller, you might have an action called Create, like so:
[HttpGet]
public ViewResult Create()
{
MyModel sampleModel = new MyModel();
return View(sampleModel);
}
[HttpPost]
public ActionResult Create(MyModel sampleModel)
{
if (ModelState.IsValid)
{
TempData["Error"] = "There were errors. Please correct the problem and submit again";
return View(sampleModel);
}
// At this point everything is fine and you can access data in your sampleModel
if (sampleModel.Age >= 16)
{
return RedirectToAction("LegalAccess");
}
else
{
TempData["Error"] = "You must be 16 or over to access this site";
return RedirectToAction("AgeRestriction");
}
}
When you create a strongly typed view that uses MyModel as model you might define it something like this:
#model MyModel
#{
Layout = "~/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName)
<br />
#Html.LabelFor(m => m.LastName)
#Html.TextBoxFor(m => m.LastName)
<br />
#Html.LabelFor(m => m.LastName)
#Html.TextBoxFor(m => m.LastName)
<input type="submit" value="Submit" />
}
When you submit this form, the model binder will in the background copy data from this form using Request.Form into an object of type MyModel which it creates in the background. This new object is passed to an action that handles HTTP POST method. With this you get strongly typed object and you don't have to worry about the order of items in FormCollection.
I hope I helped answer your question.
BTW. I wrote this without Visual Studio, so I hope there are not errors. :-)

Resources