Bind DropDownlists with JQuery in Asp.Net - asp.net

I have 3 dropdownlists for Country,State and Metro.
I want to when user seclect Country then State dropdownlist fill Jquery and when select Sate then Metro dropdownlist fill(like cascading dropdownlist of ajax).These process i want to do with JQuery.

I am going to describe it in ASP.NET MVC, but the same can be achieved if you either write an ASP.NET web service or just put a few page methods in your code behind to do the same - you'll also need a JSON serializer, either a 3rd party solution or the one in WCF.
Using MVC, first, let's have three controller actions - one to display the page, countries will be static, and two to get the states and metros respectively:
public ActionResult Index()
{
ViewData["Countries"] = _countryRepository.GetList();
return View();
}
public ActionResult States(string countryCode)
{
var states = _stateRepository.GetList(countryCode);
return Json(states);
}
public ActionResult Metros(string countryCode, string state)
{
var metros = _metroRepository.GetList(countryCode, state);
return Json(metros);
}
In the view, you have three DropDownLists, one is bound to the ViewData["Countries"] object, say it's named Countries, you can get the states in jQuery with an Ajax call like this:
$('#Countries').change(function() {
var val = $(this).val();
$states = $('#States');
$.ajax({
url: '<%= Url.Action('States') %>',
dataType: 'json',
data: { countryCode: val },
success: function(states) {
$.each(states, function(i, state) {
$states.append('<option value="' + state.Abbr+ '">' + state.Name + '</option>');
});
},
error: function() {
alert('Failed to retrieve states.');
}
});
});
The Metros drop down would be filled analogically, passing both the country and state selection to the server and getting back a JSON object with an array of metro areas.
I left out the details of repository implementation, just fill up the result variable on the server with a collection of states/metro areas in some way. I also made an assumption that the State class would have two properties - Abbr (e.g., 'CA') and Name (e.g., California).
I hope that it helps you in any way, or at least directs you somehow towards the solution.

Related

Managing HTTP requests and ViewModel in ASP.NET

