Populating sub menu using Jquery - c#

I feel like a pain asking for help ALL the time but I guess that's what here is for.
New to C# MVC and new to JQuery. I'm not entriely sure about the program flow of things when it comes to Jquery and MVC.
There really isn't that much on tutorials. This is what I want to happen. Select a type of animal (dog) and return list of breeds in sub menu.
#using(Html.BeginForm("", "Pictures", FormMethod.Get))
{
Project1.Models.Animal animal = new Project1.Models.Animal();
#:Filter Photos
<span>
Filter by animal
#Html.DropDownList("animal", new List<SelectListItem> {
new SelectListItem {Text="Select Animal", Value=""},
new SelectListItem {Text="Dog", Value="dog"},
new SelectListItem {Text="Cat", Value="cat"},
})
</span>
//This is where I want jQuery to update the dropdownlist
<span>
Filter by breed
#Html.DropDownList("breed", new SelectList(animal.DogBreeds), "Choose a breed")
</span>
//End of wanted dynamic jquery dropdownlist
<span>
<input type="submit" value="Filter" />
</span>
}
Here is the jquery code
<script type="text/javascript">
$(document).ready(function () {
$("#animal").change(function () {
var animalType = $("#animal option:selected").text();
alert($("#animal option:selected").text());
$.ajax({
type: "POST",
url: "Pictures/GetBreed",
data: animal = animalType,
success: function (data) {
$("#breed").html(data);
}
});
});
})
</script>
And what I want populating is a predefined list. This is just a sample of the list of course
public class Animal
{
public List<string> DogBreeds = new List<string>()
{
"Affenpinscher","Afghan Hound","Airedale Terrier","Akita","Alapaha Blue Blood Bulldog",
"Alaskan Malamute","American Bulldog","American Cocker Spaniel","Anatolian Shepherd",
"Australian Cattle Dog","Australian Shepherd"
};
public List<string> CatBreeds = new List<string>()
{
"Abyssinian","Aegean Cat","Australian Mist","American Curl"
};
}
And here is Pictures/GetBreed, I think this is the bit i'm struggling with. I'm not sure of the correct way to return the data. What do I do!? IS this even the correct way?
public ActionResult GetBreed()
{
string animal = Request["animal"];
if (animal == "Dog")
return dog list;
elseif (animal == "Cat")
return cat list;
else
return null;
}
Thanks for any help!

