I want to keep 2 values for next save from preivous save. MVC 4 - asp.net-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

Related

After trying to update records I get "Value cannot be null"

After I want to update a user records and when I press Update button I get
An unhandled exception occurred while processing the request.
ArgumentNullException: Value cannot be null.
Parameter name: source
System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, TResult> selector)
Here is my function for updated user record:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, AppointmentDetailsViewModel objAppointmentVM)
{
if(ModelState.IsValid)
{
objAppointmentVM.Appointment.AppointmentDate = objAppointmentVM.Appointment.AppointmentDate
.AddHours(objAppointmentVM.Appointment.AppointmentTime.Hour)
.AddMinutes(objAppointmentVM.Appointment.AppointmentTime.Minute);
var appointmentFromDb = _db.Appointments.Where(a => a.Id == objAppointmentVM.Appointment.Id).FirstOrDefault();
appointmentFromDb.CustomerName = objAppointmentVM.Appointment.CustomerName;
appointmentFromDb.CustomerEmail = objAppointmentVM.Appointment.CustomerEmail;
appointmentFromDb.CustomerPhoneNumber = objAppointmentVM.Appointment.CustomerPhoneNumber;
appointmentFromDb.AppointmentDate = objAppointmentVM.Appointment.AppointmentDate;
appointmentFromDb.isConfirmed = objAppointmentVM.Appointment.isConfirmed;
if(User.IsInRole(SD.SuperAdminEndUser))
{
appointmentFromDb.SalesPersonId = objAppointmentVM.Appointment.SalesPersonId;
}
_db.SaveChanges();
return RedirectToAction(nameof(Index));
}
return View(objAppointmentVM);
}
This function is for Drop-Down menu which display the Users from DB
public static IEnumerable<SelectListItem> ToSelectListItemString<T>(this IEnumerable<T> items, string selectedValue)
{
if(selectedValue == null)
{
selectedValue = "";
}
return from item in items
select new SelectListItem
{
Text = item.GetPropertyValue("Name"),
Value = item.GetPropertyValue("Id"),
Selected = item.GetPropertyValue("Id").Equals(selectedValue.ToString())
};
}
Any Idea where I made mistake ?
Maybe your table's column is set to not null.
Go to SQL Server and open your table. In the design table window, check the allow nulls checkbox.
In your item select one of the items is null, and LINQ is failing throwing an argument exception because you're trying to run a selector function on something that is null.

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 select different packages on the basis of states, how to get value

public ActionResult Rajasthan()
{
//List<PackageGallery> all = new List<PackageGallery>();
using (travelAndTourismEntities objentity = new travelAndTourismEntities())
{
List<PackageGallery> all = (from p in objentity.PackageGalleries where p.ParentCategory == "Rajasthan" orderby p.Imageid select p).ToList();
// all = objentity.PackageGalleries.ToList();
return View(all);
}
}
I am writing this query but this is specific to rajasthan only how to make it generalize
You can create a parameter to your action method where you accept the state name you want to use in your filter.
public ActionResult PackageGalleries(string id)
{
var all = new List<PackageGallery>();
using (var db = new travelAndTourismEntities())
{
all = db.PackageGalleries
.Where(s=>s.ParentCategory==id)
.OrderBy(x=>x.ImageId).ToList();
}
return View(all);
}
And you can call it like yourSiteName/yourControllerName/PackageGalleries/rajasthan or yourSiteName/yourControllerName/PackageGalleries/kerala
The last part of the url will be mapped to the id parameter of the action method.

Passing viewModel when redirecting in 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
}

Razor default for dropdown box

