I'm trying to do this:
choose an item in the first ddl, and then appears a list of related items in the second ddl. I'm using this method: How to keep cascade dropdownlist selected items after form submit?
But I can't handle it and something is wrong(with Ajax I guess) and I have only a list of cities for the first ddl, the second ddl is empty. Please, help.
My view:
#model Bike_Store.Models.OrderVM
#{
ViewBag.Title = "Checkout";
}
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<script>
var url = '#Url.Action("FetchAddresses")';
var adresses = $('#Delivery_id');
$('#Cities_id').change(function () {
if (!$(this).val()) {
return;
}
$.getJSON(url, { id: $(this).val() }, function (data) {
adresses.empty().append($('<option></option>').val('').text('-Please select-'));
$.each(data, function (index, bs_delivery_type) {
subLocalities.append($('<option></option>').val(item.Value).text(item.Text));
});
});
});
</script>
#using (#Html.BeginForm())
{
#Html.LabelFor(m=>m.Cities_id)
#Html.DropDownListFor(m=>m.Cities_id, Model.CitiesList, "-Please select-")
#Html.ValidationMessageFor(m=>m.Cities_id)
#Html.LabelFor(m=>m.Delivery_id)
#Html.DropDownListFor(m=>m.Delivery_id, Model.DeliveriesList, "-Please Select-")
#Html.ValidationMessageFor(m=>m.Delivery_id)
}
Model:
public class OrderVM
{
[Required(ErrorMessage = "Address")]
public decimal? Cities_id { get; set; }
[Required(ErrorMessage = "City")]
public decimal? Delivery_id { get; set; }
public SelectList CitiesList { get; set; }
public SelectList DeliveriesList { get; set; }
}
Controller:
private void ConfigureViewModel(OrderVM model)
{
IEnumerable<bs_cities> cities = _db.bs_cities;
model.CitiesList = new SelectList(cities, "cities_id", "cities_name");
if (model.Cities_id.HasValue)
{
IEnumerable<bs_delivery_type> addresses = _db.bs_delivery_type.Where(x => x.delivery_city_id == model.Cities_id.Value);
model.DeliveriesList = new SelectList(addresses, "delivery_id", "delivery_address");
}
else
{
model.DeliveriesList = new SelectList(Enumerable.Empty<SelectListItem>());
}
}
public ViewResult Checkout()
{
OrderVM model = new OrderVM();
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
public ViewResult Checkout(OrderVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
else
{
return View("123");
}
}
public JsonResult FetchSubLocalities(int ID)
{
var bs_delivery_type = _db.bs_cities.Where(x => x.cities_id == ID).Select(c => new
{
Value = c.cities_id,
Name = c.cities_name
});
return Json(bs_delivery_type, JsonRequestBehavior.AllowGet);
}
Related
I have Companies and Vacancies tables.
Company has n number of Vacancies. I need to make two dropdown lists.
In one it will be Company, when I select it, there will be Vacancies related to this company.
Here is model of Companies
public Company()
{
this.Clients = new HashSet<Client>();
this.Vacancies = new HashSet<Vacancy>();
}
[Key]
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Id { get; set; }
public virtual AspNetUser AspNetUser { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Client> Clients { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Vacancy> Vacancies { get; set; }
}
Here is model for Vacancies
public partial class Vacancy
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Vacancy()
{
this.Interviews = new HashSet<Interview>();
}
[Key]
public int VacancyId { get; set; }
public string VacancyName { get; set; }
public Nullable<int> CompanyID { get; set; }
public virtual Company Company { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Interview> Interviews { get; set; }
Here is controller where I need to do this
[HttpGet]
public ActionResult WelcomeScreen()
{
// Формируем список команд для передачи в представление
SelectList teams = new SelectList(db.Vacancy, "VacancyId", "VacancyName");
ViewBag.Teams = teams;
return View();
}
//Заносим инфу о вакансии в таблицу
[HttpPost]
public ActionResult WelcomeScreen(Interview interview)
{
db.Interview.Add(interview);
db.SaveChanges();
//Int32 id = interview.Interview_Id;
//TempData["id"] = id;
return RedirectToAction("Index", "Questions", new { id = interview.Interview_Id });
}
How I need to make Cascade Dropdown list?
UPDATE
I try solution
Here is my controller (Questions controller)
[HttpGet]
public ActionResult WelcomeScreen()
{
// Формируем список команд для передачи в представление
//SelectList teams = new SelectList(db.Vacancy, "VacancyId", "VacancyName");
//ViewBag.Teams = teams;
ViewBag.Companies = new SelectList(db.Companies, "CompanyID", "CompanyName");
return View();
}
//Заносим инфу о вакансии в таблицу
[HttpPost]
public ActionResult WelcomeScreen(Interview interview)
{
db.Interview.Add(interview);
db.SaveChanges();
//Int32 id = interview.Interview_Id;
//TempData["id"] = id;
return RedirectToAction("Index", "Questions", new { id = interview.Interview_Id });
}
public ActionResult Vacancies(int companyId)
{
var items = db.Vacancy
.Where(x => x.CompanyID == companyId)
.Select(x => new SelectListItem
{
Value = x.VacancyId.ToString(),
Text = x.VacancyName
})
.ToList();
return Json(items, JsonRequestBehavior.AllowGet);
}
Here is script
<script>
$(function () {
$("#Company").change(function (e) {
var $vacancy = $("#vacancy");
var url = $vacancy.data("url") + '?companyId=' + $(this).val();
$.getJSON(url, function (items) {
$.each(items, function (a, b) {
$vacancy.append('<option value="' + b.Value + '">' + b.Text + '</option>');
});
});
});
});
</script>
And here is View
<div class="right-grid-in-grid">
<div style="margin-left:20px;">
#Html.DropDownList("Company", ViewBag.Companies as SelectList, new { #class = "greeting"})
#Html.ValidationMessageFor(model => model.VacancyId, "", new { #class = "text-danger" })
</div>
<div style="margin-left:20px;">
<select name="id" id="vacancy" data-url="#Url.Action("Vacancies","Questions")" class="greeting"/>
</div>
</div>
But AJAX not works.
The idea of cascading dropdown is, When you load the page, you load the dropdown content for the first SELECT element. The second SELECT element will be an empty one. When user selects an option from the first dropdown, send that to the server which returns the content needed to build the second dropdown.
So in the GET action of your page, get the data needed to render the first dropdown.
public ActionResult Welcome()
{
ViewBag.Companies = new SelectList(db.Companies, "CompanyID", "CompanyName");
return View();
}
Now in the view, you can use the DropDownList helper method to render the SELECT element with the data we set to the ViewBag.Companies. We will also add our second dropdown as well.
#Html.DropDownList("Company", ViewBag.Companies as SelectList)
<select name="id" id="vacancy" data-url="#Url.Action("Vacancies","Home")">
Now we will use some ajax code(using jQuery in this example) to get the content for the second dropdown. Register an event handler for the change event of the first dropdown, get the selected value, make an ajax call to the Vacancies action method which returns the data needed to build the second dropdown in JSON format. Use this JSON data to build the second dropdown in javascript.
$(function(){
$("#Company").change(function (e) {
var $vacancy = $("#vacancy");
var url = $vacancy.data("url")+'?companyId='+$(this).val();
$.getJSON(url, function (items) {
$.each(items, function (a, b) {
$vacancy.append('<option value="' + b.Value + '">' + b.Text + '</option>');
});
});
});
});
Now the last part is, implementing the Vacancies method.
public ActionResult Vacancies(int companyId)
{
var items = db.Vacancies
.Where(x=>x.CompanyID==comapnyId)
.Select(x => new SelectListItem { Value = x.VacancyId.ToString(),
Text = x.VacancyName })
.ToList();
return Json(items, JsonRequestBehavior.AllowGet);
}
Assuming db is your DbContext class object.
Ajax is not necessary for implementing cascading dropdowns. You can post the form with the selected companyId and the action method can return the same with second dropdown filled. But people usually use ajax to give a nice user experience
I have a problem with using #Html.DropDownListFor element.
What i have:
Model 'DatabaseModel':
public class DirectionEntity
{
public string Id { get; set; }
public string DirectionName { get; set; }
}
public class ViewModel
{
public int SelectedDirectionID { get; set; }
public List<DirectionEntity> DirectionList { get; set; }
}
Model 'DataFactory':
public class DataFactory
{
public static ViewModel Refresh()
{
using (var db = new MyDatabase())
{
return new ViewModel()
{
DirectionList = db.Directions.Select(_ => new { _.Id, _.DirectionName })
.ToList()
.Select(_ => new DirectionEntity() { Id = _.Id.ToString(), DirectionName = _.DirectionName })
.ToList(),
};
}
}
}
Controller:
public System.Web.Mvc.ActionResult AddNewDocument()
{
var db = DataFactory.Refresh();
return View(db);
}
[HttpPost]
public System.Web.Mvc.ActionResult AddNewEntry(ViewModel m)
{
m = DataFactory.Save(m);
ModelState.Clear();
return View(<some view>);
}
View:
#using (Html.BeginForm())
{
#Html.DropDownListFor(m => m.SelectedDirectionID, new SelectList(Model.DirectionList.Select(x => new SelectListItem { Value = x.Id.ToString(), Text = x.DirectionName }), "Value", "Text"), new { #class = "Duration", required = "required" })
<button type="submit" class="btn btn-default SaveAll">Save</button>
}
The question:
How to handle 'SelectedDirectionID' value, after user selected some position on dropdownlist, but not yet sent the request to the server using a POST-method.
See what the id of your dropdown is and then you can subscribe to the change event on the client side. You can do this using jQuery.
$("#idOfYourDropDown").change(function () {
// Do whatever you need to do here
// Here are some ways you can get certain things
var end = this.value;
var selectedText = $(this).find("option:selected").text();
var selectedValue = $(this).val();
alert("Selected Text: " + selectedText + " Value: " + selectedValue);
});
Also you should see my answer here on why you should not return a view from a POST action the way you are.
In this case you have to use Jquery. As per your view id for your drop down is 'SelectedDirectionID';
Your Js:
$(document).ready(function () {
var selectedValue = $('#SelectedDirectionID').val();
var selectedText = $("#SelectedDirectionID option:selected").text();
});
Or Inside drop down change event.
$('#SelectedDirectionID').change(function () {
var selectedValue = $(this).val();
var selectedText = $(this).find("option:selected").text();
});
I am a beginner in programming being stuck the last 2 days on that and i am hopping on your help :)
I am building an mvc 4 app and I have a partial view with a list of departments and when you choose the department you can see the item types for this specific department in a drop down list in Browse view.
What I am trying to make is one more dropdown list in Browse view that will show the items according to the selected department and item types.
So this is my code :
View :
#using (Html.BeginForm("Browse", "Bookings", FormMethod.Post, new { id = "TypeItemFormID", data_itemsListAction = #Url.Action("ItemsList") }))
{
<fieldset>
<legend> Type/Item</legend>
#Html.DropDownList("department", ViewBag.ItemTypesList as SelectList, "Select a Type", new {id="ItemTypeID"})
<div id="ItemsDivId">
<label for="Items">Items </label>
<select id="ItemsID" name="Items"></select>
</div>
<p>
<input type ="submit" value="Submit" id="SubmitID" />
</p>
</fieldset>
}
<script src ="#Url.Content("~/Scripts/typeItems.js")"></script>
The controller :
public class BookingsController : Controller
{
private BookingSystemEntities db = new BookingSystemEntities();
//
// GET: /Bookings/
public ActionResult Index()
{
ViewBag.Message = "Select your Department";
var departments = db.Departments.ToList();
return View(departments);
}
public ActionResult Browse(string department, string ID)
{
ViewBag.Message = "Browse for Equipment";
var departments = db.Departments.Include("Items").Single(i => i.DepartmentName == department);
ViewBag.ItemTypesList = GetItemTypeSelectList(department);
return View();
}
public ActionResult Details(int id)
{
var item = db.Items.Find(id);
return View(item);
}
//
// GET: /Home/DepartmentMenu
[ChildActionOnly]
public ActionResult DepartmentMenu()
{
var departments = db.Departments.ToList();
return PartialView(departments);
}
public SelectList GetItemTypeSelectList(string department)
{
var departments = db.Departments.Include("Items").Single(i => i.DepartmentName == department);
List<SelectListItem> listItemTypes = new List<SelectListItem>();
foreach (var item in departments.Items.Select(s => s.ItemType.ItemTypeName).Distinct())
{
listItemTypes.Add(new SelectListItem
{
Text = item,
Value = item,
}
);
}
return new SelectList(listItemTypes.ToArray(),
"Text",
"Value");
}
public ActionResult ItemsList(string ID)
{
string Text = ID;
var items = from s in db.Items
where s.ItemType.ItemTypeName == Text
select s;
if (HttpContext.Request.IsAjaxRequest())
return Json(new SelectList(
items.ToArray(),
"ItemId",
"ItemName")
, JsonRequestBehavior.AllowGet);
return RedirectToAction("Browse");
}
}
The Javascript :
$(function () {
$('#ItemsDivId').hide();
$('#SubmitID').hide();
$('#ItemTypeID').change(function () {
var URL = $('#TypeItemFormID').data('itemsListAction');
$.getJSON(URL + '/' + $('#ItemTypeID').val(), function (data) {
var items = '<option>Select a Item</option>';
$.each(data, function (i, item) {
items += "<option value='" + item.Value + "'>" + item.Text + "</option>";
// state.Value cannot contain ' character. We are OK because state.Value = cnt++;
});
$('#ItemsID').html(items);
$('#ItemsDivId').show();
});
});
$('#ItemsID').change(function () {
$('#SubmitID').show();
});
});
And at last my Model :
public class Department
{
public int DepartmentId { get; set; }
[DisplayName("Department")]
public string DepartmentName { get; set; }
public List<Item> Items { get; set; }
}
public class ItemType
{
public int ItemTypeId { get; set; }
[DisplayName("Type")]
public string ItemTypeName { get; set; }
[DisplayName("Image")]
public string ItemTypeImage { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public int ItemId { get; set; }
[DisplayName("Name")]
public string ItemName { get; set; }
[DisplayName("Description")]
public string ItemDescription { get; set; }
[DisplayName("Ref Code")]
public string ItemReferenceCode { get; set; }
[ForeignKey("ItemType")]
public int ItemTypeId { get; set; }
public virtual ItemType ItemType { get; set; }
[ForeignKey("Department")]
public int DepartmentId { get; set; }
public Department Department { get; set; }
[DisplayName("Computer Location")]
public string ComputerLocation { get; set; }
[DisplayName("Author Name")]
public string AuthorName { get; set; }
[DisplayName("Published Year")]
public string PublishedYear { get; set; }
}
Here's how I would accomplish something like this. It isn't the only way to do it.
$('#ItemTypeID').on('change', function() {
$.ajax({
type: 'POST',
url: '#Url.Action("GetItemTypeForm")',
data: { itemTypeId: $('#ItemTypeID').val() },
success: function(results) {
var options = $('#ItemTypeFormId');
options.empty();
options.append($('<option />').val(null).text("- Select an Item Type -"));
$.each(results, function() {
options.append($('<option />').val(this.ItemTypeFormId).text(this.Value));
});
}
});
});
Then you'd have a controller that looks something like this.
[HttpPost]
public JsonResult GetItemTypeForm(string itemTypeId)
{
//pseudo code
var data = Repostitory.GetData(itemTypeId)
return Json(data);
}
I am trying to bind the grid (Kendo UI) with user entered values in TextBox, but when I start the program, I get an error like this,
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[KendoPratapSampleMVCApp.Models.EmployeeDetails]', but this dictionary requires a model item of type 'KendoPratapSampleMVCApp.Models.ParentViewModel'.
When the user entered the value in TextBox and then presses the submit button, the entered value needs to show in the grid.
This is my model,
namespace KendoPratapSampleMVCApp.Models
{
public class TextBoxGrid
{
public string EnteredValue { get; set; }
public List<EmployeeDetails> employees;
}
public class ParentViewModel
{
public EmployeeDetails EmployeeDetails { get; set; }
public TextBoxGrid TextBoxGrid { get; set; }
}
public class EmployeeDetails
{
public string EmployeeId { get; set; }
public string ManagerId { get; set; }
}
}
This is my controller (where i am binding the user entered value to grid)
namespace KendoPratapSampleMVCApp.Controllers
{
public class EnterValuesGridController : Controller
{
public ActionResult Index( TextBoxGrid model)
{
return View(GetEmployee());
}
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
return View(model);
}
public IEnumerable<EmployeeDetails> GetEmployee()
{
string enteredValueId =(string) TempData["enteringValue"];
string managerId = "M" +enteredValueId;
List<EmployeeDetails> empdtls = new List<EmployeeDetails>();
EmployeeDetails em1 = new EmployeeDetails();
em1.EmployeeId = enteredValueId;
em1.ManagerId = managerId;
empdtls.Add(em1);
return empdtls;
}
public ActionResult Orders_Read([DataSourceRequest]DataSourceRequest request)
{
return Json(GetOrders().ToDataSourceResult(request));
}
private IEnumerable<EmployeeDetails> GetOrders()
{
return GetEmployee();
}
}
}
And this is my view where I am displaying the grid,
#model KendoPratapSampleMVCApp.Models.ParentViewModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("PostValues","EnterValuesGrid",FormMethod.Post))
{
#Html.TextBoxFor(m=>m.TextBoxGrid.EnteredValue)
<input type="submit" name="Submitbutton1" value="Submit1" />
#(Html.Kendo().Grid<KendoPratapSampleMVCApp.Models.ParentViewModel>()
.Name("grid")
.Columns(columns => {
columns.Bound(s=>s.EmployeeDetails.EmployeeId).Filterable(false).Width(100);
columns.Bound(s => s.EmployeeDetails.ManagerId).Filterable(false).Width(100);
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Orders_Read", "EnterValuesGrid"))
)
)
}
Would anyone please tell me why I am getting this error. How can I resolve this one?
EDIT : Changed postvalue method
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
var viewmodel = new ParentViewModel
{
TextBoxGrid = new TextBoxGrid { employees = GetEmployee().ToList() }
};
return View("Index", viewmodel);
}
when I submit the button it not showing the values in grid but its showing empty grid...
Error, because model of your view is ParentViewModel, but you give its with
return view(GetEmployee);
IEnumerable, so not corresponding object for model of view.
I advice you do it as follow
public ActionResult Index( TextBoxGrid model)
{
var viewModel = new ParentViewModel
{
TextBoxGrid = new TextBoxGrid { employees = GetEmployee().ToList()}
//but first change TextBoxGrid Property from emplyees to employees{get;set;}, second from return empdtls; to return empdtls.AsEnumarable();
}
return View(viewModel);
}
You must create PostValues view,, or change PostValues to Index, if its give you dublicat change you code as follow
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
return View("Index",model);
}
I have a page that has two drop down lists and based upon the selection of these two lists I would like to populate a textarea with some data on submit button press.
The behavior that I am seeing while debugging is that the page is rendered, I make my selections and press submit. The DataAccess returns the correct results and the View returns, but with an exception "There is no ViewData item of type 'IEnumerable' that has the key 'People'.
I can see that I could re-setup the drop down lists, but it feels like I'm approaching this incorrectly. Is there another approach for doing this sort of action in MVC 3?
public ActionResult Test()
{
//People for dropdownlist 1
var db = peopleRepository.People;
var query = db.Select(c => new {c.Id, c.Name});
ViewBag.People = new SelectList(query.AsEnumerable(), "Id", "Name");
//Elements for dropdownlist 2
var list = new Dictionary<string, string> {{"1", "Name"}, {"2", "Address"}, {"3", "Zip"}};
ViewBag.Elements = new SelectList(list, "Key", "Value");
return View();
}
// This part is what I'm confused about.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test(string people, string elements)
{
if (ModelState.IsValid)
{
// Output from persistent storage query
var da = new DatabaseAccess(people, elements);
ViewBag.Results = da.Execute();
}
return View();
}
View:
#using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
#Html.DropDownList("People", (SelectList)ViewBag.People, "--Select One--")
#Html.DropDownList("Elements", (SelectList)ViewBag.Elements, "--Select One--")
#Html.TextArea("Results", (string)ViewBag.Results, 10, 120, "")
}
Here is how I would quickly construct it :
Model :
public class People
{
public int Id { get; set; }
public string Name { get; set; }
}
ViewModel (everything needed by the view):
public class TestViewModel
{
public int SelectedPeopleId { get; set; }
public string SelectedElementId { get; set; }
public SelectList People { get; set; }
public SelectList Elements { get; set; }
public String Results { get; set; }
}
Controller (used Index as the default Action, create an init function for the view model that can be adapted)to anything more appropriate :
public class HomeController : Controller
{
private static TestViewModel InitTestVM()
{
//People for dropdownlist 1
var db = new List<People>();//peopleRepository.People;
db.Add(new People { Id = 1, Name = "Name 1" });
db.Add(new People { Id = 2, Name = "Name 2" });
var query = db.Select(c => new { c.Id, c.Name });
//Elements for dropdownlist 2
var list = new Dictionary<string, string> { { "1", "Name" }, { "2", "Address" }, { "3", "Zip" } };
TestViewModel testVM = new TestViewModel
{
People = new SelectList(query.AsEnumerable(), "Id", "Name"),
Elements = new SelectList(list, "Key", "Value")
};
return testVM;
}
public ActionResult Index()
{
return View(InitTestVM());
}
// This part is what I'm confused about.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestViewModel testVM)
{
var vm = InitTestVM();
if (ModelState.IsValid && testVM != null)
{
ModelState.Clear();
// Output from persistent storage query
//var da = new DatabaseAccess(people, elements);
vm.Results = "sfdfsdfsdfsdfsdfsdfsdfsdf";//da.Execute();
vm.SelectedElementId = testVM.SelectedElementId;
vm.SelectedPeopleId = testVM.SelectedPeopleId;
return View(vm);
}
return View(vm);
}
}
And finally the View :
#model ViewModels.TestViewModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.DropDownListFor(m => m.SelectedPeopleId, Model.People, "--Select One--")
#Html.DropDownListFor(m => m.SelectedElementId, Model.Elements, "--Select One--")
#Html.TextAreaFor(m => m.Results, 10, 120, "")
<input type="submit" value="Test" />
}