MVC makes it very simply to pass json data between the client and your controller actions, you could take the following approach.
Javascript
You can get the selected animal type with the following:
var animalType = $('#animal').val()
You could use the getJson method as follows, please note you can also use Url.Action to populate the url i.e. #Url.Action("GetBreed"):
$.getJSON("Pictures/GetBreed", { animalType: animalType }, function (animals) {
// clear the select list
var breedSelect = $('#breed');
breedSelect.empty();
$.each(animals, function (index, breed) {
breedSelect.append($('<option/>', {
value: breed.Id,
text: breed.Name
}));
});
To explain what is happening in the above, a json object is passed as the argument i.e. { animalType: animalType }.
The cascading menu is emptied, the json data that is returned from the controller is looped adding an option to the select list.
Model
The above assumes a new model is created with an Id and a Name i.e.
public class Breed
{
public int Id { get; set;}
public string Name { get; set; }
}
Controller
Then change your controller action to return json as follows:
public ActionResult GetBreed(string animalType)
{
var breeds = new List<Breed>();
if (animalType == "Dog")
breeds = GetDogList();
else if (animalType == "Cat")
breeds = GetCatList();
return Json(breeds, JsonRequestBehavior.AllowGet);
}
The GetDogList and GetCatList just need to return a list of the Breed objects i.e.
private List<Breed> GetDogList()
{
var dogs = new List<Breed>();
dogs.Add(new Breed { Id = 1, Name = "Collie" });
....
return dogs;
}

Related

Kendo Grid changing depending on DropDownList

Before I start I'll just say that I've looked at other answers before posting and none specifically help me.
I need to create a Kendo UI grid in ASP.NET MVC that changes depending on what the users selects from a DropDownList. I will eventually be using data from a database, but currently I'm trying to learn with random hard-coded data.
I found a tutorial online that shows me how to do it with data from a sample database, but I can't set that up for reasons I cant explain. So I'm trying to adapt the code from that tutorial to work with my controllers and models. This might be set up completely wrong as I'm relatively new to ASP.NET MVC.
So here's the tutorial I'm trying to follow.
This is my controller:
public class LookupValueController : Controller
{
private List<LookupModel> tables = new
List<LookupModel>()
{ new LookupModel() { TableName = "Table1",
Description = "Table 1" },
new LookupModel() { TableName = "Table2",
Description = "Table 2" } };
private List<LookupValueModel> values = new List<LookupValueModel>()
{ new LookupValueModel() { TableName = "Table1", Description = "Value 1", LookupCode = "1" },
new LookupValueModel() { TableName = "Table2", Description = "Value 2", LookupCode = "2"} };
// GET: LookupValue
public ActionResult Index()
{
return View();
}
public ActionResult GetAllTableA()
{
try
{
var table = tables;
return Json(table, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(ex.Message);
}
}
public ActionResult GetAllTableB()
{
try
{
var value = values;
return Json(value, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(ex.Message);
}
}
}
Then my 2 models:
public class LookupValueModel
{
public string TableName { get; set; }
public string LookupCode { get; set; }
public string Description { get; set; }
}
public class LookupModel
{
public string TableName { get; set; }
public string Description { get; set; }
}
I've tried just changing the values in the view in the tutorial but it doesn't work, as I believe it isn't as simple as just changing some text.
I'm pretty stuck for how to do this and don't know where to go from here. I know this is a very long winded post with lots of code, but I would really appreciate some help.
Where am I going wrong adapting the tutorial code? What do I have to change to get it to work with hard-coded data?
That's not that hard. What you need to do is to change the DataSource's url for each Action you want. So, depending on what options user selects in the DDL, you change the DataSource. Check this demo.
What you need to change in from the above demo is that your grid's DataSource will call an url instead of a hard-coded json, right? In that url, you change the desired action:
let changeTableData = function changeTableData(option) {
let dataSource = new kendo.data.DataSource({
transport: {
url: "MyApp/" + option
}
});
$("#grid").data("kendoGrid").setDataSource(dataSource);
};
It will read the new url and fetch the data into the grid and updated it.
UPDATE
The transport url ir the url path to your action, e.g.
let url;
if (option == "A") {
url = "#Url.Action("TableA")";
}
else if (option == "B") {
url = "#Url.Action("TableB")";
}
let dataSource = new kendo.data.DataSource({
transport: {
url: url
}
});
1) Remove the grid from this view and create a new partialview and just have the grid located in that.
Now this can be one of two ways. Either an onclick via the drop down list or an onchange. Your choice
function Getdropdown()
{
var id = $("#//dropdownID").val(); //Get the dropdown value
var json = '{dropdownId: ' + id + '}';
$.ajax({
url:'#Url.Action("ViewGrid", "//Controller")',
type:'POST',
data:json,
contentType:'Application/json',
success:function(result){
$("//The Id of of the div you want the partial to be displayed in in the cshtml").html(result);
}
});
}
2) Get the value of the dropdown and pass it to a controller method that calls this new partial view, sending it the ID in a model
public ActionResult ViewGrid(int dropdownId)
{
AModel model = new AModel
{
DropDownID = dropdownId
};
return PartialView("_theGridPartial", model);
}
3) Change your grid to look like this:
#(Html.Kendo().Grid<KendoMvcApp.Models.EmployeeA>()
.Name("EmpGrid")
.Selectable()
.Columns(columns =>
{
columns.Bound(c => c.FirstName);
columns.Bound(c => c.LastName);
})
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetAllEmployee", "GridDataSource", new {id = Model.DropDownID}))
)
)
4) This is the new Controller read
public ActionResult GetAllEmployee([DataSourceRequest]DataSourceRequest request, int id)
{
try
{
//Have a call that gets the table data based on the id you are passing into here. This id will be the table id you have got from your dropdown list
}
catch (Exception ex)
{
return Json(ex.Message);
}
}
This should allow you to change the table based on the dropdown.

