Searching with a dropdown list in asp.net MVC - c#

I'm new to ASP.NET MVC. I want to use selected items from my dropdownlist to search my database table. The dropdownlist was generated from a BOL model which automatically binds to the view.
Below are my code snippet
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BLL;
using BOL;
namespace DentiCareApp.Areas.Admin.Controllers
{
[AllowAnonymous]
public class GenerateInvoiceController : Controller
{
private TreatmentBs objBs;
public GenerateInvoiceController()
{
objBs = new TreatmentBs();
}
// GET: Admin/GenerateInvoice
public ActionResult Index(string CompanyID)
{
DentiCareEntities db = new DentiCareEntities();
ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "CompanyName");
if (CompanyID == null)
{
return View();
}
else
{
return View(db.Treatments.Where(x => x.Company == CompanyID.Take(50)));
}
//return View();
}
Also below is the interface of view.
Secondly, I also want the search result to appear on the same page. How do I do this? If I create a separate action for this, I will need to create a separate view for it. Can partial view be used? If so how?
Below is the code to the View
#model BOL.GenerateInvoice
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<p></p>
<p></p>
<p></p>
<h2>Quickly Generate Invoice</h2>
#using (Html.BeginForm("Index", "GenerateInvoice", FormMethod.Get))
{
#Html.AntiForgeryToken()
<div class="">
<div>
#Html.DropDownList("MyCompany.CompanyId", (IEnumerable<SelectListItem>)ViewBag.CompanyId, "Select Company", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.MyCompany.CompanyId, "", new { #class = "text-danger" })
<input type="submit" value="Search" class="btn btn-primary" />
</div>
</div>
}

Try this.
Controller action:
public ActionResult Index(string CompanyID)
{
DentiCareEntities db = new DentiCareEntities();
ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "CompanyName", CompanyID); // preselect item in selectlist by CompanyID param
if (!String.IsNullOrWhiteSpace(CompanyID))
{
return View();
}
return View(db.Treatments.Where(x => x.CompanyID == CompanyID).Take(50));
}
View code:
#model IEnumerable<Treatment>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Quickly Generate Invoice</h2>
#using (Html.BeginForm("Index", "GenerateInvoice", FormMethod.Get))
{
#Html.AntiForgeryToken()
#Html.DropDownList("CompanyId", (SelectList)ViewBag.CompanyId, "Select Company", new { #class = "form-control" })
<input type="submit" value="Search" class="btn btn-primary" />
}
#if(Model != null && Model.Any())
{
foreach(var item in Model)
{
#Html.DisplayFor(model => item)
}
}
You can change the DisplayFor() here to show individual properties of the given Treatment, such as #Html.DisplayFor(model => model.TreatmentID) and such

The Above code worked for me but with little tweaks. Here are few modification I made to your code.
The parameter in the Index Action was changed from string to integer.
The Optional Parameter in the ViewBag.CompanyId was removed.
Lastly, the line if (!String.IsNullOrWhiteSpace(CompanyID)) and changed to if (CompanyID == 0) { return View(treatmentList);}
The result however is great as it worked like a charm! Thanks for your help!
// GET: Admin/ListTreatment
public ActionResult Index(string sortOrder, string sortBy, string Page, int CompanyID = 0)
{
ViewBag.sortOrder = sortOrder;
ViewBag.sortBy = sortBy;
var treatmentList = objBs.GetALL();
//ViewBag.employeeCompany = employeeCompany.Distinct();
switch (sortOrder)
{
case "Asc":
treatmentList = treatmentList.OrderBy(x => x.TreatmentDate).ToList();
break;
case "Desc":
treatmentList = treatmentList.OrderByDescending(x => x.TreatmentDate).ToList();
break;
default:
break;
}
ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "CompanyName");
ViewBag.TotalPages = Math.Ceiling(objBs.GetALL().Where(x=>x.CompanyId > 0).Count()/10.0);
int page = int.Parse(Page == null ? "1" : Page);
ViewBag.Page = page;
treatmentList = treatmentList.Skip((page - 1) * 10).Take(10);
if (CompanyID == 0)
{
return View(treatmentList);
}
return View(db.Treatments.Where(x => x.CompanyId == CompanyID).Take(50));
}

First : for entity framework id should be nullable, so it can be accepted as argument, the action parameter should be int? CompanyID
Second : the comparison is not correct with (CompanyID == 0)
It should be (CompanyID == null)

Related

my search button goes to the wrong function

