I have this datamodel:
so one Project has many Milestones.
What I did is this: when I go to the detail of a specific Project, I can add/create Milestones for it, like in the picture:
When I click "Create Milestone" I navigate to the View where I can create the milestone for this specific Project, when I click save, it will automatically be saved for this project. Here the HttpPost method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateMilestone([Bind(Include = "Name,Description,FromDate,DueDate,Finished,ProjectID")] Milestone milestone, int? id)
{
if (ModelState.IsValid)
{
var forProject = db.Projects.Where(x => x.ID == id).FirstOrDefault();
if (forProject != null)
{
milestone.Project = forProject;
db.Milestones.Add(milestone);
db.SaveChanges();
return RedirectToAction("Details", forProject);
}
else
{
return HttpNotFound();
}
}
else
{
return View(milestone);
}
}
Here is a screenshot of the CreateMilestone View, and focus on the url (it's localhost:xxxxx/Projects/CreateMilestone/3002). The id parameter in the CreateMilestone method is for the Project ID, and in the url the id (3002) is also for the project.
I'm trying to make the app to navigate to the Details view of that specific Project I just added a milestone, which I do actually!
And as you see it works:
But: look at the url! Instead of being localhost:xxxxx/Projects/Details/3002 it is: http://localhost:55623/Projects/Details/3002?Milestones=System.Collections.Generic.HashSet%601%5BTheProjectManager.Models.Milestone%5D&Users=System.Collections.Generic.HashSet%601%5BTheProjectManager.Models.ApplicationUser%5D&ProjectName=Testing&Description=Testing%20data
So, how can I make the url be like: localhost:xxxxx/Projects/Details/3002 when I navigate to the details view after adding a new milestone?
UPDATE:
the Get Details:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Project project = db.Projects.Find(id);
if (project == null)
{
return HttpNotFound();
}
return View(project);
}
and the Get CreateMilestone:
public ActionResult CreateMilestone(int? id)
{
var forProject = db.Projects.Where(x => x.ID == id).FirstOrDefault();
if (forProject != null)
{
return View();
}
else
{
return HttpNotFound();
}
}
In this line
return RedirectToAction("Details", forProject);
you are redirecting to Details action and as parameter you send "Project" object which is serialized to query string. Instead of full object you can use only id. But you also need to change Details action to accept int as parameter instead of Project class
Instead of return RedirectToAction("Details",forProject);
try this return RedirectToAction("Details", new { id = id });
Related
I have a POST method that returns me to my summary page that looks like this
public ActionResult SpecialOrderSelection(ItemViewModel model)
{
if (ModelState.IsValid)
{
JobOrder jobOrder = db.JobOrders.Find(model.Id);
if (jobOrder == null)
{
return HttpNotFound();
}
ViewBag.JobOrderID = jobOrder.ID;
}
return SpecialOrderSummary(model);
}
And here is my Summary GET method
public ActionResult SpecialOrderSummary(ItemViewModel model)
{
return View("SpecialOrderSummary", model);
}
It sends me to my SpecialOrderSummary View Page, however the URL still displays as what my POST method is and not my GET. Also on every refresh it goes to the post first.
Why is this?
This is normal, because mvc runs like this.
You should use redirect,
public ActionResult SpecialOrderSelection(ItemViewModel model)
{
if (ModelState.IsValid)
{
JobOrder jobOrder = db.JobOrders.Find(model.Id);
if (jobOrder == null)
{
return HttpNotFound();
}
ViewBag.JobOrderID = jobOrder.ID;
}
return Redirect("SpecialOrderSummary?(your model serialize)");;
}
I am trying to customize a POST and GET method called CreateOrEdit(int id, Request request) inside of the controller so that when I am in the Index view which is a list of requests generated from a SQL Table and I click either on the Edit button on the right of each row or on the Create New button, I am redirected to the same View which I have called CreateOrEdit.cshtml. I have managed to make the configuration on RouteConfig.cs but I don't how to come up with an 'if - else' condition in order to check whether id is null or is a number. Someone could help me on solving this?
P. s.: Maybe this is children easy but today is my 9th day as a developer guys :)
I have tried:
1. Add another 2 routes.MapRoute() inside RouteConfig.cs
2. Inside the ActionResult CreateOrEdit() GET and POST methods tried to add a condition in order to know whether id != null but it doesn't seem to help.
[HttpGet]
public ActionResult CreateOrEdit(int? id)
{
return View();
}
[HttpPost]
public ActionResult CreateOrEdit(int? id, Request request)
{
if (/* id is not null (Edit has been clicked) */)
{
try
{
using (DbModels dbModel = new DbModels())
{
dbModel.Requests.Add(request);
dbModel.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
else
{
try
{
// Ketu shtojme logjiken e update-imit
using (DbModels dbModel = new DbModels())
{
dbModel.Entry(request).State = System.Data.EntityState.Modified;
dbModel.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
return View();
}
first your condition is wrong. so just change your condition and then try.
[HttpPost]
public ActionResult CreateOrEdit(int? id, Request request)
{
if (id == null)
{
try
{
using (DbModels dbModel = new DbModels())
{
dbModel.Requests.Add(request);
dbModel.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
else
{
try
{
// Ketu shtojme logjiken e update-imit
using (DbModels dbModel = new DbModels())
{
dbModel.Entry(request).State = System.Data.EntityState.Modified;
dbModel.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
return View();
}**strong text**
I'm new to programming and having some trouble with a MVC 5 project. Specifically, within the auto-generated views details, edit and delete. Data is missing for fields which pull data from another model/table.
A have a table with form data known as "Shoutouts." Include is the user's first and last name, and a class known as "Level" which contains a weighted value with a name and an Id.
I was able to work around this by discovering how to use .Inlcude() in the ActionResult for the Index.
public ActionResult Index(string sortOrder)
{
var allShoutouts = db.Shoutouts
.Include(s => s.User)
.Include(s => s.Level);
return View(allShoutouts);
}
But I don't understand how to do it in the other views as well since they need the ShoutoutId to passed through the return.
public ActionResult Details(int? id)
{
ShoutoutFormViewModel SFVM = new ShoutoutFormViewModel();
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Shoutout shoutout = db.Shoutouts.Find(id);
if (shoutout == null)
{
return HttpNotFound();
}
return View(shoutout);
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Shoutout shoutout = db.Shoutouts.Find(id);
if (shoutout == null)
{
return HttpNotFound();
}
return View(shoutout);
}
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Shoutout shoutout = db.Shoutouts.Find(id);
if (shoutout == null)
{
return HttpNotFound();
}
return View(shoutout);
}
Here's what the page looks like for delete as an example of the issue.
I couldn't find any similar questions on Stack Overflow or Google so any help is appreciated.
since you have the id:
var shoutout = db.Shoutouts
.Include(s => s.User)
.Include(s => s.Level)
.Single(s => s.Id == id);
return View(allShoutouts);
i am new in MVC5. I am trying to load master and details data using ActionResult for retrieving master data and JsonResult for Details retrieving data single click in ActionLink.
public JsonResult getOrderDetails(int? id)
{
List<OrderDetail> OrderDetail = new List<OrderDetail>();
OrderDetail = db.OrderDetails.Where(a => a.OrderID==id).OrderBy(a => a.OrderDetialsID).ToList();
return new JsonResult { Data = OrderDetail, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
OrderMaster OrderMaster = db.OrderMasters.Find(id);
return View(OrderMaster);
}
No, this won't work. It will throw an exception explaining that a link must point to exactly one resource (a.k.a one Controller, one Action). Also, that's not how you normally think of doing it in MVC. This is not WebForms where you load the master and detail separately.
You should be doing something like this instead:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var orderMaster = db.OrderMasters
.Where(om => om.OrderMasterId == id)
.Include(om => om.OrderDetails) // include the details here
.Single();
return View(orderMaster);
}
I have below controllers:
// GET: /MaterialPaymentRequestSbuItem/CreateChild
public ActionResult CreateChild(int? parentId)
{
if (parentId==null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var parenetRequest = (from request in db.MaterialPaymentRequests
where request.Id==(int)parentId
select request);
ViewBag.MaterialPaymentRequestId = new SelectList(parenetRequest, "Id", "Description", (int)parentId);
ViewBag.ParentID = parentId;
if (parenetRequest!=null && parenetRequest.First()!=null)
ViewBag.ParentTitle = parenetRequest.First().Description;
return View();
}
// POST: /MaterialPaymentRequestSbuItem/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild([Bind(Include = "Id,Name,Unit,UnitPrice,MaterialPaymentRequestId,Quantity")] MaterialPaymentRequestSubItem materialpaymentrequestsubitem)
{
if (ModelState.IsValid)
{
try
{
db.MaterialPaymentRequestSubItems.Add(materialpaymentrequestsubitem);
db.SaveChanges();
}
catch (Exception e)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
updateTotalPriceOfParentPaymentRequest(db, db.MaterialPaymentRequests.Find(materialpaymentrequestsubitem.MaterialPaymentRequestId));
return RedirectToAction("List", new { id = materialpaymentrequestsubitem.MaterialPaymentRequestId });
}
ViewBag.MaterialPaymentRequestId = new SelectList(db.PaymentRequests, "Id", "Description", materialpaymentrequestsubitem.MaterialPaymentRequestId);
//need to becheked
ViewBag.ParentID = materialpaymentrequestsubitem.MaterialPaymentRequestId;
if (Request != null && Request["parentID"] != null)
{
try
{
int id = Int32.Parse(Request["parentID"]);
ViewBag.ParentTitle = db.MaterialPaymentRequests.Find(id).Description;
}
catch(Exception e)
{
}
}
return View(materialpaymentrequestsubitem);
}
My main problem is that user is allowed to select model.MaterialPaymentRequestId from drop-down and he/she may leave it with no value selected. MaterialPaymentRequestId is used in first controller (befor post) to find Parent title from db and pass it to view using ViewBag, however if user does not select MaterialPaymentRequestId dropdown items, after postback, I lost MaterialPaymentRequestId. Currently I read Request variable and look inside url to find parameters to lookup for parentID.
My url calls are like http://localhost:46813/Admin/MaterialPaymentRequestSbuItem/CreateChild?parentId=23.
However this practice seems like a bad practice than I cannot pass v variable between two controller methods a process like this:
Controller method(get) ---> View ---> Controller method(post)
Currently I feel a bit stuck in MVC!
i hope i got your point right, you can use an #Html.hiddenfor(model => model.ParentId) in your view it will store ParentId value from query string and when user submits form will be posted to POST method so you dont need to look into url to get it. use a viewmodel with ParentId property and do as below
public class MaterialPaymentsViewModel {
//other properties
public int ParentId {get;set;}
}
public ActionResult CreateChild(int? parentId)
{
var model = new MaterialPaymentsViewModel{ParentId = parentId};
//other stuff
return View(model);
}
//View
#using (Html.beginform()){
//
#html.hiddenfor(m => m.ParentId)
//submit
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild(MaterialPaymentsViewModel model)
{
if(model.ParentId != null)
{
//
}
//
}