Using Razor pages for my views, I can't find a way to pass an Id / bounded model to my controller.
I have created a delete template view with my model, added a delete action method to my controller, but I can't figure out how to pass any parameters.
#model AdventureWorks.Models.HumanResources.Department
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Department</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
#Html.DisplayFor(model => model.Name)
</dd>
<dt>
#Html.DisplayNameFor(model => model.GroupName)
</dt>
<dd>
#Html.DisplayFor(model => model.GroupName)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ModifiedDate)
</dt>
<dd>
#Html.DisplayFor(model => model.ModifiedDate)
</dd>
</dl>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Delete" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
public ActionResult DeleteConfirmed(Department department)
{
return ViewDepartments();
}
The Department object that is returned, is a new object with no properties set.
Could you advise me, how to pass at least an Id of the to be deleted object?
I managed to get the model with the form on my create and update method, but I can't figure out, how to do the same on delete.
You can add the parameters you want to pass in Html.BeginForm.Here is a demo:
#using (Html.BeginForm("DeleteConfirmed", "Department",new { Id=Model.Id}, FormMethod.Post))
{
...
}
result:
And you don't need to add #Html.AntiForgeryToken(),because your form method is post.
DisplayFor will not do the Model binding.
Assuming Id is a key of Department, add
#Html.HiddenFor(model => model.Id)
inside of Html.BeginForm.
Inside of you delete action use department.Id to find and delete the item.
You have to pass some value to your controller.
#using (Html.BeginForm("DeleteConfirmed", "Department", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id) // Use valid expression for id property
...
}
And change signature of DeleteConfirm method to
public ActionResult DeleteConfirmed(int id) // Use valid id property type
{
// Delete object
}
That should do the trick.
Related
I am trying to send an Event id (Model name is event) from my event view to a partial view in which you could comment on that related event (which is encuptulated by that view and rendered via ajax) then to the post controller action of that partial view which will assign eventId to comment id for db relation. View and partial view has different models. How could i manage that?
DIAGRAM OF WORKFLOW
View -> Partial View -> Controller | | |
Model1(Event) - Model2(Comment)- Post action that'll get Id from Model1 as argument.
(Detail) - (CreateComment) - (Comment Controller - Create)
Event.Id -> Sent to partial view -> On Post action(create comment), Id will be sent to action.
VIEW CODE
#using Evented.Domain.Models
#using Microsoft.AspNetCore.Identity
#model Evented.Web.EventVMCompany
#inject UserManager<User> UserManager
#{
ViewData["Title"] = "Detail";
}
<h1>Detail</h1>
<h4>EventVM</h4>
<hr />
#Html.ValidationMessageFor(m => m.Id)
<form asp-action="JoinEvent">
<div>
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Id)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Id)
#Html.HiddenFor(model=>model.Id)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Topic)
#Html.HiddenFor(model=>model.Topic)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Topic)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Title)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Title)
#Html.HiddenFor(model=>model.Title)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Description)
#Html.HiddenFor(model=>model.Description)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Description)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.Location)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.Location)
#Html.HiddenFor(model=>model.Location)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.BeginsAt)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.BeginsAt)
#Html.HiddenFor(model=>model.BeginsAt)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.EndsAt)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.EndsAt)
#Html.HiddenFor(model=>model.EndsAt)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.joineeLimit )
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.joineeLimit)
#Html.HiddenFor(model=>model.joineeLimit)
</dd>
#Html.HiddenFor(model=>model.CreatorId)
#Html.HiddenFor(model=>model.joineeNumber)
#Html.HiddenFor(model=>model.UsersJoined)
#Html.HiddenFor(model=>model.UsersJoined.Count)
</dl>
</div>
#{
if (Model.CreatorId != UserManager.GetUserId(User))
{
#foreach (var item in Model.UsersJoined)
{
#if (item.UserId != UserManager.GetUserId(User))
{
<button type="submit" class="btn btn-primary">Join</button>
}
else
{
<button type="submit" formaction="/Event/LeaveEvent" class="btn btn-primary">Leave</button>
}
}
#if (Model.UsersJoined.Count == 0)
{
<button type="submit" class="btn btn-primary">Join</button>
}
}
}
</form>
<a asp-action="Index" class="btn btn-primary">Back to List</a>
<div>#{
foreach (var item in Model.UsersJoined)
{
if (item.UserId == UserManager.GetUserId(User))
{
<div id="commentlist"></div>
}
}
}</div>
<div id="createcomment"></div>
<script type="text/javascript">
$('#createcomment').load('#Url.Action("Create","Comment", ViewData["EventId"] )');
$('#commentlist').load('#Url.Action("Index","Comment")');
</script>
PARTIAL VIEW CODE
#model Evented.Web.CommentVM
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" >
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input asp-for="Text" class="form-control" placeholder="Comment"/>
<span asp-validation-for="Text" class="text-danger"></span>
</div>
<div class="form-group">
<input name="button" id="button" type="submit" value="Comment" class="btn btn-primary " />
</div>
</form>
</div>
</div>
CONTROLLER ACTION CODE
[HttpPost]
[ValidateAntiForgeryToken]
public async Task< ActionResult> Create(CommentVM commentVM,int eventId)
{
User usr= usrManager.GetUserAsync(User).Result;
var comment = mapper.Map<Comment>(commentVM);
comment.EventId= eventId;
comment.User = usr;
comment.CreatedAt= DateTime.Now;
comment.UpdatedAt= DateTime.Now;
await commentService.AddCommentAsync(comment);
return RedirectToAction("Index");
}
GITHUB OF PROJECT - https://github.com/kocfurkan/Evented
Codes provided is all i could.
Please try to pass data like this:
EventController:
public async Task<IActionResult> Detail(int id)
{
ViewData["EventId"] = id;
//.....
}
Detail.cshtml:
//...
<script type="text/javascript">
$('#createcomment').load('#Url.Action("Create","Comment", new {id= ViewData["EventId"]} )');
//...
</script>
CommentController:
public ActionResult Create(int id)
{
return PartialView("_PartialPageCreate", new CommentVM() { EventId = id});
}
_PartialPageCreate.cshtml:
<div class="form-group">
//Add a hidden input
<input name="eventId" type="hidden" value="#Model.EventId" />
<input asp-for="Text" class="form-control" placeholder="Comment"/>
<span asp-validation-for="Text" class="text-danger"></span>
</div>
Test Result:
I have a table with three columns with first two formulating the composite key
SrcSys (CompositeKey Part I)
CustId (CompositeKey Part II)
CustNm
I am new to ASP & starting with MVC Core.
The following code for get method works well:
public async Task<IActionResult> Delete(string _SrcSys, string _CustId)
{
if (_SrcSys == null || _CustId == null)
{
return NotFound();
}
var customer = await _context.Customers.SingleOrDefaultAsync(Cust => Cust.SrcSys == _SrcSys && Cust.CustId == _CustId);
if (customer == null)
{
return NotFound();
}
return View(customer);
}
The relevant code of Delete.cshtml is:
#model RiskDotNet.Models.Customer
#{
ViewData["Title"] = "Delete";
}
#*<h2>Delete</h2>*#
<br />
<hr />
<dl class="dl-horizontal">
<dt>
Src Sys
</dt>
<dd>
#Html.DisplayFor(model => model.SrcSys)
</dd>
<dt>
Cust ID
</dt>
<dd>
#Html.DisplayFor(model => model.CustId)
</dd>
<dt>
Customer
</dt>
<dd>
#Html.DisplayFor(model => model.CustNm)
</dd>
</dl>
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" />
<p />
<p />
<input type="submit" value="Cancel" class="btn btn-default" a asp-action="Index">
</div>
</form>
All the three fields are appearing on the page.
In respect of HttpPost what would be a reasonable piece of code?
You need to put the SrcSys and CustId in the form so they can be passed to the backend on the submit.
You can just put this in the form part:
#Html.HiddenFor(model => model.SrcSys)
#Html.HiddenFor(model => model.CustId)
These properties wont be displayed but they will be submitted.
Sidenote
Dont use Html helpers ( #Html.DisplayFor, #Html.HiddenFor..) they are the old way of doing things.
Use tag helpers that came with MVC Core:
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro
I resolved the problem myself:
Updated HttpPost:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeletePost(Customer customer)
{
try
{
_context.Entry(customer).State = EntityState.Deleted;
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
return RedirectToAction("Delete", new { ss = customer.SrcSys, ci = customer.CustId });
}
}
and Updated Delete.cshtml:
#model RiskDotNet.Models.Customer
#{
ViewData["Title"] = "Delete";
}
<hr />
<dl class="dl-horizontal">
<dt>
Src Sys
</dt>
<dd>
#Html.DisplayFor(model => model.SrcSys)
</dd>
<dt>
Cust ID
</dt>
<dd>
#Html.DisplayFor(model => model.CustId)
</dd>
<dt>
Customer
</dt>
<dd>
#Html.DisplayFor(model => model.CustNm)
</dd>
</dl>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.SrcSys)
#Html.HiddenFor(model => model.CustId)
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" />
<p />
<p />
<input type="submit" value="Cancel" class="btn btn-default" a asp-action="Index">
</div>
</form>
}
Did the job!!!
:-)
2 Points
3 Posts
Data from view to different controller
1 minute ago|LINK
Hello friends
I'm from Colombia, sorry for the writing
I have a problem I do not know how to connect two controllers from one view, I'm using EF Data Base First, this automatic genre classes to my model, one of these classes is called "UNIVERSITY" which is a table of the database where are all the universities, and another class is "CAMPUS_UNIVERSITY" where are all the campus of a university, a university can have multiple campus
I have 2 controllers and their associated views
The first controller is "University" (I think i not necessary show) and your view "Index" (list all Universidadades). That is this:
#model IEnumerable<RolesMVC3.Models.UNIVERSITY>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Nombre
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.ActionLink("Add Campus", "Create", "CampusUniversity" new { id=item.IdUniversity }) |
#Html.ActionLink("Edit", "Edit", new { id=item.IdUniversity }) |
#Html.ActionLink("Delete", "Delete", new { id=item.IdUniversity })
</td>
</tr>
}
</table>
The link "Add Campus" routed to controller "CampusUniversity" to the action "Create". That is this:
public ActionResult Create()
{
ViewBag.IdCityCampus = new SelectList(db.CITY_CAMPUS, "IdCityCampus", "Name");
ViewBag.IdUniversity = new SelectList(db.UNIVERSITY, "IdUniversity", "Name");
return View();
}
//
//
[HttpPost]
public ActionResult Create(CAMPUS_UNIVERSITY campus_university)
{
if (ModelState.IsValid)
{
db.CAMPUS_UNIVERSITY.AddObject(campus_university);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.IdCityCampus = new SelectList(db.CIUDAD_SEDE, "IdCityCampus", "Nombre", campus_university.IdCityCampus);
ViewBag.IdUniversity = new SelectList(db.UNIVERSIDAD, "IdUniversity", "Nombre", campus_university.IdUniversity);
return View(campus_university);
}
And the associated view (View "Create" Controller " CampusUniversity ") is:
#model RolesMVC3.Models.CAMPUS_UNIVERSITY
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>SEDE_UNIVERSIDAD</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdUniversity, "UNIVERSIDAD")
</div>
<div class="editor-field">
#Html.DropDownList("IdUniversity", String.Empty)
#Html.ValidationMessageFor(model => model.IdUniversity)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IdCityCampus, "CITY_CAMPUS")
</div>
<div class="editor-field">
#Html.DropDownList("IdCityCampus", String.Empty)
#Html.ValidationMessageFor(model => model.IdCityCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AddressCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AddressCampuse)
#Html.ValidationMessageFor(model => model.AddressCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneCampus)
#Html.ValidationMessageFor(model => model.PhoneCampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.MailCampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MailCampus)
#Html.ValidationMessageFor(model => model.MailCampus)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I want to do that by clicking "Add Campus" appears the name of the university comes fromthe table or class "UNIVERSITY" in the view Create (controller "SedeUniversidad") and that can save the campus of the university and not as I have now, because I have to choose the university of a DropDownList, how I can do?
Thank you, blessings!
I can't understand some of your English. It sounds like you want to send data from your Create view to your University controller. You can make the POST url of your form go wherever you want by putting the following values in your HTML.BeginForm statement in your Create view.
#using (Html.BeginForm("ActionName", "ControllerName"))
My problem is when I try to render a view with two Html.RenderAction. It says: "The operation cannot be completed because the DbContext has been disposed".
I have Ninject configured in this way:
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope;
But If I do in the default way...
Bind<IUnitOfWork>().To<UnitOfWork>()
there's no error.
I have to work with it in RequestScope (so I think), but how can I do it? It seems's that when second Html.RenderAction is called the previous DbContext it's disposed !
UPDATED:
This is the main view (summarized for brevity)
#model FoodAway.Model.Product
#Html.ValidationSummary(true)
<fieldset>
<legend>Producto</legend>
#using (Html.BeginForm())
{
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
#Html.HiddenFor(model => model.Id)
<p>
<input type="submit" value="Guardar" />
</p>
}
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Ingredients)
</div>
<div class="editor-field">
#{Html.RenderAction("IngredientsToRemoveList", "Ingredients");}
</div>
</fieldset>
<fieldset>
#{Html.RenderAction("IngredientsToAddList", "Ingredients");}
</fieldset>
</fieldset>
and his controller/action:
public ActionResult EditProduct(string name)
{
Product product = unitOfWork.ProductRepository.Get(i => i.Name ==name).FirstOrDefault();
if (product == null)
return HttpNotFound();
return View(product);
}
So, the error in DBContext is when I have this 2 RenderAction methods, the strange thing is if I have only 1 RenderAction there is no problem!!!!!
You need to enumerate the set before passing it to the view. This means that you query the database within the valid scope of the DbContext.
You can do this by using .ToArray() in your controller
I have created a ViewModel with two things, a Contact and a list of Phones for that Contact.
My goal is to add data for a new Contact, and add a few Phones, and then save by a Controller action.
I've edited the scaffolded Create.cshtml for my Contact, added a grid for the phones. Added a javascript for creating the phones. So far so good.
The problem is when I click the Create button, and I get back to the Controller, I get no Phones. How do I (in the View) add the phone-rows to my IEnumerable?
EDIT:
Took out code in view that was not correct in this context.
My ViewModel:
public class ContactViewModel
{
public Contact Contact {get; set;}
public IEnumerable<Phone> Phones { get; set; }
}
My view:
#model PilotKibsNet.Controllers.ContactViewModel
<script type="text/javascript" src="../../Scripts/jquery-1.5.1.js"></script>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script type="text/javascript">
function Add() {
$("#tbl > tbody:last").append("<tr><td>" + $("#Number").val() + "</td><td>" + $("#Kind").val() + "</td><td></td></tr>");
$("#Number").val("");
$("#Kind").val("");
}
</script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Name)
#Html.ValidationMessageFor(model => model.Contact.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.Address)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.Address)
#Html.ValidationMessageFor(model => model.Contact.Address)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Contact.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Contact.City)
#Html.ValidationMessageFor(model => model.Contact.City)
</div>
<legend>Phone numbers</legend>
<label>Number :</label>
#Html.TextBox("Number")
<label>Kind :</label>
#Html.TextBox("Kind")
<input type="button" value="Add" onclick="Add()" />
<table id="tbl">
<tr>
<th>
Phone
</th>
<th>
Kind
</th>
<th></th>
</tr>
<tbody>
</tbody>
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
And then, in by Controller action, the Contact has the data, but the Phone is an empty list.
[HttpPost]
public ActionResult Create(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
contactViewModel.Contact.id = Guid.NewGuid();
db.Contacts.AddObject(contactViewModel.Contact);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contactViewModel.Contact);
}
How do I get the Phones back to the server?!?
You have only display templates for those Phones collection. No value at all will be sent to the server. You could use hidden fields if the user is not supposed to edit the values or textboxes if he is.
Also I would replace this foreach loop in your view by an editor template:
if (Model != null)
{
#Html.EditorFor(x => x.Phones)
}
and then I will define an editor template which would be rendered for each element of the Phones collection (~/Views/Shared/EditorTemplates/Phone.cshtml):
#model Phone
<tr>
<td>
#Html.DisplayFor(x => x.Number)
#Html.HiddenFor(x => x.Number)
</td>
<td>
#Html.DisplayFor(x => x.Type)
#Html.HiddenFor(x => x.Type)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
#Html.ActionLink("Details", "Details", new { id = Model.id }) |
#Html.ActionLink("Delete", "Delete", new { id = Model.id })
</td>
</tr>
I have used hidden fields here to persist the values of the model so that when you post the form to the server they would be sent.
Another and IMHO better approach if the user is not supposed to edit those values in the table is to simply refetch them in your POST action from your database.