I have a C# MVC application which is populating a dropdown based on a date selected. Once the date is selected I am sending it to an action via AJAX/jQuery. The action gets a list of items to return for that date.
Here is where my problem is. I have done it previously where I render a partial view from the action and pass it the SelectList as the model. However, I really just want to do it inline in the original view, so I'm hoping there is some way I can return the SelectList and from there do some magic Javascript/JQuery to put it into a dropdown.
Has anybody ever done this before? If so, what do I on the client end after calling the load() to return the SelectList?
I've done something like this previously, when I was just returning a string or other value to be rendered as straight text:
$("#returnTripRow").load("/Trip.aspx/GetTripsForGivenDate?date=" + escape(selection));
But I'm not sure how to intercept the data and morph it into am Html.DropDown() call, or equivalent.
Any ideas?
Thanks,
Chris
Supposing you have a controller action that will feed the data for the dropdown:
public ActionResult Cars()
{
return Json(new[] {
new { id = "bmw", name = "BMW" },
new { id = "mer", name = "Mercedes" },
new { id = "aud", name = "Audi" }
}, JsonRequestBehavior.AllowGet);
}
And in your view:
$.getJSON('/home/cars', { }, function(cars) {
var list = $('select#cars');
list.find('option').remove();
$(cars).each(function(index, car) {
list.append('<option value="' + car.id + '">' + car.name + '</option>');
});
});
Related
Have a view with 2 drop-downs the 2nd one disabled by default. When selection is made in first drop-down, it is supposed to both call an action in my controller to retrieve list of values for 2nd drop-down, then use simple scripting to clear the 2nd drop-down, enable the 2nd drop-down and fill it with the results.
When I make a selection from the first drop-down, the 2nd drop-down is enabled but no values appear. Using Ctrl-shift-i I see the error TypeError: right-hand side of 'in' should be an object, got string.
But I'm using a List of values not a string variable...
I have verified in SQL manager that the SQL query works for all 3 different options available in first drop-down.
Added alert(attValues); into $.post. It is resulting in an entire HTML doc being shown in the alert that goes about really long way of saying 404 page not found.
The important line seeming to be:
<form method="post" action="../../../Error_404.aspx?selectedOption=SKU_SelectableAttribute_2" id="error404">
Controller
[HttpPost]
public ActionResult GetAttributeValues(string selectedOption)
{
JsonResult result = new JsonResult();
if (selectedOption != null)
{
string sql = "SELECT Title FROM BL_Attribute (NOLOCK) WHERE BL_Attribute.DeleteFlag = '0' AND AttributeGroupName = '" + selectedOption + "'";
using (SqlCommand selectAttValues = new SqlCommand(sql, P21SqlConnection))
{
using (SqlDataReader reader = selectAttValues.ExecuteReader())
{
List<string> attValues = new List<string>();
while (reader.Read())
{
attValues.Add(reader["Title"].ToString());
}
return Json(attValues, JsonRequestBehavior.AllowGet);
}
}
}
return Json(new { Success = "false" });
}
View
#using System.Data
#model Product
#{
ViewBag.Title = "Attributes";
Layout = "~/Views/Shared/_VisualRuleLayout.cshtml";
var listAttGroups = new List<SelectListItem>
{
new SelectListItem { Text = "SKU_Color", Value = "SKU_Color"},
new SelectListItem { Text = "SKU Select Att 1", Value = "SKU_SelectableAttribute_1"},
new SelectListItem { Text = "SKU Select Att 2", Value = "SKU_SelectableAttribute_2"}
};
}
#section scripts{
<script>
$(function () {
$("#ApplyGroup").change(function () {
var option = $(this).val();
$("#AttributeValue").empty();
$("#AttributeValue").prop('disabled', false);
var url = "KCDA_PrdGrp_Attributes/GetAttributeValues?selectedOption=" + option;
$.post(url, function (attValues) {
$.each(attValues, function (i, attValue) {
$("#AttributeValue").append($('<option></option>').val(attValue).html(attValue));
});
});
});
});
</script>
}
<center><h3>Edit Attributes</h3></center>
#using (Html.BeginForm("Return", "KCDA_PrdGrp_Attributes", FormMethod.Post, new { name = "Return" }))
{
#Html.DropDownList("ApplyGroup", listAttGroups, new { #id = "ApplyGroup", #class = "form-control" })
#Html.DropDownList("AttributeValue", new List<SelectListItem>(), new { #id = "AttributeValue", #class = "form-control", disabled = "disabled" })
}
The error is the result of the returned JSON being a string. JSON is afterall, just a notation. When .each attempts to iterate an array like variable, it instead finds a string and throws the error.
In order to convert the string into an iterable array, it needs to be parsed. Looking to see if your Success flag was false would help as well.
$.post(url, function (attValues) {
var result = JSON.parse(attValues);
if( result.Success && result.Success == "false" ) return;
$.each(result, function (i, attValue) {
$("#AttributeValue").append($('<option></option>').val(attValue).html(attValue));
});
});
As an aside, the SQL in the controller is problematic as it does not prevent malicious values from being inserted into a live query. It should be addressed by parametizing, encoding, or using a different sql paradigm (such as integrating LINQ or using a ORM).
So issue ended up simple over pathing, ajax.post() defaults to current directory already and I had included it in URL. Removing the "KCDA_PrdGrp_Attributes/" from beginning of URL fixed issue.
Also the JSON.parse() was incorrect. It failed using .parse with error of invalid character line 1 character 1 every time after fixing URL, but it does work perfectly without it.
Thanks again for help - Travis idea of logging (in my case adding simple alert()) to show variable value indeed helped me finish debugging.
$("#ApplyGroup").change(function () {
var option = $(this).val();
$("#AttributeValue").empty();
$("#AttributeValue").prop('disabled', false);
var url = "GetAttributeValues?selectedOption=" + option;
$.post(url, function (attValues) {
$.each(attValues, function (i, attValue) {
$("#AttributeValue").append($('<option></option>').val(attValue).html(attValue));
});
});
});
The closest I have come to finding an an answer is here: https://stackoverflow.com/a/16295052/608674
The problem is that I can not figure out how set the root name dynamically.
Using the w3widget responsive-calendar. The calendar uses a javascript object with many child objects. Like this:
$(".responsive-calendar").responsiveCalendar({
events: {
"2018-04-30": {
"number": 5,
"badgeClass": "badge-warning",
"url": "http://w3widgets.com/responsive-calendar"
},
"2018-04-25": {
"number": 1,
"badgeClass": "badge-warning",
"url": "http://w3widgets.com/responsive-calendar"
},
"2018-04-03": {
"class": "active special",
"url": "http://w3widgets.com/responsive-calendar"
},
"2018-04-26": {
"number": 2,
"badgeClass": "badge-warning",
"url": "http://w3widgets.com"
},
"2018-05-03": {
"number": 1,
"badgeClass": "badge-error"
},
"2018-06-12": {}
}
});
I attempted to bypass this problem by returning a list of strings from the controller but this isn't working... I'm not sure how to add each string into the "event" JavaScript object with the correct root name.
var jsonEvent = string.Format("'{0}: {{'" +
"'class' : '{1}'," +
"'link' : '{2}'," +
"'link_target' : '{3}," +
"'title' : '{4}'," +
"'location' : '{5}'," +
"'date' : '{6}'," +
"'desc' : '{7}'," +
"'count' : '{8}'," +
"'event_id' : '{9}'" +
"}},",
evnt.StartDate.AddDays(i).ToString("yyyy-MM-dd"),
GetEventClass(evnt.Id, i, dayCount),
evnt.EventUrl,
hasLink,
evnt.Name,
evnt.Location,
dateString,
evnt.Description,
i,
eventId);
I tried to put the string into the event variable like this:
var actionUrl = '#Url.Action("GetJsonEvents", "EventsSurface", new { pageId = Model.Id })';
$.getJSON(actionUrl).done(function (data) {
$.each(data.items, function (index, item) { event[index] = value; });
});
Of course that seems wrong because it would give the root name the value of index.
I've also tried adding the data into variable called "events_data" and parsing it out like was suggested in another question events: Json.Parse(events_data), but that doesn't seem to work... probably because I'm not returning the data correctly from the controller.
It's apparent to me that I just don't understand this process well enough. I know I'm not working with JSON objects so that confuses me when trying to pass back data to the view from the controller...
Assuredly, part of the problem is that I am returning the list of strings from the controller like this: return Json(eventList, JsonRequestBehavior.AllowGet);
I don't know how else to return the data to an ajax call and place it into a JavaScript object.
Edit: 1/518 12.32
Using a Dictionary object in the controller works. I had to create a class for the Json Event Object because the name "class" is reserved in C# and I couldn't use an anonymous object. I ran into a problem trying to decorate the class property with a JsonProperty attribrute...
private class JsonEvent
{
[JsonProperty (PropertyName = "class")]
public string Class { get; set; }
public string link { get; set; }
...}
because I was still using the return Json(..., ...), which is the .net serialization not Newtonsoft. I just had to serialize using Json and return the content: return Content(JsonConvert.SerializeObject(eventList), "application/json");.
In the view, when I JSON.stringify(data) the event object looks perfect. Unfortunately, when I try to use the data in the resonsponive-calendar, it still doesn't work.
So far I have tried:
event_data = data;
event_data = JSON.stringify(data);
Whole ajax call looks like:
var events_data = {};
$.getJSON(actionUrl, events_data).done(function (data) {
console.log(JSON.stringify(data));
events_data = Json.parse(data);
});
And of course, the calendar just calls the event: events_data
Solved 1/5/18 13.54
So, yes, the dictionary in the Controller is the way to go. I am working with someone else's code in JavaScript. They hardcoded the data in. Turns our that the calendar was loading and calling the event data before the ajax call was complete.
so events_data = data works just fine.
Have you tried passing a dictionary from the controller? If that doesn't work, you might have to use a classic ASHX handler and ResponseWrite the JSON object to do what you want.
I'm not sure if returning a Dictionary<string, event> where the date string is the key, from a controller would do what you want or not, but it would be worth a try. JSON isn't hard to ResponseWrite from generic handler either though.
I have a method in a Model which takes over 15 seconds to calculate. This occurs multiple times on the same page and is really causing some slowdown. I would like to run this method asynchronously with the page so that the value appears once it is calculated.
Currently this is how the value is called and displayed (within the Index.cshtml view):
<div>Blocked: #item.GetNumJiraIssuesByStatus("Blocked")</div>
<div>Open: #item.GetNumJiraIssuesByStatus("Open")</div>
I would like the #item.GetNumJiraIssuesByStatus (both Open and Blocked) to be done with Ajax. Here is the method within the Model:
public int GetNumJiraIssuesByStatus(string status)
{
var sJql = "project = \"" + JiraProjectKey + "\" and status = " + status;
//apply a 'result field' filter simply to reduce the amount of data being returned. Any field will do - use of 'resolution' is entirely arbitrary.
var resultFieldNames = new List<string> {"resolution"};
Issues issues = new JiraClient(new JiraAccount()).GetIssuesByJql(sJql, 0, 1000, resultFieldNames);
return issues.total;
}
I have been trying to instead get this done by having a span which populates with the value when the AJAX is done:
$(".jiradata").each(function (i, el) {
var $el = $(this);
$.get("/Project", { s: "open" }, function (data) { text; })
})
Although this does not work properly. Does anyone know what I can do?
Thanks!
I just wanted to know, what is the elegant way of populating the observable properties after posting json to the server.
my js
var vm = (function() {
var commit = function(item) {
var model = {
Name: item.name(),
IsActive: item.is_active()
};
$.post('/to/server/Post', model);
.done(function(d) {
item.id(d.Id);
});
}
}());
in my server
public JsonResult Post(itemVm model)
{
var item = new Item
{
Name = model.Name,
IsActive = model.IsActive
};
// do saving here and commit to database
model.id = item.Id;
return Json(model, JsonResultBehavior.DenyGet);
}
While above snippet will work. I find it hard to maintain it this way, is there an elegant or another way of doing this? I need the returned Id for update later on.
Btw, I'm using ASP.NET MVC 5, KnockoutJs
Any help would be much appreciated. Thanks
First try to relate the things.
I have a dynamic created div which I was loading from $().Load()
something like this
$(elem).load("BarChart");
Note: elem id dynamically created div at the same moment
untill this all working fine but now I want to send selected Data
something like this
$(elem).load("BarChart",{Values: values});
Note: BarChart is Partial View. which is calling Controller Method but not able to find the values passed from load
controller Method
public ActionResult BarChart(List<String> Values)
{
foreach (var v in Values)
{
lstPointSeries = Utility.GetPointSeries(Session["DbName"].ToString(), Session["AccountGroupName"].ToString(), null, AggregrationType.Total, v, null);
}
ViewBag.pointSeries = lstPointSeries;
return PartialView();
}
Note: Values is null
EDIT:
var values are list of selected checkbox from UI. like this
something like this
values = ["first","second","third","fourth"];
var values = $('input:checkbox:checked.XAxisrowCheckbox').map(function () {
return $(this).closest('td').next().text();
}).get();
I tried your code, and it works fine
Try this:
url = urlHelper.CommonHelper("", "About", "TestAction");
$("#TestDivId").load(url, { Values: ["aaa","bbb"] });
public ActionResult TestAction(List<string> Values) { return View(); }