when I run my code it seems that my HttpGet method works fine. But when I try to return the value to my HttpPost action it just runs my HttpGet method and then I get an "NullReferenceException" error.
Here is my code.
My Actions in my controller:
[HttpGet]
public IActionResult AddMovie(int? id)
{
List<Movie> movieList = new List<Movie>();
movieList = dbContext.Movies.ToList();
AddMovieViewModel viewModel = new AddMovieViewModel()
{
movies = movieList,
customer = dbContext.Customers.Where(s => s.CustomerId == id).FirstOrDefault()
};
return View(viewModel);
}
[HttpPost]
public IActionResult AddMovie (int id,int cid)
{
Customer customer = dbContext.Customers.Where(s => s.CustomerId == cid).FirstOrDefault();
Movie movie = dbContext.Movies.Where(s => s.MovieId == id).FirstOrDefault();
customer.BorrowingMovies.Add(movie);
customer.BorrowingMovies.Add(movie);
return View();
}
And here my view
#model MovieExampleAppDotNetCore.ViewModels.AddMovieViewModel
#{
ViewData["Title"] = "AddMovie";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>AddMovie</h1>
<label>Add movie for: #Model.customer.Name</label>
<table style="width:100%" class="table table-bordered table-hover">
<tr>
<th>Name</th>
</tr>
#foreach (var movie in Model.movies)
{
<tr>
<td>#movie.Name</td>
<td>
#Html.ActionLink("Select", "AddMovie", new { id = movie.MovieId, cid = Model.customer.CustomerId })
</td>
</tr>
}
</table>
I hope someone can help me with my problem.
The HTML ActionLink does not work with POST so is hitting your GET method. See this question.
To overcome and resolve your issue, wrap the button in a Form, something like this should do the trick.
#using (Html.BeginForm("AddMovie", "ControllerName", new { id = movie.MovieId, cid = Model.customer.CustomerId }, FormMethod.Post))
{
<button class="btn btn-primary" type="submit">
Add Movie
</button>
}
Related
I am new to MVC and I am trying populate a list of item in the MVC view class, but the model object is null in the .cshtml file during the startup.
#foreach (var element in Model)
Thanks for your help.
My Code:
public class HomeController : Controller
{
List<ModelMath> mathList = new List<ModelMath>();
[HttpPost]
public ActionResult Submit(FormCollection fc)
{
mathList = new List<ModelMath>();
int num = Convert.ToInt32(fc["Num"]);
while(num > 1)
{
ModelMath modelMath = new ModelMath();
modelMath.Number = num;
mathList.Add(modelMath);
num--;
}
return View(mathList);
}
}
Model class:
public class ModelMath
{
public int Number { get; set; }
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h3><b>HTTPPost Method</b></h3>
#using (Html.BeginForm("Submit", "Index", FormMethod.Post))
{
<table>
<tr>
<td>Enter a Number: </td>
<td>#Html.TextBox("Num")</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"></td>
</tr>
</table>
}
<h4 style="color:purple">
<div class="panel-body">
<div class="col-md-12" style="margin-top: 15px;">
<table class="table table-bordered table-responsive table-hover">
<tr>
<th>Input Numbers </th>
</tr>
#foreach (var element in Model)
{
<td>#d.Number</td>
}
</table>
</div>
</div>
</h4>
Could you please let me know what's wrong with my code? Thanks again for your help.
In your Index function, you need to populate the model and pass to the view. Something like
Public ActionResult Index()
{
var myList = new List<example>();
return view(myList)
}
and in your view:
#model List<example>
That is what populates your index view model. It would help if you show us the controller function returning your index view.
you should write the type of Model at first of your View
#model List<ModelMath>
and for showing a view you need [HttpGet] attribute action
[HttpGet]
Public ActionResult Index()
{
//var mathList= new list<ModelMath>();
return view(mathList)
}
I'm new with asp.net MVC and studying with some example code.
I'm referrence the sample from https://github.com/LaunchCodeEducation/cheese-mvc.
And I want to add new action and view for the example. Such as add a delete link/button to delete a cheese from cheese/index page directly:
But it seems there have something wrong with the SingleRemove action and view I wrote.
The action I use as below:
[HttpGet]
public IActionResult SingleRemove()
{
ViewBag.cheeses = context.Cheeses.ToList();
return View();
}
[HttpPost]
public IActionResult SingleRemove(int cheeseId)
{
Cheese theCheese = context.Cheeses.Single(c => c.ID == cheeseId);
//context.Cheeses.Remove(theCheese);
//context.SaveChanges();
return View(theCheese);
}
And the view I use as :
#model CheeseMVC.Models.Cheese
<h1>Going to be removed cheese information as below</h1>
<form >
<ul>
<li>Cheese ID: #Model.ID</li>
<li>Cheese Name: #Model.Name</li>
<li>Cheese Type: #Model.Type</li>
<li>Cheese Description: #Model.Description</li>
</ul>
<input type="submit" value="Remove Selected Cheese" />
</form>
Could you please guide how to set the action and model correctly?
And how to let a pop-up window to double confirm the deletion on a cheese?
If you create a Controller and select "Controller with views, using Entity Framework" it will create all of that for you based on your model. You could then go back and make it pretty with ccs to use buttons instead of links ect.. I am not sure what your view is doing in the above code. Your view should be
<table class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
<th></th>
</tr>
</thead>
foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Name)</td>
<td>#Html.DisplayFor(modelItem => item.Type)</td>
<td>#Html.DisplayFor(modelItem => item.Description)</td>
<td>
#using (Html.BeginForm("Delete", "controller name goes here", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" id="id" value="#item.ID" />
<input onclick="return confirm('Are you sure you want to delete the Cheese?');" type="submit" value="Delete" class="btn btn-primary " />
}
</td>
</tr>
}
</table>
Then in your Controller you would have something like this:
public ActionResult Delete(int? ID)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Cheese cheese = db.Cheese.Find(id);
if (cheese == null)
{
return HttpNotFound();
}
return View(Index);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult Delete(int ID)
{
var cheese = db.cheese.Find(id);
if (cheese != null)
{
Cheese cheese = db.Cheese.Find(id);
db.Cheese.Remove(cheese);
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index", "Cheese");
}
Make sure your are using:
using System.Data.Entity;
using System.Linq;
using System.Net;
And also not sure what your context is but this is where the db.Cheese comes from:
private ApplicationDbContext db = new ApplicationDbContext();
In my ASP.Net MVC project I have following ViewModel
public class ApproveItemViewModel
{
[Required]
public int ItemId { get; set; }
[Required]
public string ItemCode { get; set; }
}
I have following two methods in controller
[HttpGet]
public ActionResult ListPendingItems()
{
var items = new List<ApproveItemViewModel>();
//add few items here in above list
return View(vms);
}
[HttpPost]
public JsonResult ApproveItem(ApproveItemViewModel viewmodel)
{
return Json(new { success = success }, JsonRequestBehavior.AllowGet);
}
Now in my razor view what I want is to call ApporveItem method using Ajax calls for each individual item. so I created multiple ajax form using below code.
#model IEnumerable<ApproveItemViewModel>
#foreach (var item in Model)
{
using (Ajax.BeginForm("ApproveItem", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "dane"
}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<tr>
<td>#Html.LabelFor(m => item.ItemId)</td>
<td>#Html.DisplayFor(m => item.ItemId)</td>
</tr>
<tr>
<td>#Html.LabelFor(m => item.ItemCode)</td>
<td>#Html.TextBoxFor(m => item.ItemCode))</td>
</tr>
<tr>
<td><input type="submit" value="Approve" /></td>
</tr>
</table>
}
}
However in the controller action method parameter I get both ItemId and ItemCode as 0 and null respectively. Whats the problem here, could anyone help please? How can we pass the viewmodel to action using ajax?
The problem is most likely that the Model Binder in the view doesn't know how to bind your list of ApproveItemViewModel's.
See this answer for an explanation: https://stackoverflow.com/a/21191624/2521893
#model IEnumerable<ApproveItemViewModel>
#for (int i = 0; i < Model.Count; i++)
{
using (Ajax.BeginForm("ApproveItem", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "dane"
}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<tr>
<td>#Html.LabelFor(m => Model[i].ItemId)</td>
<td>#Html.DisplayFor(m => Model[i].ItemId)</td>
</tr>
<tr>
<td>#Html.LabelFor(m => Model[i].ItemCode)</td>
<td>#Html.TextBoxFor(m => Model[i].ItemCode))</td>
</tr>
<tr>
<td><input type="submit" value="Approve" /></td>
</tr>
</table>
}
}
Cause of this issue is 'parameter' name. You need to keep same name for both controller post action's parameter(ie, viewmodel) and iterating model(item) in cshtml side, then only binding should happened. See the two different solutions below.
Solution 1 : Modify cshtml page:-
Replace #foreach (var item in Model) with #foreach (var viewmodel in Model)
ie,
#foreach (var viewmodel in Model)
Solution 2 : Modify controller action:-Change ApproveItem action's parameter name.
ie,
[HttpPost]
public JsonResult ApproveItem(ApproveItemViewModel item)
{
return Json(new { success = success }, JsonRequestBehavior.AllowGet);
}
I have a list of categories that I want to edit. I can successfully pass them into the controller.
public ActionResult Edit()
{
if (!IsAdmin) return RedirectToAction("Index", "Home");
ViewBag.IsAdmin = IsAdmin;
var categories = _model.Categories.ToList();
return View(categories);
}
Then I have a view to edit the names of the categories.
#using MyStructures.Models
#model List<MyStructures.Models.Category>
#using (Html.BeginForm("Update", "Categories", FormMethod.Post))
{
foreach (var category in Model)
{
var categoryToEdit = #category;
<table>
<tr>
<td>Category Number: #category.Id</td>
<td>#Html.EditorFor(x => categoryToEdit.Name)</td>
<td colspan="2">
<input type="submit" value="Save"
formaction=#Href("~/Categories/Update/") />
</td>
</tr>
</table>
}
<input type="submit" value="Cancel"
formaction=#Href("~/Home/Index/") />
}
How do I pass the updated value to the "Update" controller? The value of Category obj is null.
[HttpPost]
public ActionResult Update(Category obj)
{
var existing = _model.Categories.Find(obj.Id);
existing.Name = obj.Name;
_model.SaveChanges();
return RedirectToAction("Index", "Home");
}
I got a stored procedure which i show in the view for edits. I made a strong type of the stored procedure. When i edit the fields and then press the save button, the parameter "cm" is always empty. And it's not showing a list but just 1 record.
The custom model:
public class CustomModel
{
public string Description { get; set; }
public System.Data.Linq.ISingleResult<GetItems_ListResult> ItemList { get; set;}
}
This part of the controller sends it to the view:
public ActionResult Details(int id)
{
var row = dataContext.Items.FirstOrDefault(x => x.ItemID == id);
var cm = new CustomModel();
cm.ItemList = dataContext.GetItem_List(row);
cm.Description = row.Description;
return View(cm);
}
This controller receives data from the view:
[HttpPost]
public ActionResult UpdateItems(CustomModel cm)
{
return RedirectToAction("Index");
}
This is the view:
#model TestWeb.Models.CustomModel
#using (Html.BeginForm("UpdateItems", "Item", FormMethod.Post))
{
<table>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
#foreach (var p in Model.ItemList.ToList())
{
<tr>
<td>
#Html.HiddenFor(mdl => p.ItemId)
</td>
<td>#p.Name</td>
<td>
#Html.EditorFor(mdl => p.Description)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="save" />
</p>
}
What am i doing wrong here?
Try the following:
Make a GetItems_ListResult.cshtml like this:
<tr>
<td>
#Html.HiddenFor(mdl => mdl.ItemId)
</td>
<td>#Model.Name</td>
<td>
#Html.EditorFor(mdl => mdl.Description)
</td>
</tr>
Then in your for loop do this:
#for (int i = 0; i < Model.ItemList.Count(); i++)
{
#Html.EditorFor(m => m.ItemsList[i])
}
Update: I didn't quite notice you were using an ISingleResult. You could do this instead:
//Since it'll have none or one element..
if(Model.ItemList != null && Model.ItemList.Any())
{
#Html.EditorFor(m => m.ItemList.First())
}
Have you read this blog post? http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ Steve covers editing lists in asp mvc.
Once your read that take a look at this nuget package http://nuget.org/packages/BeginCollectionItem