I have a CSHTML page and I'm having trouble finding the best way to structure my requests flow and maintaining a persistance of what is in the ViewModel with what is being displayed in the View.
I'm using an ASP.NET Web Service as API to connect the website to the database. This is how my Controller is populating the ViewModel before calling the View:
[AllowAnonymous]
[Route("company/sites")]
public async Task<IActionResult> CompanySites()
{
var client = _clientFactory.CreateClient("API");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", HttpContext.Request.Cookies[Startup._tokenCookieName]);
CompanyAccount user = JsonConvert.DeserializeObject<CompanyAccount>(HttpContext.Request.Cookies[Startup._companyInfoCookieName]);
if (user == null)
{
return RedirectToAction("Index", "Company");
}
CompanySitesViewModel viewModel = new CompanySitesViewModel ();
viewModel.LoggedInCompanyId = user.CompanyId;
// Populate viewModel...
return View(viewModel);
}
The ViewModel:
public class CompanySitesViewModel
{
public List<CompanyDTO> AdministratedCompanies { get; set; }
public CompanySitesViewModel ()
{
AdministratedCompanies = new List<CompanyDTO>();
}
}
And this is one of the places I access data from the ViewModel inside the View:
...
#if (Model.AdministratedCompanies.Count > 0)
{
<div class="list-group list-group-flush">
#for (int i = 0; i < Model.AdministratedCompanies.Count; i++)
{
<button class="list-group-item">
<div>
<h6>#Model.AdministratedCompanies[i].CompanyName</h6>
#if (#Model.AdministratedCompanies[i].CompanyCnpj != null)
{
<span><small class="text-muted">##Model.AdministratedCompanies[i].CompanyCnpj</small></span>
}
</div>
</button>
}
</div>
}
...
My problem starts when I want to manipulate the data displayed in this list. In instance, I want to remove one company from AdministratedCompanies. I'm currently doing a Ajax call directly to the API and, when receiving success, forcing a page refresh so the View gets updated without the deleted company.
This is the Ajax call:
function deleteCurrentSite() {
if (currentCompanyIdToDelete != null) {
$.ajax({
url: "#Startup._apiConnectionString" + "sites/" + currentCompanyIdToDelete ,
type: "DELETE",
success: function (e) {
showAlert('Company deleted. Refreshing page...', true);
// Has to reload page to refresh site list
document.location.reload(true);
},
error: function (e) {
showAlert('Error deleting company.', false);
},
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Bearer " + '#Model.Token');
}
});
return false;
}
}
I have background in React development, and it is incredibly easy to just change the state and have the view to be updated, and I seems very unoptimal to have to reload the whole page because of a change.
I have some ideas in mind to solve this:
Find the deleted company's div and delete it manually. Not optimal, even less when I want to add a company and have to create and append the component.
Have the Controller to store the ViewModel and have the Ajax call to send the ID I want to delete to the Controller, that then manages the API calls. But from what I found, if I use RedirectToAction or call the View again after the deletion, the page will still be refreshed (even though this seems a better approach as having Ajax to call the API).
Found some references to this library BeginCollectionItem to create a more dynamic binding between the View and ViewModel, but when I saw it was updated 7 years ago I didn't investigate further.
So what is the best way of creating a dynamic binding between the View and ViewModel including CRUD operations and list redraw when changes occur?
Here's an example of some javascript (jQuery) for a simple get. The handler passes the URL of the "jq_pagename.cshtml":
function DisplayError(jqXHR, textStatus, error) {
errortext = error + jqXHR.responseText;
$('#status').html('');
$('#results').html(errortext);
}
function updateMainDiv(url) {
$('#results').html('');
data = "<img src='/images/waiting.gif'></img>";
$('#status').html(data);
$.get(url, function (data) {
$("#results").html(data);
$('#status').html('');
}).fail(function (jqXHR, textStatus, error) {
DisplayError(jqXHR, textStatus, error);
});
}
For this technique I usually use partials for static view controls on the page... search, top-level nav, etc... and then for main content. the main page includes those, the jq_ page does not. The "results" div is only in the main page. You are sending the GETs or POSTs to the jq_page via javascript and returning their HTML via javascript. This way the exact same controller can be used to update the data and the view. (You're just intercepting the returned HTML and putting it where you like.) Here's an example of processing a form (onsubmit, or onchange select, etc..):
function ProcessFormPost(formID, destURL) {
formresult = $('#' + formID).serialize();
$('#super').html('');
data = "<img src='/images/waiting.gif'></img>";
$('#status-super').html(data);
$.post(destURL, formresult, function (data) {
$("#super").html(data);
$('#status-super').html('');
}).fail(function (jqXHR, textStatus, error) {
DisplaySuperError(jqXHR, textStatus, error);
});
return false;
}

ASP .NET API Ajax How to update only some properties?

I have a datatable and for each row there's a button. When clicked, it should set a property (field AvailableToCall) in my class. So I call an Ajax for my update method API passing the value (true) for the property. The problem is that when I do that, all the other properties (for example, name, adress, etc.) are set to null. Is there a way that I can update only a specific property leaving all the other properties of my table the same as before the AJAX call?
$.ajax({
url: "/api/person/" + personId,
type: "put",
data: {
AvailableToCall: true
}
}).done(function () {
// something
}
Thanks for the help.
Another way you could achieve this is a different endpoint:
$.ajax({
url: "/api/person/" + personId + "/availabletocall",
type: "put",
data: true
}).done(function () {
// something
}
So your url is something like below which accepts a body with a boolean:
/api/person/123/availabletocall
Your controller action could simply receive that single value and update whichever datasource you're using.
First of all you need to show your ApiController method.
I assume your method is like this,
public HttpResponseMessage Put(int id)
{
var _AvailableToCall = HttpContext.Current.Request.Form["AvailableToCall"];
//I'm using HttpContext to fetch the data in the above line. You can fetch
//the bool value as your way
//Now you just need to fetch the data by personId, (here it is id).
myClass obj = contextObj.myClass().where(m=>m.personId ==
id).firstOrDefault();
obj.AvailableToCall = true;
//That's it. Now you can update it.
contextObj.Entry(obj).State = System.Data.Entity.EntityState.Modified;
contextObj.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, new { Status = "OK",
Message = e.ToString() });
//You can return your data as your requirements or as you are writing in
//your project.
}
See here "contextObj" is the object of my Context Class. And "myClass" is my modal class that I want to update/save data.
You can write "Json" return type in place of "HttpResponseMessage".
Cheers...

JSON Post Request is not working in ASP.NET5 MVC but is working in ASP.NET4.5 MVC

I have an example which sends a JSON post request to MVC controller. This example works in ASP.NET 4.5 but won’t work in the newest ASP.NET 5 release. Do I miss anything in this example?
I created a model, but I didn’t bind it to database. It will be just the object created in the memory.
public class SalesOrder
{
public int SalesOrderId { get; set; }
public string CustomerName { get; set; }
public string PONumber { get; set; }
}
I use Visual Studio 2015 to create that model based controller and its associated CRUD views. However, in this example, I will only run the “Create” view.
Inside the controller, I hard coded a SalesOrder object list and it only contains an item. I will use it to work with the CRUD views.
private List<SalesOrder> salesOrderList =
new List<SalesOrder> (
new SalesOrder[]
{
new SalesOrder()
{
SalesOrderId = 1,
CustomerName = "David",
PONumber = "123"
}
});
Inside the controller, I also create a new function to process the “Save” request. The request will just change the CustomerName property of the model then bounce back with the JSON result.
[HttpPost]
public JsonResult Save(SalesOrder salesOrderViewModel)
{
salesOrderViewModel.CustomerName = "David returns";
return Json(new { salesOrderViewModel });
}
In the Create.cshtml, I created a button and attach JQuery script to its click event.
<p><button id="saveButton">Save</button></p>
This is the JQueryScript.
$(function () {
var clickFunc = function () {
var salesOrderViewModel = {
"salesOrderViewModel": {
"SalesOrderId": 123,
"CustomerName": "ab",
"PONumber": "2",
}
}
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: JSON.stringify(salesOrderViewModel),
contentType: "application/json; charset=utf-8"
});
}
$('#saveButton').click(clickFunc)
})
I click the "Save" button in Create.cshtml to trigger the post request.
I set the debug break point in the controller and verify the coming post request. In ASP.NET 4.5, the JSON deserialization is working, and it shows all the values.
However, in ASP.NET 5, an empty object is returned.
In ASP.NET 5 case, if press F12 to start the debugger in Microsoft Edge, then it shows the Post request does have the correct values, but for some reasons, they are not passed to MVC controller.
Please see these screen shots:
http://i63.tinypic.com/68vwnb.jpg
Do I miss anything?
Thanks for helping…
I don't think you need to specify the name of the parameter. Try:
var salesOrderViewModel = {
"SalesOrderId": 123,
"CustomerName": "ab",
"PONumber": "2",
}
I think you need to especify fromBody in the Controller.
[HttpPost]
public JsonResult Save([FromBody]SalesOrder salesOrderViewModel)
{
salesOrderViewModel.CustomerName = "David returns";
return Json(new { salesOrderViewModel });
}
Thanks for DCruz22 and Stephen Muecke.
The working version of the script is:
$(function () {
var clickFunc = function () {
var salesOrderViewModel = {
"salesOrderViewModel": {
"SalesOrderId": 0,
"CustomerName": "ab",
"PONumber": "2",
"MessageToClient": "POST to server"
}
}
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: salesOrderViewModel
});
}
$('#saveButton').click(clickFunc)
})
I found the parameter name "salesOrderViewModel" is not a problem. With it, the script is still working.
Actually, this question is a simplified version of my original problem. My originally problem is starting from the knockoutJs. Below is the script doing the data binding. After user clicks the "Save" button, the self.save function() is called and the script will send the post request including the data model to the MVC controller.
SalesOrderViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/SalesOrders/Save/",
type: "POST",
cache: false,
data: ko.toJSON(self),
success: function (data) {
}
});
}
}
The problem is "ko.toJSON(self)" includes some other information. Below is the request body I captured from the Microsoft Edge debugger.
{"SalesOrderId":0,
"CustomerName":"chiang123",
"PONumber":"123",
"MessageToClient":null,
"__ko_mapping__":{
"ignore":[],
"include":["_destroy"],
"copy":[],
"mappedProperties":{
"SalesOrderId":true,
"CustomerName":true,
"PONumber":true,
"MessageToClient":true}}}
You can see all data starts from "ko_mapping" is KnockoutJs specific. Do I need to manually trim those data in order to make this work? Per information, obviously the same implementation should work in ASP.NET 4.5 but I just haven't try it yet. Many thanks...

