In my partial view I have a dialog box and a fancy tree is rendered. From the view on the list box change event I load the tree. When the tree is loaded I check to see if cache exists and if it does I pull from cache and if not then build and add the list into cache.
Cache itself is working correctly, but the method which pulls data to a list to be added to cache seems to pull older values. Since this method is trigged by ajax on this view, I suspect the issues lies within, I have tried to set no cache attribute in controller action method as well as sending a hard code cache bust paramater but to no avail.
JS Listbox change event
$('#SystemID').change(function () {
var userroleid = $("#UserRoleID").val();
// if (userroleid != 1) {
$("#treeview").remove();
$("#partTreeView").remove();
var overlay = $('<div></div>').prependTo('body').attr('id', 'overlay');
$.ajax({
type: 'POST',
url: serviceEntryURL,
cache: false,
datatype: "html",
data: $("#form").serialize(),
success: function (result) {
$("#main").html(result);
overlay.remove();
}
});
});
View Rendering the Tree
<div id="errorCodes">
#Html.RenderTree(CacheHelper.ErrorCodes(#Model.ErrorCodeType), ec => ec.Name, ec => ec.Children.ToList(), ec => (ec.ID).ToString(), Model.ErrorCodes, "error")
</div>
Cache Helper
if (HttpRuntime.Cache[cacheKeyRemove] != null)
{
ERRORCODES = (List<Domain.Lists.ErrorCode>)HttpRuntime.Cache[cacheKeyRemove];
}
else
{
**//The following method GlobaList.ErrorCodes is not cached or anything but it still returns
older values. **
ERRORCODES = RunLog.Domain.Lists.GlobalList.ErrorCodes(instrumentTypeID);
HttpRuntime.Cache.Add(cacheKeyRemove, ERRORCODES, null, DateTime.Now.AddHours(10), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}
Error Code Edit Page
If I go to this view and edit the error code and the cache key is removed successfully. When I go back to the view where i render tree, since this cache was removed, it queries the above method to build the error code list but the value I had just edited is not the correct and the old one. Whats even more weird is if I add a new record to my error code table and cache is reset, then the new record shows up correctly in the other view.
while (enumerator.MoveNext())
{
if (enumerator.Key.ToString() == cacheKeyRemove)
{
HttpContext.Cache.Remove(enumerator.Key.ToString());
}
}
I experienced such error one time, It was a caching problem. In order to solve this problem, each time I send a new ajax request, I appended the url with a new random number.
Hope this helps you.
for example suppose the url is:
http://localhost/app1/getData?id=randomNb
Related
I have a cascading dropdown like for eg first dropdown shows the list of countries and based on the selection of countries the next dropdown gets populated. The problem is that in development environment it's working fine but when deployed in a server the first dropdown gets populated correctly as it's elements come from resource file and after selection of first drop down I get an error.
JS :
<script>
$(document).ready(function () {
$("#Site").change(function () {
var SelectedVal = $(this).val();
$("#Model").html('');
$("#Model").append($("<option></option>").attr("value", '')
.text(' '));
if (SelectedVal != '') {
$.get("/Home/GetModelList", { Sid: $("#Site").val() }, function (data) {
$("#Model").empty();
$("#Model").html('');
$("#Model").append($("<option></option>").attr("value", '')
.text(' '));
if (data.modelAlert != null) {
alert(data.projectAlert);
}
$.each(data.models, function (index, item) {
$("#Model").append($('<option></option>').text(item));
});
});
}
})
});
</script>
Controller :
public JsonResult GetModelList()
{
List<string> models = db.GetModels();
string modelAlert = alert.GetAlert();
var result = new { modelAlert, models };
return Json(result, JsonRequestBehavior.AllowGet);
}
The error message that I get is
Failed to load resource: the server responded with a status of 404 (Not Found) Home/GetModelList?Sid=Ind:1
I checked for similar problems like this and it was all about the JS path or the controller path but I've already given the absolute path. Can someone let me know where am I going wrong, let me know if any additional data is needed.
Thanks
$.get("/Home/GetModelList", { Sid: $("#Site").val() }, function (data) {
The above line was causing the routing problem, usually when we call a controller action from js in this way there tends to be a routing problem due to the folder structure reference. In order to avoid this routing problem and to be more clear we can also call controller action from js like below
$.get('#Url.Action("MethodName", "ControllerName")', function (data) {
This resolved my issue.
So basically I'm trying to show some Profile Data in my MVC Application.
Right now, everytime I click on a date on my Telerik Kendo Calendar, I can refresh the whole page and update the data I want.
However, instead of refreshing the whole I just want to refresh the partial views that shows only the data that updates after selecting the date.
Index.cshtml
<!--CODE-->
#Html.Partial("_WorkingTimeData")
<!--CODE-->
_WorkingTimeData.cshtml
var workedTime = ViewData["WorkedTimeToday"];
var hoursPerDay = ViewData["HoursPerDayContract"];
<p>You worked #workedTime hours</p>
<p>Hours Per Day (Contract) #hoursPerDay Hours</p>
Yes, right now I'm ViewDatas and it works.
This is the ajax code in Index.cshtml
$.ajax({ url: '/Profile/Index',
dataType: "json",
type: "POST",
data: JSON.stringify(10),
success: function(returl){
alert('It worked');
location.href=returl.Url;
},
error: function(jqXHR,responseText,textStatus){ alert(jqXHR.responseText) } });
Controller
[HttpPost]
public ActionResult Index(string number){
//THINGS TO DO
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Profile");
return Json(new { Url = redirectUrl });
}
Well I'm very new to this, and I've been doing my research. However I still have some questions:
- Do I need to create a post method for _WorkingTimeData instead of Index like I have?
- Do I need to create a ViewModel for the Partial View?
Thanks
EDIT NUMBER 2 FOR VISHAL:
This didn't work at all, not even an alert, because, strangely, it doesn't recognise the calendar...
$("#calendar").kendoCalendar({
change : function() {
$.ajax({
url: "/Profile/WorkingTimeData",
type: "get"
}).done(function(data) {
$("#profile-timeline").html(data);
});
}});
It says $("#calendar").kendoCalendar is not a function (Telerik says that it's this way)
As for this, it reached the controller but didn't update anything:
function change() {
alert("Escolheste outro dia");
var calendar = $("#calendar").data("kendoCalendar");
var current = calendar.current();
alert(current);
$.ajax({
url: "/Profile/WorkingTimeData",
type: "get"
}).done(function(data) {
$("#profile-timeline").html(data);
});
}
I think it's because of the profile-timeline... It's a div in my view
Do I need to create a post method for _WorkingTimeData?
Yes, you need to create. But, Get would be fine too.
Do I need to create a ViewModel for the Partial View?
Not needed. If required you can create.
But, by looking at your partial view you are just using ViewData[""]. So, you need not to create any ViewModel.
Just create a method in Controller returning _WorkingTimeData PartialView.
And call that method by JQuery ajax on your DatePicker change event and replace the contents of the Div.
For example.
Controller
public PartialViewResult WorkingTimeData()
{
ViewData["WorkedTimeToday"]="NEW VALUE";
ViewData["HoursPerDayContract"] = "NEW VALUE";
return this.PartialView("_WorkingTimeData");
}
JavaScript
$("DATEPICKERELEMENT").change(function() {
$.ajax({
url: "/CONTROLLER/WorkingTimeData",
type: "get"
}).done(function(data) {
alert(data);
$("#divisionIdContainingPartialView").html(data);
}).fail(function() {
alert('error');
});
});
I wrote a post that details why you need to break the logic of thinking about partial views client-side. If you're interested you can find it here.
The TL;DR version is simply, all you have client-side is HTML. There's no knowledge about what was or was not rendered to the response via a partial view. As a result, the real question is "How do I change a portion of my HTML page based on an AJAX response?". In the simplest form, you simply select some element on the page and then alter its inner HTML. You can do that with some custom HTML created client-side or you can actually pass back an HTML document as your AJAX response and then insert that.
So I have a Partial view that loads in with:
#Html.Partial("_partial", Model, new ViewDataDictionary { { "DisplayCheckbox", true } })
Within that _partial page is a loop that looks like this
#foreach (var w in Model.WeekEndingDateRange)
{
<th>#w.WeekEndingDate.FormatDate()</th>
}
which creates table headers for a jquery tinytable (that is later populated with data in my view).
The problem I'm having is that the Model.WeekEndingDateRange can change. When the user presses a button to filter results shown on the table, it makes an ajax call to my controller that looks like this
function filterResults(){
//do some stuff like creating "model"
$.ajax({
type: "POST",
url: "#Url.Action("FilterTable", "Report")",
data: model
})
.done(function (data) {
//continue on to populate table data
So when the ajax call finishes I can make a call like:
data.WeekEndingDateRange
to grab the list which I want the partial to loop through. This will create (size of the data.WeekEndingDateRange list) amount of headers for the table.
Therefore I need a way for the partial to not grab Model.WeekEndingDateRange but instead to grab data.WeekEndingDateRange. This way, before the table is filtered, the partial will create no headers (because no information is populated in the table) and as soon as the user filters their results, the table will create a new header for each element in data.WeekEndingDateRange.
I've already tried doing:
#Html.Partial("_ProjectAllocationReport", data, new ViewDataDictionary { { "DisplayCheckbox", true } })')
after my ajax call, but this won't work because data is out of scope.
Any help would be greatly appreciated!
I would suggest you just leverage your view. You actually DO want the partial to grab Model.WeekEndingDateRange. The problem is that your not updating the Model's WeekEndingDateRange.
So your ajax call would be something like
function filterResults()
{
$.ajax({
type: "POST",
url: "",
data: model,
datatype: "html"
}).done(function(html)
{
$("HeaderElementHere").html(html);
});
}
And in your controller, do
Model.WeekEndingDateRange = data.WeekEndingDateRange
#Html.Partial("_partial", Model, new ViewDataDictionary { { "DisplayCheckbox", true } })
All you are really wanting to do is pass up some end date that your View uses for it's loop to generate your HTML and then pass that back down in the ajax call to be put into your page.
I have two asp:BulletedLists, one is populated on Page_Load and the other is empty. The user can drag and drop < li >'s between them, the meat of that drag-n-drop is
function Move(element, source, target) {
var newLI = document.createElement("li");
var sourceBL = document.getElementById(source);
var targetBL = document.getElementById(target);
newLI.innerHTML = element.innerHTML;
sourceBL.removeChild(element);
targetBL.appendChild(newLI);
}
I create a new element so that it aligns itself within the asp:BulletedList rather than placing itself where the mouse is released.
The problem is I need to know what is where on postback, the second asp:BulletedList is always empty and the first asp:BulletedList populates itself with the original values even though I do not clear or repopulate them.
foreach (ListItem li in blSelectedDocuments.Items) // .Items is empty
{
}
In the past with working with jQuery plugins on ASP.NET WebForms pages, I have used AJAX to send the updated data back to an ASP.NET AJAX Page Method and then stored the changes into Session cache. Then upon postback, the Page_Load would look into the Session to see what order the values in the list were (I had a drag and drop list for the order of display of a report).
Mock code example:
JavaScript:
function Move(element, source, target) {
var newLI = document.createElement("li");
var sourceBL = document.getElementById(source);
var targetBL = document.getElementById(target);
newLI.innerHTML = element.innerHTML;
sourceBL.removeChild(element);
targetBL.appendChild(newLI);
// TODO: Serialize source and target lists to JSON to pass to the server
var serializedData = {};
// Use jQuery.ajax() to call ASP.NET AJAX Page Method
$.ajax({
type: "POST",
url: "PageName.aspx/UpdateListsInSessionCache",
data: serializedData,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
// Do something here when the AJAX calls completes
}
});
}
ASP.NET Code-behind (C#)
using System.Web.Services;
[WebMethod]
public static void UpdateListsInSessionCache(List<ListItem> source, List<ListItem> target)
{
Session["SourceList"] = source;
Session["TargetList"] = target;
}
protected void Page_Load(object sender, EventArgs e)
{
// Create new lists so we have something empty and not null to work with
var source = new List<ListItem>();
var target = new List<ListItem>();
// Always check for values in Session cache and update if there are values
if (Session["SourceList"] != null)
{
source = Session["SourceList"] as List<ListItem>;
}
if (Session["TargetList"] != null)
{
target = Session["TargetList"] as List<ListItem>;
}
// Do something with source and target lists
}
Horrifically, none of that worked. I'm on SharePoint and the Session wasn't enabled (or whatever) because of some deep dark corner of SharePoint that the asp.config file is located in. Neither did ViewState work in the similar manner. Maybe the AJAX half of that would have worked, but I never got that far.
The solution I got to work was to create a hidden input field, write the order of the asp:BulletedList to that hidden field to go with the postback via the Submit button. Thanks JasonP for serialisation fiddle.
NOTE: I tried some other suggestions I found on the web, using a Label/TextBox with ViewState and/or Readonly properties set did not work for me. Label worked to change text within the page but did not persist on postback.
I have an ASP .NET MVC application, additonally I am using Knockout 2.0.0. I created a partial view which I would like to render to the page using knockout. The partial needs to be rendered within a Knockout foreach statement. I am unable to get the knockout HTML binding to work, and so I'm currently using a hack to put the html into the div using JQuery.
There is a lot of html on this page, so it's not possible to post all of the source code, so I will try and post the pertinent code:
<div data-bind="foreach:issues">
#* SNIP - A lot of other html here*#
<div id="myPartialDiv" data-bind="html: $parent.getHtml(issueId())">
</div>
</div>
Further down I have the following javascript function on my KO View Model (I have commented out my hack and included the code that returns HTML):
var getHtml = function (issueId) {
var baseUrl = '#Url.Action("GetHtmlAction","MyController")';
$.ajax(
{
type: "POST",
url: baseUrl,
data: "&issueId=" + issueId,
success: function (data) {
//$('#mypartialDiv').html(data);
return data;
},
error: function (req, status, error) {
//$('#myPartialDiv').html('Something went wrong.');
return 'Something went wrong.'
},
dataType: "text"
});
}
The code above results in no data being rendered to the page. USing Chrome debug tools, I see that there are no javascript errors occuring, and knockout is simply not binding the html of the div to the results returned from the getHtml function.
What am I doing wrong?
Thanks
As Miroslav Popovic explains, the problem is that the AJAX request is asynchronous, so the return data is ignored and there is no return value from your call to getHtml.
I would suggest using a custom binding that handles the asynchronous HTML loading (I've put a working example here).
This works by taking 2 parameters to the asyncHtml: a function to call that takes a success callback as it's final parameter (plus any other parameters) and an array of the parameters that need to be passed to that function.
<div id="myPartialDiv" data-bind="asyncHtml: { source: getHtml, params: [123] }">Loading...</div>
The custom binding then grabs these values, concats a custom callback onto the parameters that are passed to it, and calls the specified function:
ko.bindingHandlers.asyncHtml = {
init: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var parameters = value.params.concat([function(data) {
$(element).html(data);
}]);
value.source.apply(null, parameters);
}
};
Finally we can re-implement our view model HTML-retrieving method to make the POST call and invoke the new success handler:
var ViewModel = function() {
this.getHtml = function(issueId, callback) {
$.ajax(
{
type: "POST",
url: "/echo/html/",
data: {
html: "<p>server response " + issueId + "</p>",
delay: 1
},
success: callback,
dataType: "text"
});
};
};
Note: for this example I am using the jsFiddle echo to post back a random response
$.ajax is an asynchronous call. When you call it, the execution will just continue to the next statement in the getHtml function. Since this is the last statement, the getHtml function will return undefined.
About your return data;... This return is within a success callback function. The data will be result of that function, not the parent getHtml function. Besides, getHtml is already completed. You can't return a result from it.
How about having an observable property in your view model called html, and then find some other means of triggering the getHtml function (button click, some other success callback, issueId property change...), that will in turn set the 'html' property value. Then you could simply data-bind to that property data-bind="html: html".