My Get function works fine and the search textbox shows but when I enter the user ID and click search, it goes directly to the post function. It is supposed to go to the Get function again to show the data . after the data shows and whether I selected from the checkboxes or not, I click save and then it is supposed to go to the POst function.
What am I doing wrong?
GET function :
[HttpGet]
public ActionResult Index(int? SearchId)
{
var viewModel = new UserViewModel();
if (SearchId != null)
{
var userDepartments = db.TBL_User_Dep_Access.Where(x => x.UserID == SearchId).Select(x => x.Dep_ID).ToList();
List<UserDepartmentViewModel> udeptVM = db.TBL_Department.Select(i => new UserDepartmentViewModel
{
Dep_Id = i.Department_ID,
Dep_Name = i.Department_Name,
IsChecked_ = userDepartments.Contains(i.Department_ID)
}).ToList();
var userPermissions = db.TBL_UserPermissions.Where(x => x.UserID == SearchId).Select(m => m.PermissionID).ToList();
List<UsrPERViewModel> upVM = db.TBL_Permissions.Select(i => new UsrPERViewModel
{
Id = i.PermissionID,
Name = i.PermissionName,
IsChecked = userPermissions.Contains(i.PermissionID)
}).ToList();
viewModel.Departments = udeptVM;
viewModel.Permissions = upVM;
}
return View(viewModel);
}
My View:
#model Staff_Requisition.Models.UserViewModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<style>
.list-group {
max-height: 300px;
margin-bottom: 10px;
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
</style>
#using (Html.BeginForm("Index", "TBL_UserPermission"))
{
#Html.AntiForgeryToken()
<body class="nav-md">
<div class="container body">
<div class="main_container">
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-right top_search">
<div class="input-group">
#Html.TextBox("SearchId", "", null, new { #id = "SearchId", #placeholder = "Search for...", #class = "form-control" })
<span class="input-group-btn">
<input class="btn btn-default" value="Search" type="submit">Go! />
</span>
<ul>
#if (Model.Permissions != null)
{
foreach (var P in Model.Permissions)
{
<li>
<p>
#Html.CheckBoxFor(modelItem => P.IsChecked, new { #class = "flat", #value = P.IsChecked })
#Html.DisplayFor(modelItem => P.Name, new { #class = "DepartmentName", #value = P.Name })
#Html.HiddenFor(modelItem => P.Id, new { #class = "Dep_Id", #value = P.Id })
</p>
</li>
}
}
</ul>
<ul class="to_do">
#if (Model.Departments != null)
{
foreach (var D in Model.Departments)
{
<li>
<p>
#Html.CheckBoxFor(modelItem => D.IsChecked_, new { #class = "flat", #value = D.IsChecked_ })
#Html.DisplayFor(modelItem => D.Dep_Name, new { #class = "DepartmentName", #value = D.Dep_Name })
#Html.HiddenFor(modelItem => D.Dep_Id, new { #class = "Dep_Id", #value = D.Dep_Id })
</p>
</li>
}
}
</ul>
<div class="col-xs-12 col-sm-6 emphasis">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</body>
}
My POST function:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(UserViewModel user_Pers)
{
//remove user with specified ID from database
db.TBL_UserPermissions.RemoveRange(db.TBL_UserPermissions.Where(c => c.UserID == user_Pers.SearchId));
db.TBL_User_Dep_Access.RemoveRange(db.TBL_User_Dep_Access.Where(c => c.UserID == user_Pers.SearchId));
//for each permission that's checked add user to the table
foreach (var u in user_Pers.Permissions)
{
if (u.IsChecked)
{
TBL_UserPermissions Tup = new TBL_UserPermissions();
Tup.UserID = user_Pers.SearchId;
Tup.PermissionID = u.Id;
Tup.IsActive = true;
db.TBL_UserPermissions.Add(Tup);
}
}
db.SaveChanges();
foreach (var d in user_Pers.Departments)
{
if (d.IsChecked_)
{
TBL_User_Dep_Access Tud = new TBL_User_Dep_Access();
Tud.UserID = user_Pers.SearchId;
Tud.Dep_ID = d.Dep_Id;
Tud.IsActive = true;
db.TBL_User_Dep_Access.Add(Tud);
}
}
db.SaveChanges();
return RedirectToAction("myInfo");
}
BTW I removed most of the div in the view manually for simplicity, so it's okay if an opening or closing doesn't match.
As has been pointed out in the comments, in your code you have 1 form whereas to solve the problem you are talking about you need 2 forms. One form responsible for the search get request and the other responsible for the user post.
Here is a simple example of a search form and an update form on the same page.
The viewmodel and controller
using System.Web.Mvc;
namespace SearchAndSubmit.Controllers
{
public class UserViewModel
{
public int? Id { get; set; }
public string Name { get; set; }
}
public class HomeController : Controller
{
[HttpGet]
public ActionResult Edit(int? SearchId)
{
var viewModel = new UserViewModel();
if (SearchId != null)
{
viewModel.Id = SearchId;
//logic to search for user and create viewmodel goes here
}
return View(viewModel);
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Edit(UserViewModel user_Pers)
{
//validation and create update logic goes here
return RedirectToAction("Index");
}
}
}
The view
#model SearchAndSubmit.Controllers.UserViewModel
#{
ViewBag.Title = "Edit/create user";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>#ViewBag.Title</h2>
#*This is the search form it does a get request*#
#using (Html.BeginForm("edit", "home", FormMethod.Get))
{
#Html.TextBox("SearchId", "", null, new { #id = "SearchId", #placeholder = "Search for...", #class = "form-control" })
<span>
<input value="Search" type="submit">
</span>
}
#*This is the form for updating the user it does a post*#
#using (Html.BeginForm("edit", "home", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(c => c.Id)
<p>
#Html.LabelFor(c => c.Name)
#Html.TextBoxFor(c => c.Name)
</p>
<div>
<input type="submit" value="Save" />
</div>
}

how to get one item of the list in a foreach ViewBag mvc 5

I want to get all the student have the ContractStatus == "Pending" in foreach and make a link to Edit the student
<div class="row">
#{ foreach (var studentCohort in ViewBag.CohortSubscriptionId)
{
<div class="col-md-5">
#{
var link = Html.ActionLink((string) studentCohort.ContractStatus, "Edit", "CohortSubscriptions", new { id = (object) studentCohort.ContractStatus }, new { #class ="form-control"});
var contractStatus = studentCohort.ContractStatus == "Pending" ? link : studentCohort;
}
#studentCohort.FullName (#studentCohort.contractStatus)
</div>
}
}
</div>
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Cohorts cohorts = db.Cohorts.Find(id);
if (cohorts == null)
{
return HttpNotFound();
}
var studentByCohort = db.Enrolled_Students.Where(x => x.CohortId == id).Select(x => new StudentCohortViewModel
{
CohortId = x.CohortId,
FirstName = x.FirstName,
LastName = x.LastName,
ContractStatus = x.ContractStatus
}).Distinct().ToList();
ViewBag.CohortSubscriptionId = studentByCohort;
return View(cohorts);
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''CodeboxxSchoolPortal.Models.StudentCohortViewModel' does not contain a definition for 'contractStatus''
Your choice in variable names and reassignments are hurting you here. Consequently, you're getting your types mixed and the errors you experience.
Instead of the ternary conditional (c ? a : b), I suggest using basic if/else which is easier to read and write.
<div class="row">
#foreach(StudentCohortViewModel studentCohort in ViewBag.CohortSubscriptionId)
{
if (studentCohort.ContractStatus == "Pending")
{
<text>
#studentCohort.FullName (#Html.ActionLink(studentCohort.ContractStatus,
"Edit",
"CohortSubscriptions",
new { id = student.ContractStatus },
new { #class = "form-control" }))
</text>
}
else
{
<text>
#studentCohort.FullName (#studentCohort.ContractStatus)
</text>
}
}
</div>
To help with identifying the correct type, instead of var studentCohort use the more explicit StudentCohortViewModel studentCohort.
change
(#studentCohort.contractStatus)
to
(#studentCohort.ContractStatus)
in your Razor view.

Pass data between several views in MVC applications

I am creating a MVC application and I would like to pass data between views.
Here is my first view:
#model ClassDeclarationsThsesis.Models.AddGroupViewModel
#{
ViewBag.Title = "Add Groups";
}
<h2>Add Groups to subjects</h2>
#foreach (var user in Model.Users)
{
if (user.email.Replace(" ", String.Empty) == HttpContext.Current.User.Identity.Name)
{
if (user.user_type.Replace(" ", String.Empty) == 3.ToString() || user.user_type.Replace(" ", String.Empty) == 2.ToString())
{
using (Html.BeginForm("AddGroup", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create new groups.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#{
List<SelectListItem> listItems1 = new List<SelectListItem>();
}
#foreach (var subject in Model.Subjects)
{
listItems1.Add(new SelectListItem
{
Text = subject.name,
Value = subject.name,
Selected = true
});
}
#Html.LabelFor(m => m.subject_name, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.subject_name, listItems1, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.qty, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.qty, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
}
if (user.user_type.Replace(" ", String.Empty) == 1.ToString())
{
<p>You do not have enough permissions to enter this page. Contact the administrator.</p>
}
}
}
And my controller for this:
public ActionResult AddGroup(AddGroupViewModel model)
{
var entities = new ClassDeclarationsDBEntities1();
var model1 = new AddGroupViewModel();
model1.Subjects = entities.Subjects.ToList();
model1.Users = entities.Users.ToList();
// set your other properties too?
if (ModelState.IsValid)
{
return RedirectToAction("AddGroupsQty", "Account");
}
return View(model1);
}
And what I would like to achieve is to pass chosen item from dropdown list and this qty variable to AddGroupsQty View. How do I do this? In my controller of AddGroupsQty i have just a simple return of view so far.
You can pass the values using querystring.
return RedirectToAction("AddGroupsQty", "Account",
new { qty=model.qty,subject=model.subject_name);
Assuming your AddGroupsQty have 2 parameters to accept the quantity and subject
public ActionResult AddGroupsQty(int qty,string subject)
{
// do something with the parameter
// to do : return something
}
This will make browser to issue a new GET request with the values in query string. If you do not prefer to do that, you can use a server side temporary persistence mecahnism like TempData
TempData["qty"]=model.qty;
TempData["subject"]= model.subject_name;
return RedirectToAction("AddGroupsQty", "Account");
And in your AddGroupsQty action,
public ActionResult AddGroupsQty()
{
int qty=0;
string subjectName=string.Empty;
if(TempData["qty"]!=null)
{
qty = Convert.ToInt32(TempData["qty"]);
}
if(TempData["subject"]!=null)
{
subjectName = TempData["subject"];
}
// Use this as needed
return View();
}
If you want to pass these values from the ADdGroupsQty action to it's view, you can use either a view model or ViewBag/ViewData.

Pass dropdown lselected item back to controller

I am trying to pass the selected item in a dropdown list back to the controller to fire a stored procedure.
Controller that populates the list:
public ActionResult Activate()
{
var query = db.Certificates
.Where(a => a.Active == "Y")
.Select(cer => cer.CertificateNumber.Substring(0, 4))
.Distinct()
.OrderBy(cer => cer);
ViewBag.BoxNumber = new SelectList(query.ToList());
return View();
}
View I want tet the value from.
#{
ViewBag.Title = "Activate";
}
<h2>#ViewBag.Title.</h2>
<h3>#ViewBag.Message</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.DropDownList("BoxNumber", String.Empty)
<input type="submit" value="Activate" class="btn btn-default" />
}
Action I want to use it in:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Activate(string BoxNumber)
{
var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["GrandCelebration"].ConnectionString);
var command = new SqlCommand("ActivateCertificates", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#BoxNumber", BoxNumber);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
return RedirectToAction("Activate");
}
The selected item is not being returned.

How to change the value in Html.TextBox for using Jquery and Json?

In the create view what i am trying to do is when you choose a name from the dropdown list to fill the Login html.TextBoxFor automatically with his details.
Currently the Login textbox remains empty when i choose a person from dropdown list.
So i ve got my json object and tested as well my sql which is fine so i suppose the issue must be somewhere in jquery.
I would be glad if you could help me find the error.
View :
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">#Html.LabelFor(model => model.UserLogin)</div>
<div class="editor-field">#Html.TextBoxFor(model => model.UserLogin, new {id ="LoginId" })
#Html.ValidationMessageFor(model => model.UserLogin)</div>
<div class="editor-label">#Html.LabelFor(model => model.UserFullName)</div>
<div class="editor-field">#Html.DropDownList("UserFullName", ViewBag.UserFullName as SelectList, "Select a User", new { id = "UserID" })
#Html.ValidationMessageFor(model => model.UserFullName)</div>
<p>
<input type="submit"
value="Create" />
</p>
</fieldset> }
<div>#Html.ActionLink("Back to List", "Index")</div>
<script type="text/javascript">
$('#UserID').on('change', function () {
$.ajax({
type: 'POST',
url: '#Url.Action("GetUserForm")',
data: { FullName: $('#UserID').val() },
success: function (results){
var login = $('#LoginId');
login.empty();
$.each(results, function ()
{
login.val(this.ID).text(this.Value);
});
}});
});
</script>
Controller:
public ActionResult Create()
{
var names = StaffDB.StaffData.AsEnumerable().Select(s => new
{
ID = s.ID,
FullName = string.Format("{0} {1}", s.Forename1, s.Surname)
}).ToList();
if(ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.UserFullName = new SelectList(names, "FullName", "FullName", user.UserFullName);
return View(user);
}
[HttpPost]
public JsonResult GetUserForm(string FullName)
{
//pseudo code
var data = from s in StaffDB.StaffData
where s.Forename1 + ' ' + s.Surname == FullName
select new
{
Value = s.Login,
ID = s.ID
};
return Json(data);
}
I think the issue is while returning the json, In MVC by default Jsonresult is "Deny get", so you have add "Allow Get".
[HttpPost]
public JsonResult GetUserForm(string FullName)
{
//pseudo code
var data = from s in StaffDB.StaffData
where s.Forename1 + ' ' + s.Surname == FullName
select new { Value = s.Login, ID = s.ID };
if (data == null)
return Json(null);
return Json(data , JsonRequestBehavior.AllowGet);
}

Categories