Cascading dropdown with Static data

i need to develop two dropdown list in my MVC3 project, where first dropdown will be a db driven and based on the data selected on first dropdown my second dropdown should change. Second dropdown is having hard coded text and value. how could i achived this. please help
Following is my codebased
viewmodel
public IEnumerable<SelectListItem> ProductTypeCode{ get; set; }
public int? ProductID { get; set; }
public IEnumerable<SelectListItem> ProductGroupCode;
public int? ProductGrpID { get; set; }
Controller
public ActionResult Index() {
var model = new MyViewModel
{
// TODO: Fetch those from your repository ,
model.ProductTypeCode= new SelectList(obj.ProductTypeCode as System.Collections.IEnumerable, "Value", "DispalyText");
return view(model);
}
VIEW
#Html.DropDownListFor(m => m.ProductID , Model.ProductTypeCode, "ALL" , new { #class = "DropDownList" })</td>
My question is based on the above dropdown of productType, i need to populate another dropdown called "ProductGroup" which is having hardcoded value. based on the ProductType dropdown the value of productgroup should change.
You have several options.
You can write your own javascript to handle the onchange event. There are literally thousands of simple tutorials on this exact topic. This one will probably address your question the best.
You can use extensions like Telerik's. They're relatively straight forward, well documented, but do have the extra weight of another library on them (although the markup they generate is pretty slim).
If you go with option 1 and write your own, the two main things you'll have to add in will be an extra controller action and some javascript.
The javascript will listen for change events on your product Id drop down. Put this in a document ready function on the page itself.
$("#ProductID").change(function() {
// Get the product id selected
var id = $(this).val();
// Fire off an ajax request to get the groups
$.ajax({
// whatever the url may be.
url: "#Url.Action("Groups")" + id, // Append the id to the url.
dataType: "json",
type: "POST",
error: function() {
alert("An error occurred.");
},
success: function(data) {
var items = "";
$.each(data, function(i, item) {
items += "<option value=\"" + item.Id+ "\">" + item.Name + "</option>";
});
// Set the secondary dropdown content to the newly created
// list of options. Use whatever Id your secondary is.
$("#ProductGroup").html(items);
});
The controller action responds to the ajax call with the list of appropriate product groups.
public class ProductsController : Controller
{
public ActionResult Groups(int id)
{
// You only need the id and a name field in the response, not the
// entire object.
var groups = _myService.FindGroupsForProductId(id)
.Select(g => new
{
Id = g.Id,
Name = g.Name
});
// Return a json result. You only need to re
return Json(groups);
}
}
The code above should help you get started. It's assuming several things that you didn't show in your code at all. Your question got downvoted because at first, you didn't post any code. Then, the code that you did post doesn't really show that you've put any effort into finding the solution on your own. Find some jquery tutorials on this, there are thousands, then if you have specific problems, bring them here.

RedirectToAction not working when called by jQuery?

I am trying to call an action method by jQuery, and got help with passing parameters here: Calling action method in MVC with jQuery and parameters not working . However, even though the parameters are sent correctly now, in the action method I need to redirect (passing on those same parameters) to another action method. In the debugger I can see that the redirect is carried out, and the parameters are still there, but the View returned doesn't update accordingly...
Is there some problem with calling an action method that redirects by using jQuery?
Action method called by jQuery:
public ActionResult SelectDate(string date)
{
DateTime dateObject = DateTime.Parse(date);
MyCalendar calendar = new MyCalendar();
string number = calendar.GetWeekNumber(dateObject).ToString();
string year = dateObject.Year.ToString();
return RedirectToAction("Edit", new { number = number, year = year });
}
Action method redirected to:
public ActionResult Edit(string number, string year) //Why string here???
{
int n;
if (string.IsNullOrEmpty(number))
n = myCalendar.GetWeekNumber(DateTime.Today);
else
n = Int32.Parse(number);
int y;
if (string.IsNullOrEmpty(year))
y = DateTime.Today.Year;
else
y = Int32.Parse(year);
List<Customer> customers = _repository.Customers;
ViewData["Customers"] = new SelectList(customers, "CustomerId", "CustomerName");
ViewData["WeekNumber"] = n;
ViewData["Year"] = y;
return View();
}
Or is jQuery get() not the proper way to call an action method to load a new page? Note that doing the same thing with an ActionLink works fine, it's just that I need to call it by jQuery because I'm using the datepicker plugin and also a button as the way to call the action.
What am I doing wrong?
UPDATE:
Actually, the RedirectToAction doesn't seem to be the problem, I modified the code so that the jQuery now calls the final action method directly (by doing the job of the first action method directly in the jQuery, i.e. convert date to week and year). But I still don't get the new page with the new week and year.
Here's the new jQuery:
function selectWeek() {
$('#selectWeekButton').click(function (event) {
var date = $('#selectWeekId').val();
var selectedDate = new Date(date);
var year = selectedDate.getFullYear();
var week = selectedDate.getWeekOfYear();
var url = '<%: Url.Action("Edit") %>';
$.get(url, { number: week, year: year }, function (data) {
// alert('Test');
});
});
}
Again, is it using the get that is incorrect? I do not wish to load content in an html tag, I just want to use jQuery to do the exact same thing as an actionlink, i.e. call an action method to get the Edit View...
For instance, this actionlink works fine, calling an action method called Next that redirects to Edit and shows the new week and year View:
<a href="<%=Url.Action("Next", new { number=ViewData["WeekNumber"], year = ViewData["Year"] })%>">
>></a>
But I want to do that (or Edit directly) in jQuery...
jquery AJAX automatically follows redirect meaning that in the success callback you will get the result of the Edit action you have redirected to. In this callback you will get the partial HTML returned by the controller action. So if you want to update some part of the DOM you need to explicitly instruct it so:
$.ajax({
url: '<%= Url.Action("SelectDate") %>',
data: { date: '123' },
success: function(result) {
$('#someresultDiv').html(result);
}
});
or simply use the .load() method:
$('#someresultDiv').load('<%= Url.Action("SelectDate") %>', { date: '123' });

Resources