Passing viewModel when redirecting in ASP.NET MVC 4 - asp.net-mvc-4

I have below statement:
return Redirect(this.Request.UrlReferrer.AbsolutePath);
this redirects to the caller view. It is working ok, but now I need to return a view model when redirecting, something like this (it's wrong):
return Redirect(this.Request.UrlReferrer.AbsolutePath(item));
So how can I achieve this?
I want to do this because I have a jqrid in which one of its columns offers some actions, edit and delete the row. So if user clicks on edit, i retrieve some data from the id passed to the database. Then once I get this data, I populate a view model in order to update some textboxes in the view, so I need to pass the view model when redirecting.
Below my code in the controller:
public ActionResult Edit(int id)
{
ItemViewModel item = new ItemViewModel();
using (DBContext context = new DBContext())
{
Items itemToModify = context.Items.Single(i=> i.ItemId == id);
item.Desc = itemToModify.Desc;
item.Name = itemToModify.Name;
}
return Redirect(this.Request.UrlReferrer.AbsolutePath, item); <-- how to do this
}

You can use TempData like
In your controller
public ActionResult Action1()
{
ItemViewModel item = new ItemViewModel();
TempData["item"] = item;
return Redirect("Action2");
}
public ActionResult Action2()
{
ItemViewModel item = (ItemViewModel)TempData["item"];
//Your Code
}

Related

ASP.net Core, redirect to Index method with error message from another method

From this method I want to redirect to index method with error message.
ModelState.AddModelError(String.Empty,"Item can't be deleted, item in use in expense.");
return RedirectToAction("Index");
Index method is SQL query with view model -
public async Task<IActionResult> Index()
{
var itemList = (from i in _context.Item
join ui in _context.UserItems
on i.ItemId equals ui.ItemId
//where i.ItemStatus.Equals(1)
where ui.userId.Contains(getLoggedInUserId())
select new ItemViewModel
{
Item = i
});
return await Task.FromResult(View(itemList));
}
RedirectToAction("Index") doesn't redirect with error message.
Thanks in Advance.
Or you can use TempData if the Index method doesn't accept any parameter:
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
TempData["ErrorMessage"] = "Item can't be deleted, item in use in expense.";
return RedirectToAction("Index");
Index method:
public async Task<IActionResult> Index()
{
if (TempData.ContainsKey("ErrorMessage"))
{
ModelState.AddModelError(String.Empty, TempData["ErrorMessage"].ToString());
}
var itemList = (from i in _context.Item
join ui in _context.UserItems
on i.ItemId equals ui.ItemId
//where i.ItemStatus.Equals(1)
where ui.userId.Contains(getLoggedInUserId())
select new ItemViewModel
{
Item = i
});
return await Task.FromResult(View(itemList));
}
ASP.NET Core is by default stateless which means ModelState is not keeping the state between requests. So when you redirect from one controller action to another, you need to pass along the values together with the redirection request. One way to do this is using query parameters - also referred to as "route values" in ASP.NET Core:
return RedirectToAction("Index", new { ErrorMessage = "Item can't be deleted, item in use in expense." });
Then your Index method needs to accept the ErrorMessage as a parameter:
public async Task<IActionResult> Index(string ErrorMessage)
{
var itemList = (from i in _context.Item
join ui in _context.UserItems
on i.ItemId equals ui.ItemId
//where i.ItemStatus.Equals(1)
where ui.userId.Contains(getLoggedInUserId())
select new ItemViewModel
{
Item = i
});
// Add the message to the ModelState if need be
ModelState.AddModelError(String.Empty, ErrorMessage)
return await Task.FromResult(View(itemList));
}

Send Parent ViewData to Partial that is rendered in javascript

I am using asp .net core 3, I add some multiple partial via javascript
function AddBill(type)
{ tag = "....."; // some div and a tags
$.get('/Glasses/DisplayFarBill?index=' + farIndex,
function (partial) {
$('#FarSightedBillsSection').append(tag);
$('#farSighted' + farIndex).append(partial);
$('#farSighted' + farIndex).collapse('show');
farIndex++;
});
}
I have multiple ViewData property on parent that has filled in controller via db context, if I add partialview with tag, partials recognize parent ViewData, but when I add them via javascript, they don't and I should again fill them in action and access to db multi times.
public ActionResult DisplayFarBill(int index)
{
ViewData["Index"] = index;
//ViewData["LenseCover"] = new SelectList(_context.LenseCover, "Id", "Name");
//ViewData["FrameBrand"] = new SelectList(_context.FrameBrand, "Id", "Name");
//ViewData["FrameModel"] = new SelectList(_context.FrameModel, "Id", "Name");
//ViewData["LenseBrand"] = new SelectList(_context.LenseBrand, "Id", "Name");
BillFarSighted billFarSighted = new BillFarSighted
{
PackFactor = 1,
LenseCoverId = 2
};
return PartialView("BillFarSighted", billFarSighted);
}
how can I send Parent ViewData to partial?
I have multiple ViewData property on parent that has filled in
controller via db context, if I add partialview with tag, partials
recognize parent ViewData, but when I add them via javascript, they
don't and I should again fill them in action and access to db multi
times.
The reason why you can use the partialview tag to get ViewData at once is because the partialview tag is carried out at the same time when the view is loaded, and it is only loaded once.
But when you use ajax to get the partialview, the program will enter another action here is DisplayFarBill, which will make the previously stored ViewData value disappear.
If you don't want to get the data again in the DisplayFarBill action, you can use TempData to store it.
It should be noted that the TempData storage model needs to be serialized into a json string for transmission, and remember to add TempData.Keep() in partial view to keep data for next using.
For the specific difference between TempData and ViewData, please refer to: TempData vs ViewData
The following is the example where I use TempData:
public IActionResult Index()
{
var data= new SelectList(_context.LenseCover, "Id", "Name");
TempData["LenseCover"] = JsonConvert.SerializeObject(data);
return View();
}
public ActionResult DisplayFarBill(int index)
{
ViewData["Index"] = index;
BillFarSighted billFarSighted = new BillFarSighted
{
PackFactor = 1,
LenseCoverId = 2
};
return PartialView("BillFarSighted", billFarSighted);
}
BillFarSighted partial view:
#using Newtonsoft.Json;
#model BillFarSighted
#Html.DropDownList("LenseCover", JsonConvert.DeserializeObject<List<SelectListItem>>(TempData["LenseCover"].ToString()).ToList())
#{TempData.Keep();}
Here is the test result:

I need to update the model view and reflect those changes in database

Here,I have a strongly typed view in which I'm showing the registered user his/her data in a form which will allow for updating edited data and make those changes reflected back to database.
I have written all the code for the action methods in both the GET and POST method accordingly but i can't figure out what's causing the issue.The issue is that the changes i made on the view page binded to the model class are not reflected back to the database table though i have written the method db.submit changes().
Below is my code:
GET and POST action methods for the Detailsupdate view page:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult PatientDetailsPage2(Patients p)
{
if (ModelState.IsValid)
{
tblPatient updatedpatientdetail = new tblPatient()
{
PatientName = p.PatientName,
PatientAge = (short) p.Age,
PatientMail = p.PatientEmail,
PatientMobileNo = p.PatientMobileNo,
PatientPassword = p.PatientPassword
};
db.SubmitChanges();
return View();
}
else
{
ViewBag.ErrorMessage = "Please ensure all the fields are filled correctly";
}
return View();
}
public ActionResult PatientDetailsPage2()
{
if(TempData["doc"] != null)
{
var data = (Patients)TempData["doc"];
return View(data);
}
return View();
}
Also I would mention that when i place debug and scan for updated values it shows the updated value at the point where the model's object is assigned into the table parameters but as soon as the submit changes line code is scanned it shows the old value for password field(the field value which i want to be updated here).Please help me programmers!
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult PatientDetailsPage2(Patients p)
{
if (ModelState.IsValid)
{
tblPatient updatedpatientdetail = new tblPatient()
{
PatientName = p.PatientName,
PatientAge = (short) p.Age,
PatientMail = p.PatientEmail,
PatientMobileNo = p.PatientMobileNo,
PatientPassword = p.PatientPassword
};
db.Patients.Add(updatedpatientdetail);
db.SubmitChanges();
return View();
}
else
{
ViewBag.ErrorMessage = "Please ensure all the fields are filled correctly";
}
return View();
}
you must add your model object to Db Model before save.

I want to keep 2 values for next save from preivous save. MVC 4

User enters PWS (public water system), LabID. Then clicks Save button.
I would like these values to populate the new input form that right now gets emptied out on a succesful save.
#Html.TextBoxFor(model => model.PWS, new { #autofocus = "autofocus", #style="width:50px", #maxlength="5" })
Controller ActionResult
First time through:
[HttpGet]
public ActionResult AddColiform(string sortorder)
{
int batchid;
batchid = Convert.ToInt32(Session["ThisBatch"]);
//Session["ThisBatch"] = batchid;
ViewBag.Methods = FillMethods();
ViewBag.Latest = (from m in _db.BactiBucket
where m.Batch_ID == batchid
select m).ToList();
ViewBag.ThisBatch = batchid;
return View(new BactiBucket());
}
When Save button clicked:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddColiform(BactiBucket bucket)
{
if (ModelState.IsValid)
{
//FIRST RECORD SAVED FOR USER CREATES BATCH, OTHERWISE BATCH IS ZERO
if (Session["ThisBatch"].Equals(0))
{
var newbatchid = CheckAndMakeBatchIfNone();
Session["ThisBatch"] = newbatchid;
bucket.Batch_ID = newbatchid;
}
_db.AddToBactiBucket(bucket);
_db.SaveChanges();
return RedirectToAction("AddColiform");
}
ViewBag.Methods = FillMethods();
int batchid;
batchid = Convert.ToInt32(Session["ThisBatch"]);
ViewBag.ThisBatch = batchid;
ViewBag.Latest = (from m in _db.BactiBucket
where m.Batch_ID == batchid
select m).ToList();
return View(bucket);
}
You can pass additional parameters to your GET method in the redirect, and use ths values to set the properties of your model (note its not clear why your method has a parameter string sortorder when you never use it)
[HttpGet]
public ActionResult AddColiform(string sortorder, string PWS, string LabID)
{
....
BactiBucket model = new BactiBucket() { PWS = PWS, LabID = LabID };
return View(model);
}
[HttpPost]
public ActionResult AddColiform(BactiBucket bucket)
{
if (ModelState.IsValid)
{
....
return RedirectToAction("AddColiform", new { PWS = bucket.PWS, LabID = bucket.LabID });
}
....
}
Ok, if it was a snake it would have bit me.
In the declaration of the ActionResult I pass the values of the textboxes to the controller. It comes in with the Post action. (PWS and LabID are the names of the inputs).
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddColiform(BactiBucket bucket, string PWS, string LabID)
Then right before the return RedirectToAction("AddColiform");
I set Session variables for each value:
Session["PWS"]=PWS;
Session["LabID"]=LabID;
of course I might use ViewBag.PWS and ViewBag.LabID
Then, when returning and building the new Add Record form,
I populate the #Value of each textbox respectfully:
#Html.TextBoxFor(model => model.PWS, new {#Value=Session["PWS"], #autofocus = "autofocus", #style="width:50px", #maxlength="5" })
#Html.TextBoxFor(model => model.LabID, new {#Value=Session["LabID"], #style="width:150px", #maxlength="20" })
Since I haven't run this code I know I will have to check if Session objects aren't null. Or ViewBag objects. Or set them to "" first time through.
I got this from this forum thread

ASP.NET MVC , proper way to persist dynamic selectList?

I am learning on MVC4+EF 5.0 project, i using VS2012 default template to create blank project and scaffolding the database to *.edmx model, and a edit view which use for edit a staff working on which company.
I experience a problem is maintenance the SelectList in edit view(Dropdown) when user fail input and return to it.
The DropDownList bind the ListItem from controller:
Edit.cshtml
#Html.DropDownListFor(model => model.CompanyID, (SelectList)ViewData["CompanySelectList"])
MemberController.cs
[HttpGet]
public ActionResult Edit(int SelectedCompanyID = 0, int StaffID = 0)
{
IQueryable<company_benefit> companys = from c in db.company where c.ID.Equals(CompanyID) select c ;
ViewData["CompanySelectList"] = new SelectList(companys, "ID", "Name", SelectedCompanyID);
staff s = db.staff.Find(StaffID);
if (s == null)
{
return HttpNotFound();
}
return View(s);
}
[HttpPost]
public ActionResult Edit(staff s)
{
if (ModelState.IsValid)
{
db.Entry(s).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index"); //Edit Success
}
return View(s); //Edit Fail
}
If someone submit the form with invalid data resulting fail input, It will return the view.
However, the SelectList is bind from ViewData, so the ViewData will gone when the page is loaded, and it is behavior of viewdata ,and i change to TempData is not help too.
So do i need build the SelectList again when Post to Edit Action?
I concern to use session to store that, but afriad to break to MVC design pattern.
My english is not good, sorry for confusion.
Thanks you.
A quick solution is In your http post method for edit again create your view data
[HttpPost]
public ActionResult Edit(staff s)
{
if (ModelState.IsValid)
{
db.Entry(s).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index"); //Edit Success
}
IQueryable<company_benefit> companys = from c in db.company where c.ID.Equals(CompanyID) select c ;
ViewData["CompanySelectList"] = new SelectList(companys, "ID", "Name", SelectedCompanyID);
return View(s); //Edit Fail
}
What you are doing is basically saying that when you return from your edit view to the server then server should rebuild view data and call the same view so it can populate the list.
There is a better way where you can create a model which includes both your current model and a list<companys> companies = new list<companys>(); and then populate it again from database. Again the concept is same just using strongly typed model.