I have a drop down list written in Razor for a MVC app I am working on as:
#Html.DropDownList("BillId", "")
However the user does not have to select anything according to the logic of my program (the list is populated with 'Bill' objects in my controller). If they do not select any thing I get an error
The ViewData item that has the key 'BillId' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
How do I write a statement in Razor to return a BillId of 0 if nothing is selected?
I am not sure of the syntax as I have a background in straight java and VB but something alongs the line of
If DropdownBox.SelectedIndex = 0
Else
BillId = DropdownBox.SelectedIndex
End
Controller as follows:
Function Create(id As Integer) As ViewResult
ViewBag.id = id
Dim job As Job = New Job
job.CustomerId = id
job.JobAmount = 0
job.JobDate = Date.Now()
job.JobStatus = "Active"
Dim BillList = New List(Of Bill)()
Dim BillQuery = From s In db.Bills
Select s
BillList.AddRange(BillQuery)
ViewBag.BillIdList = New SelectList(BillList, "BillId", "BillDate")
ViewBag.BillId = New SelectList(BillList, "BillId", "BillDate")
Return View(job)
End Function
The POST function for create is as below:
<HttpPost()>
Function Create(job As Job) As ActionResult
If ModelState.IsValid Then
db.Jobs.Add(job)
db.SaveChanges()
Dim customer As Customer = db.Customers.Find(job.CustomerId)
Dim customerNumber As String = customer.CustCellphone.ToString()
Dim messageSender As SendMessage = New SendMessage
Dim smsMessage As String = "LAUNDRY: Job Number " & job.JobId & " has been booked in. You will be notified when individual services within it are ready for collection."
messageSender.SendMessage(smsMessage, customerNumber)
Dim url As String = "/RequestedService/AddService/" + job.JobId.ToString()
Return Redirect(url)
End If
Return View(job)
End Function
EDIT
I was wondering too how this is passed back as in the POST I may be able to check for a 'null'? However I feel the problem may be the moment the submit button is pressed
In your POST controller action you forgot to populate the ViewCrap (oops, I meant ViewBag) before returning the view:
<HttpPost()>
Function Create(job As Job) As ActionResult
If ModelState.IsValid Then
...
End If
' Here you must populate the ViewCrap before returning the view the same
' way you did in your GET action because your view depend on it
Dim BillQuery = From s In db.Bills
Select s
ViewBag.BillId = New SelectList(BillQuery.ToList(), "BillId", "BillDate")
Return View(job)
End Function
But I would hyper strongly recommend you to use view models and forget about the existence of the ...... (the word that I don't want to pronounce).
UPDATE:
Now let's look at the correct way to implement this (which is by using view models). A view model is a class that you should define for each of your views and which will represent its specific requirements. So from what you have said in the comments section to my answer you want to have a dropdown list in your view where the user has to select a bill from a dropdown and which is required.
So let's roll the view model:
public class JobViewModel
{
[Required(ErrorMessage = "Please select a bill")]
[Display(Name = "Bill")]
public int? SelectedBillId { get; set; }
public IEnumerable<SelectListItem> Bills
{
get
{
return db.Bills.ToList().Select(x => new SelectListItem
{
Value = x.BillId.ToString(),
Text = x.BillDate.ToString()
});
}
}
public int CustomerId { get; set; }
... here you could put any other properties that you want
to display on the view, things like JobId, ...
}
then we define our controller with the 2 actions:
public ActionResult Create(int id)
{
var model = new JobViewModel
{
CustomerId = id
};
return View(model);
}
[HttpPost]
public ActionResult Create(JobViewModel model)
{
if (ModelState.IsValid)
{
// Using AutoMapper here to map between the domain model
// and the view model (http://automapper.org/)
var job = Mapper.Map<JobViewModel, Job>(model);
// Now call your service layer to do the necessary processings
// on this job domain model including saving the job and sending
// messages and stuff. This avoids polluting your controller with
// business logic code which belongs to your service layer
ServiceLayer.ProcessJob(job);
return RedirectToAction("AddService", "RequestedService", new { id = job.JobId });
}
return View(model);
}
and finally you will have a corresponding view which will be strongly typed to the view model:
#model JobViewModel
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.SelectedBillId)
#Html.DropDownListFor(x => x.SelectedBillId, Model.Bills, "-- select --")
#Html.ValidationMessageFor(x => x.SelectedBillId)
</div>
... some other input fields
<p><button type="submit">OK</button></p>
}
And now, as promised in the comments section let me show what I dubbed the absolute pornographic approach to solve this and which if you implemented in your application I will have to ask you to no longer come back and ask any ASP.NET MVC related question on StackOverflow :-)
The pornographic approach consisted into manually inserting an item with id = 0 and text = empty string into the beginning of the list and then inside the controller verifying if the selected id equals 0 in order to check whether the model is valid or not:
So in your GET action:
Function Create(id As Integer) As ViewResult
ViewBag.id = id
Dim job As Job = New Job
job.CustomerId = id
job.JobAmount = 0
job.JobDate = Date.Now()
job.JobStatus = "Active"
Dim Bills = db.Bills.ToList().Select(Function(s) New SelectListItem With { .Value = s.BillId.ToString(), .Text = s.BillDate.ToString() })
Bills.Insert(0, New SelectListItem With { .Value = "0", .Text = "" })
ViewBag.BillId = Bills
Return View(job)
End Function
<HttpPost()>
Function Create(job As Job, BillId as Integer) As ActionResult
If BillId > 0 Then
db.Jobs.Add(job)
db.SaveChanges()
Dim customer As Customer = db.Customers.Find(job.CustomerId)
Dim customerNumber As String = customer.CustCellphone.ToString()
Dim messageSender As SendMessage = New SendMessage
Dim smsMessage As String = "LAUNDRY: Job Number " & job.JobId & " has been booked in. You will be notified when individual services within it are ready for collection."
messageSender.SendMessage(smsMessage, customerNumber)
Dim url As String = "/RequestedService/AddService/" + job.JobId.ToString()
Return Redirect(url)
End If
ModelState.AddModelError("BillId", "Please select a bill")
Return View(job)
End Function
and inside the view:
#Html.DropDownList("BillId")