I have a view where a user will enter an ID that will be passed to a controller method which will then populate a view containing the related patient record.
I am new to MVC and have been unable to get the ID from the textbox and pass it to the controller method. I appreciate any help.
In my view:
#model Final.Models.Patient
#Html.TextBoxFor(model => model.Patient_ID)
#Html.ActionLink("Patient", "Details", new { id=???? })
In my controller:
public ViewResult Details(decimal id)
{
Patient patient = db.Patients.Single(p => p.Patient_ID == id);
return View(patient);
}
Thanks.
I was able to make it work with the following:
#using (#Html.BeginForm("Details", "Patient")) {
#Html.TextBoxFor(model => model.Patient_ID)
<input type="submit", value="Submit"/>
public ActionResult Details(Patient _patient)
{
decimal id = _patient.Patient_ID;
Patient patient = db.Patients.Single(p => p.Patient_ID == id);
return View(patient);
}
Is jQuery method acceptable for you? You can assign an id to the textbox, and then get the value (id entered by user) and then submit to your controller using $.ajax
#Html.TextBoxFor(model => model.PatientID, new { id = "patient"})
$.ajax({
url: '/Home/Details',
type: 'POST',
data: { id: $('#patient').val()},
async: false,
success: function (result) {
alert('success!');
}
});
Hope this help you :)
receive the model in ActionResult instead
#model Final.Models.Patient
#usign (#BeginForm("Details","Controller"){
#Html.TextBoxFor(model => model.Patient_ID)
#Html.ActionLink("Patient", "Details", new { id=???? })
<input type="submit", value="Submit"/>
}
in your controller
[HttpPost]
public ActionResult Details(Patient _patient)
{
decimal id = _patient.Patient_ID
Patient patient = db.Patients.Single(p => p.Patient_ID == id);
return View(patient);
}
Related
My question is two-fold.
I have a View that gets data on the change of a drop down selection.
The data retrieved is a List property of a ViewModel class using an Ajax call.
This data is shown as a selection of check boxes for the user to select any number of them.
If I return a Partial View from an AJAX call, this is easy enough, but from what I have experienced, this doesn't work for POST'ing back to the controller. Nothing is bound correctly.
From what I have read the correct way is to use EditorFor, So firstly, I cannot figure out how to populate the EditorFor from the AJAX call.
Secondly, If I test by sending initial data from my GET, the EditorFor displays the correct checkbox options, but when I POST, the count of the items is 0.
View:
#model EngineeringAssistantMVC.Controllers.FirmwareController.FirmwareViewModel
#using (Html.BeginForm("Upload", "Firmware", FormMethod.Post, new { #id = "uploadFirmwareForm", #class = "form-horizontal" }))
{
<!-- Device -->
<div class="form-group">
<div class="col-lg-1">
#Html.LabelFor(x => x.Device, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-lg-2">
#Html.DropDownListFor(x => x.Device, ViewBag.Devices as IEnumerable<SelectListItem>, new { #class = "form-control", #id = "Devices" })
</div>
<div class="col-lg-9">
#Html.ValidationMessageFor(x => x.Device, "", new { #class = "text-danger" })
</div>
</div>
#Html.EditorFor(x => x.SelectedModels, "SelectedModels", new { #id = "Models" })
#Html.HiddenFor(x => x.SelectedModels)
}
And the AJAX call:
function GetModels() {
$.ajax({
type: "GET",
url: '#Url.Action("GetModels", "Firmware", null)',
data: { SelectedDevice: $('#Devices').val() },
success: function (dataSet) {
//$('#Models').html(dataSet);
//$('#Models').data(dataSet);
//$('#Models').val(dataSet);
// How do I populate the EditorFor from the dataSet returned?
},
error: function (err) {
console.log("ERROR: " + err.responseText);
},
})
}
SelectedModels EditFor Template:
#model IEnumerable<EngineeringAssistantMVC.ViewModels.ModelViewModel>
#foreach (var item in Model)
{
#Html.CheckBoxFor(x => item.IsSelected)
#Html.Label(item.Description)
#Html.HiddenFor(x => item.ModelId)
#Html.HiddenFor(x => item.IsSelected)
#Html.HiddenFor(x => item.Description)
}
Controller:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase uploadFile, FirmwareViewModel firmwareViewModel)
{
// firmwareViewModel.SelectedModels count is 0 here
}
ModelFirmware Class:
public class ModelFirmware
{
public int ModelFirmwareId { get; set; }
public int FirmwareId { get; set; }
public int ModelId { get; set; }
}
FirmwareViewModel:
public class FirmwareViewModel
{
public int FirmwareViewModelId { get; set; }
[Required]
public string Device { get; set; }
public ICollection<ModelViewModel> SelectedModels { get; set; }
}
I just can't get it to work correctly.
EDIT 1: - Add method that returns the models
[HttpGet]
public ActionResult GetModels(string SelectedDevice)
{
var deviceAbbreviation = _dbContext.Radios.Where(x => x.RadioName == SelectedDevice).Select(x => x.ProjectAbbreviation).FirstOrDefault();
var models = _dbContext.AnatomyModels.Where(x => x.SerialPrefix.StartsWith(deviceAbbreviation.Trim()) && x.ParentId == 0).ToList();
List<ModelViewModel> mvms = models.Select(x => new ModelViewModel()
{
ModelId = x.AnatomyModelId,
Description = x.SerialPrefix,
IsSelected = false,
}).ToList();
return Json(mvms);
}
There are numerous issues with your code.
First your not using the EditorTemplate correctly. Change its name to ModelViewModel.cshtml to match the name of the class, and locate it in the /Views/Shared/EditorTemplates (or /Views/YourControllerName/EditorTemplates) folder. The template is then based on a single object (note also the LabelFor() required to create a label associated with the checkbox, and you need to delete the hidden input for IsSelected)
#model ModelViewModel
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Description)
#Html.HiddenFor(m => m.ModelId)
#Html.HiddenFor(m => m.Description)
Refer also Post an HTML Table to ADO.NET DataTable to understand why your foreach loop would never have created the correct name attributes for model binding.
Then in the main view use
<div id="container">
#Html.EditorFor(m => m.SelectedModels)
</div>
and remove the hidden input for SelectedModels (but before you do, inspect the html for that element to understand why its value would never bind). The EditorFor() method will correctly generate the html for each item in your collection.
Next, change your GetModels() method to return a partial view based on FirmwareViewModel since that is what you will be posting back. Note that you could return a JsonResult, but that would mean generating a whole lot of html in the ajax call back that would not be strongly typed.
[HttpGet]
public PartialViewResult GetModels(string SelectedDevice)
{
var deviceAbbreviation = _dbContext.Radios.Where(x => x.RadioName == SelectedDevice).Select(x => x.ProjectAbbreviation).FirstOrDefault();
var models = _dbContext.AnatomyModels.Where(x => x.SerialPrefix.StartsWith(deviceAbbreviation.Trim()) && x.ParentId == 0).ToList();
List<ModelViewModel> mvms = models.Select(x => new ModelViewModel()
{
ModelId = x.AnatomyModelId,
Description = x.SerialPrefix,
IsSelected = false, // not really necessary since its the default
}).ToList();
FirmwareViewModel model = new FirmwareViewModel
{
SelectedModels = mvms
};
return PartialView(model);
}
and your GetModels.cshtml view will be
#model FirmwareViewModel
#Html.EditorFor(m => m.SelectedModels)
Then, modify your ajax call to add the partial view in the success callback
$.ajax({
type: "GET",
url: '#Url.Action("GetModels", "Firmware")', // do not need to add 3rd parameter
data: { SelectedDevice: $('#Devices').val() },
success: function (response) {
$('#container').html(response);
},
error: function (err) {
console.log("ERROR: " + err.responseText);
},
})
The .html() function will replace any elements already existing in the <div id="container"> element
Finally, since your using a view model, make use of it and do not use ViewBag. Your view model should contain a IEnumerable<SelectListItem> Devices property which you populate in the GET method (and use #Html.DropDownListFor(x => x.Device, Model.Devices, new { #class = "form-control" }) in the view (note also that the method generates id="Device"). It should also contain a HttpPostedFileBase property to avoid the additional parameter in the POST method, and allow you to add validation attributes.
I have a few users with roles created in my MVC 5 application. I have a ticket Model which contains basic ticket info. But now I want to add a property called "Assigned To" to this ticket Model and I want to assign this property value to the users available.
In my view I want to have a drop down list of all available Users so I can select a user to assign the ticket to. How can I create this property in my Model and how to make it a drop down list in my view? Thanks
Update 1:
in my Index() method I already have an existing actionresult model to return to view and its like this:
Models.Application model = db.Applications
.Include("Source")
.Include(.....)
.SingleOrDefault(m => m.Id == id);
if (model == null)
{
return new HttpNotFoundResult();
}
return View(model);
How can I incorporate the code you suggest in the Index() method with what I already have?
Query your database to get the list of users, then transpose this into your view model. Make sure you DONT pass the User class directly from the DB as you will send the password, salt etc to the browser. You should transpose it from a DB shape to a VM shape, containing only the fields required in the view.
ViewModel:
class MyViewModel
{
public IEnumerable<User> Users { get; set; }
public string User { get; set;}
}
[HttpGet]
public ActionResult Index()
{
var viewModel = new MyViewModel()
{
Users = <map users from db>
};
return this.View(viewModel);
}
View:
<div class="form-group">
#Html.LabelFor(m => m.User)
<div class="col-md-10">
#Html.DropDownListFor(x => x.User, new SelectList(Model.Users, "Id", "Name"), new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.OriginStation, "", new { #class = "text-danger" })
</div>
</div>
Then your form postback handler:
[HttpPost]
public ActionResult Index(MyViewModel viewModel)
{
viewModel.User now contains the id of the user
}
How to load ValidationSummary using ajax? I was trying to use MVC's ready Membership.
Simple question, but I'm stuck.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[RecaptchaControlMvc.CaptchaValidator]
public ActionResult Register(RegisterModel model, bool captchaValid, string captchaErrorMessage)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
if (captchaValid)
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", captchaErrorMessage);
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
View:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<legend>Registration Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
<input type="hidden" id ="some" value=""/>
</li>etc.
I don't want to redirect each time on for example, if username exists or etc.
To do this you can return a partial view as html. The rendered partial will contain the modelstate errors and therefore will display when returned as html.
Example
Could can create a class called AjaxResult
public class AjaxResult
{
public string Html { get; set; }
public bool Success { get; set; }
}
Then in your success function from the ajax call you can append the html to the appropriate element. e.g.
$.ajax({
url: 'http://bacon/receive',
dataType: "json",
type: "POST",
error: function () {
},
success: function (data) {
if (data.Success) {
$('body').append(data.Html);
}
}
});
this is my Get actionresult :
public ActionResult Add()
{
ViewData["categoryList"]= _categoryRepository.GetAllCategory().
ToSelectList(c => c.Id, c => c.Name);
return View("Add");
}
this my razor that render the categoryList , and I have no trouble with that !
<div>
#Html.LabelFor(b => b.Category)
#Html.DropDownList("Category", ViewData["categoryList"] as IEnumerable<SelectListItem>)
#Html.ValidationMessageFor(b => b.Category)
</div>
finally after submitting the page , category select send via null value to post this action
[HttpPost]
public ActionResult Add(BlogPost blogPost)
{
if (ModelState.IsValid)
{
blogPost.PublishDate = DateTime.Now;
_blogPostRepository.AddPost(blogPost);
_blogPostRepository.Save();
return RedirectToAction("Add");
}
return new HttpNotFoundResult("An Error Accoured while requesting your order!");
}
could anybody tell me why ??
controller
public ActionResult Add()
{
ViewBag.CategoryList = new SelectList(_categoryRepository.GetAllCategory(), "Id", "Name");
// you dont need the specify View name
// like this: return View("Add")
// you need to pass your model.
return View(new BlogPost());
}
view
#Html.DropDownListFor(model => model.CategoryId, ViewBag.CategoryList as SelectList, "--- Select Category ---", new { #class = "some_class" })
controller post action
[HttpPost]
public ActionResult Add(BlogPost blogPost)
{
if (ModelState.IsValid)
{
blogPost.PublishDate = DateTime.Now;
_blogPostRepository.AddPost(blogPost);
_blogPostRepository.Save();
// if you want to return "Add" page you should
// initialize your viewbag and create model instance again
ViewBag.CategoryList = new SelectList(_categoryRepository.GetAllCategory(), "Id", "Name");
return View(new BlogPost());
}
return new HttpNotFoundResult("An Error Accoured while requesting your order!");
}
I have a property in my model very simple one:
Now this dropDown doesn't work right
#Html.DropDownListFor(m => m.Camp, new SelectList(ViewBag.Camps, "Id", "Name"))
it returns null instead of a chosen Camp, but if I change that into:
#Html.DropDownListFor(m => m.Camp.Id, new SelectList(ViewBag.Camps, "Id", "Name"))
It would return me a Camp object with correct Id, but the Name would be still null.
Why?
UPD:
And now another problem is if I choose the second approach it would screw up with unobtrusive validation. Although I'll be able to get the right camp based on the chosen id.
That's normal. Only the Id is posted to the controller action. That's how dropdown inside forms work. So that's all you can hope to get there. You will then use this Id to get the corresponding Camp object from the database:
[HttpPost]
public ActionResult Foo([Bind(Prefix = "Camp")]int id)
{
Camp camp = Repository.GetCamp(id);
...
}
Also please get rid of this ViewBag and use a real view model:
public class CampViewModel
{
public int Id { get; set; }
public IEnumerable<SelectListItem> Camps { get; set; }
}
and in the controller:
public ActionResult Index()
{
var model = new CampViewModel
{
Camps = Repository.GetCamps().Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(int id)
{
Camp camp = Repository.GetCamp(id);
...
}
and the view:
#model CampViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.Id,
new SelectList(Model.Camps, "Value", "Text")
)
<input type="submit" value="OK" />
}