DropDownList always displays the first element

I have the DropDownList which has two items. When I select the second one, it flashes it then goes back the first one immediately.
#Html.DropDownListFor(m => m.SelectedProduct, new SelectList(Model.Products, "ProductCode", "ProductName",Model.SelectedProduct),new { #class = "form-control" })
My controller code.
public ActionResult Index(int id, string productName)
{
var model = new ProductModel
{
Product = ProductService.GetProducts()
};
var view = "Something";
model.SelectedProduct = productName;
if(productName =="another")
view = "another";
return View(view, model);
}
The type of Model.Products is IList<Product>.
public class Product
{
public string ProductName {get;set;}
public string ProductCode {get;set;}
}
I saw this link, but I don't have ViewData in my controller. So help me please.
My client side code:
$(document).ready(function () {
$("#SelectedProduct").change(function () {
var selectedValue = $(this).find('option:selected').text();
window.location.href = "#(Url.RouteUrl("MyRoute", new { id = Model.id }))/" + encodeURI(selectedValue);
});
The problem is with the selected item (4th parameter) that is passed to
new SelectList(Model.Products, "ProductCode", "ProductName", Model.SelectedProduct).
This expects that Model.SelectedProduct holds the Value of an item in the SelectList.
But your JS code passes var selectedValue = $(this).find('option:selected').text(); which is the Name.
Change this to
var selectedValue = $(this).find('option:selected').val(); to pass along the ProductCode.

MVC DropDownList OnChange to update other form fields

I am new to MVC (I am moving over from the dark side of traditional ASP.Net) and I know that SO is more of a "why doesn't this work" but, being new to MVC, I just wanted to ask how something is achieved - I don't really have any code or markup because I don't know how at the moment.
Right, using an analogous example... I have a form that has a drop-down of a list of "Widgets" (have that working, thanks to SO) ... and then there are other fields (Length/Height/Width) which have "default" values.
When the form displays, the Drop-Down is shown but the form fields of L/H/W are empty/disabled until the user selects one from the DDL.
Now, in clasic ASP.Net world, you would do a PostBack on the "onselectedindexchange" and that would look at the item selected, then update the L/H/W fields with values from the "master widget entry" version.
As MVC does not have post back... how is this achieved?
In Asp.Net MVC, There is no postback behaviour like you had in the web forms when a control value is changed. You can still post the form and in the action method, you may read the selected value(posted value(s)) and load the values for your text boxes and render the page again. This is complete form posting. But there are better ways to do this using ajax so user won't experience the complete page reload.
What you do is, When user changes the dropdown, get the selected item value and make a call to your server to get the data you want to show in the input fields and set those.
Create a viewmodel for your page.
public class CreateViewModel
{
public int Width { set; get; }
public int Height{ set; get; }
public List<SelectListItem> Widgets{ set; get; }
public int? SelectedWidget { set; get; }
}
Now in the GET action, We will create an object of this, Initialize the Widgets property and send to the view
public ActionResult Create()
{
var vm=new CreateViewModel();
//Hard coded for demo. You may replace with data form db.
vm.Widgets = new List<SelectListItem>
{
new SelectListItem {Value = "1", Text = "Weather"},
new SelectListItem {Value = "2", Text = "Messages"}
};
return View(vm);
}
And your create view which is strongly typed to CreateViewModel
#model ReplaceWithYourNamespaceHere.CreateViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(s => s.SelectedWidget, Model.Widgets, "Select");
<div id = "editablePane" >
#Html.TextBoxFor(s =>s. Width,new { #class ="myEditable", disabled="disabled"})
#Html.TextBoxFor(s =>s. Height,new { #class ="myEditable", disabled="disabled"})
</div>
}
The above code will render html markup for the SELECT element and 2 input text fields for Width and Height. ( Do a "view source" on the page and see)
Now we will have some jQuery code which listens to the change event of the SELECT element and reads the selected item value, Makes an ajax call to server to get the Height and Width for the selected widget.
<script type="text/javascript">
$(function(){
$("#SelectedWidget").change(function() {
var t = $(this).val();
if (t !== "") {
$.post("#Url.Action("GetDefault", "Home")?val=" + t, function(res) {
if (res.Success === "true") {
//enable the text boxes and set the value
$("#Width").prop('disabled', false).val(res.Data.Width);
$("#Height").prop('disabled', false).val(res.Data.Height);
} else {
alert("Error getting data!");
}
});
} else {
//Let's clear the values and disable :)
$("input.editableItems").val('').prop('disabled', true);
}
});
});
</script>
We need to make sure that we have an action method called GetDetault inside the HomeController to handle the ajax call.
[HttpPost]
public ActionResult GetDefault(int? val)
{
if (val != null)
{
//Values are hard coded for demo. you may replae with values
// coming from your db/service based on the passed in value ( val.Value)
return Json(new { Success="true",Data = new { Width = 234, Height = 345}});
}
return Json(new { Success = "false" });
}
Make a Controller "Action" that return "Json" data.
Make Ajax call "onchange" of dropdown to that "Action".
On ajax "response" (json) u will get values then set those values to
fields from json response.
This is the way to update field values.
Shyju made a brilliant post in 2015 but I had to update it to make it work for MVC 5. I worked with one of my progammers (I'm an IT manager) to create this. You need to create a class to represent the dropdown and the Height and Width.
public class AjaxText
{
public int Width { set; get; }
public int Height { set; get; }
public List<SelectListItem> Widgets { set; get; }
public int? SelectedWidget { set; get; }
}
In my HomeController.cs, the GET action will create an object of this, initialize the Widgets property and send to the view.
public IActionResult AjaxText()
{
//Hard coded for demo. You may replace with data form db.
AjaxText vm = new AjaxText();
vm.Widgets = new List<SelectListItem>
{
new SelectListItem {Value = "1", Text = "Weather"},
new SelectListItem {Value = "2", Text = "Messages"}
};
return View(vm);
}
And your create view will render html markup for the SELECT element and 2 input text fields for Width and Height. ( Do a "view source" on the page and see)
#model AjaxText
#{
ViewData["Title"] = "AjaxText";
}
<h1>#ViewData["Title"]</h1>
#using(Html.BeginForm())
{
#Html.DropDownListFor(s => s.SelectedWidget, Model.Widgets, "Select");
<div id = "editablePane" >
#Html.TextBoxFor(s =>s. Width,new { #class ="myEditable", disabled="disabled"})
#Html.TextBoxFor(s =>s. Height,new { #class ="myEditable", disabled="disabled"})
</div>
Now we will have some code which listens to the change event of the SELECT element and reads the selected item value, makes an ajax call to server to get the Height and Width for the selected widget. I added some alerts to help you debug.
<script type="text/javascript">
$(function(){
$("#SelectedWidget").change(function() {
var t = $(this).val();
if (t !== "")
{
$.ajax({
type: 'POST',
datatype: 'json',
url: '/Home/GetDefault?val=' + t,
success: function (bbb) {
alert(t);
alert(bbb.success);
alert(bbb.info.height);
$("#Width").prop('disabled', false).val(res.Data.Width);
$("#Height").prop('disabled', false).val(res.Data.Height);
},
error: function (msg) {
alert("error");
}
});
} else {
//Let's clear the values and disable :)
$("input.editableItems").val('').prop('disabled', true);
}
});
});
</script>
And in my home controller, the Post is done almost the same as how Shyju did it, but success doesn't have quotes around true and false. And you don't have to use the word data... info or whatever will work too. But keep it lowercase to maintain your sanity.
[HttpPost]
public JsonResult GetDefault(int? val)
{
if (val != null)
{
//Values are hard coded for demo. you may replae with values
// coming from your db/service based on the passed in value ( val.Value)
return Json(new { success = true, info = new { width = 234, height = 345 } });
}
return Json(new { Success = false });
}
I'm sure there are better ways to do this. This is what worked for us. Cheers and enjoy your coding experience! :)

How Do I Model Bind A List Of 'List<SelectItem>' Using MVC.Net

I am trying to create a form that will consist of a series of dropdown lists, all of which are loaded from a database. I will not know how many dropdown lists will be needed, or how many options each dropdown list will have at compile-time.
How can these fields be set-up to allow them to model-bind when posted?
There is a lot of other complexity in each of the below code elements, but I cannot get the model binding to work even when reduced down to a basic level.
The Models:
public class MyPageViewModel
{
public List<MyDropDownListModel> ListOfDropDownLists { get; set; }
}
public class MyDropDownListModel
{
public string Key { get; set; }
public string Value { get; set; }
public List<SelectListItem> Options { get; set; }
}
The Controller Get Action:
[AcceptVerbs(HttpVerbs.Get)]
[ActionName("MyAction")]
public ActionResult MyGetAction()
{
var values_1 = new List<string> {"Val1", "Val2", "Val3"};
var options_1 =
values_1
.ConvertAll(x => new SelectListItem{Text=x,Value=x});
var myDropDownListModel_1 =
new MyDropDownListModel { Key = "Key_1", Options = options_1 };
var values_2 = new List<string> {"Val4", "Val5", "Val6"};
var options_2 =
values_2
.ConvertAll(x => new SelectListItem{Text=x,Value=x})};
var myDropDownListModel_2 =
new MyDropDownListModel { Key = "Key_2", Options = options_2 };
var model =
new MyPageViewModel
{
ListOfDropDownLists =
new List<MyDropDownListModel>
{
myDropDownListModel_1,
myDropDownListModel_2,
}
};
return View(model);
}
The Controller Post Action:
[AcceptVerbs(HttpVerbs.Post)]
[ActionName("MyAction")]
public ActionResult MyPostAction(MyPageViewModel model)
{
//Do something with posted model...
//Except 'model.ListOfDropDownLists' is always null
return View(model);
}
The View:
#model MyPageViewModel
#using (Html.BeginForm("MyPostAction"))
{
foreach (var ddl in Model.ListOfDropDownLists)
{
#Html.DropDownListFor(x => ddl.Value, ddl.Options)
}
<button type="submit">Submit</button>
}
Edit: Corrected typos and copy-paste mistakes.
Solution:
The problem turned out to be the foreach-loop within the view. Changing it into a for-loop instead caused the post to populate as expected. The updated view is below:
#using (Html.BeginForm("MyPostAction"))
{
for (int i = 0; i < Model.ListOfDropDownLists.Count; i++)
{
#Html.HiddenFor(x => x.ListOfDropDownLists[i].Key)
#Html.DropDownListFor(m => m.ListOfDropDownLists[i].Value, Model.ListOfDropDownLists[i].Options);
}
<button type="submit">Submit</button>
}
Your view is only creating multiple select elements named dll.Value (and duplicate ID's) which has no relationship to your model. What you need is to create elements named ListOfDropDownLists[0].Value, ListOfDropDownLists[1].Value etc.
Change you loop in the view to this
for (int i = 0; i < Model.ListOfDropDownLists.Count; i++)
{
#Html.DropDownListFor(m => m.ListOfDropDownLists[i].Value, Model.ListOfDropDownLists[i].Options);
}
You posted code has multiple errors (e.g. your pass a model of type MyPageViewModel but the post action method expects type of MyModel). I assume these are just typo's.
I can give you my solution,It is working:
Method in base controller
//To bind Dropdown list
protected Dictionary<int, string> GenerateDictionaryForDropDown(DataTable dtSource, string keyColumnName, string valueColumnName)
{
return dtSource.AsEnumerable()
.ToDictionary<DataRow, int, string>(row => row.Field<int>(keyColumnName),
row => row.Field<string>(valueColumnName));
}
Code in controller:
DataTable dtList = new DataTable();
dtList = location.GetDistrict();
Dictionary<int, string> DistrictDictionary = GenerateDictionaryForDropDown(dtList, "Id", "DistrictName");
model.DistrictList = DistrictDictionary;
Binding Data in view:
#Html.DropDownListFor(model => model.DiscrictId, new SelectList(Model.DistrictList, "Key", "Value"), new { id = "ddlDist", #class = "form-control" })
Binding Other Dropdown from this(cascading):
Other Dropdown:
#Html.DropDownListFor(model => model.TalukaId, new SelectList(Model.TalukaList, "Key", "Value"), new { id = "ddlTaluka", #class = "form-control" })
JQuery Code:
$("#ddlDist").change(function () {
var TalukaList = "Select"
$('#ddlTaluka').html(TalukaList);
$.ajax({
type: "Post",
dataType: 'json',
url: 'GetTaluka',
data: { "DistId": $('#ddlDist').val() },
async: false,
success: function (data) {
$.each(data, function (index, optionData) {
TalukaList = TalukaList + "<option value='" + optionData.Key + "'>" + optionData.Value + "</option>";
});
},
error: function (xhr, status, error) {
//alert(error);
}
});
$('#ddlTaluka').html(TalukaList);
});
Controller Method Return JSON
public JsonResult GetTaluka(int DistId)
{
LocationDH location = new LocationDH();
DataTable dtTaluka = location.GetTaluka(DistId);
Dictionary<int, string> DictionaryTaluka = GenerateDictionaryForDropDown(dtTaluka, "ID", "TalukaName");
return Json(DictionaryTaluka.ToList(), JsonRequestBehavior.AllowGet);
}

Ho to pass a Model Object or a Viewbag to Javascript?

I am using asp.net mvc4 with C#. I get the details from Getdeatils() method of student class. This method return an array. Getdetails method also have same fields like studentBO. In the controller I have a method like follows
public ActionResult Index()
{
List<studentBO> list = new List<studentBO>();
Student.GetDetails[] dt = Student.Getdeatils();
for (int i = 0; i < dt.Length; i++)
{
studentBO.name= dt[i].name;
studentBO.studentno= dt[i].studentno;
studentBO.address= dt[i].address;
list1.Add(studentBO);
}
ViewBag.Registrationlist = list1;
return View(list1);
}
studentBO object have 3 fields
public class studentBO
{
public long studentno{ get; set; }
public string name{ get; set; }
public string address{ get; set; }
}
How can I get viewbag or model in my Jquery `$(document).ready(function () {}` function. I want to get every students name. So I have to use foreach loop as well.
You can serialise your item in the ViewBag and write it to the view, so that the Javascript code will be able to read it:
$(document).ready(function() {
var registrationList = #(Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.Registrationlist)));
for (var i = 0; i < registrationList.length; i++) {
var studentno = registrationList[i].studentno;
var name= registrationList[i].name;
var address= registrationList[i].address;
// write some more code to make use of the values
}
});
Use WebAPI to create a service that returns your objects. Then you can use an ajax-call in your Javascript code to fetch the objects.
WebAPI:
public class StudentsController : ApiController
{
IEnumerable<Student.GetDetails> GetDetails()
{
List<studentBO> list = new List<studentBO>();
Student.GetDetails[] dt = Student.Getdeatils();
for (int i = 0; i < dt.Length; i++)
{
studentBO.name= dt[i].name;
studentBO.studentno= dt[i].studentno;
studentBO.address= dt[i].address;
list1.Add(studentBO);
}
return list1;
}
}
Javascript:
$(document).ready(function () {
// Send an AJAX request
$.getJSON("api/students")
.done(function (data) {
// On success, 'data' contains a list of students.
$.each(data, function (key, item) {
//Do something with the student object
});
});
});

Categories

Resources