Reputation: 3064
I have few jquery tabs on a usercontrol that loads a separate user control under each. Each user control is unique. It all works fine right now but the overall page response is too slow. In order to improve performance I am trying to load few user controls under these tabs on demand (that is on click of tab). Possibly without post back... ajaxish. Can anyone guide me? I tried to follow this tutorial and this one too but did not have any success. I have attached the code for parent usercontrol.
<ul id="tabs">
<li class="active">Rewards</li>
<li id="liCoupons">Coupons</li>
<li id="liLibrary">Library</li>
<li id="liProducts">Favorite</li>
<li id="liPreferences">Preferences</li></ul><ul id="tabPanes" class="rewardsTabs">
<li>
<div class="wrapper active">
<uc:Rewards ID="wellness" runat="server" />
</div>
</li>
<li id="liCoupons">
<div class="wrapper">
<uc:Coupon runat="server" />
</div>
</li><li id="liLibrary">
<div class="wrapper">
<uc:Library runat="server" />
</div>
</li><li id="liProducts">
<div class="wrapper">
<uc:Products runat="server" />
</div>
</li>
<li>
<div class="wrapper">
<div class="preferences">
<uc:Preferences runat="server"/>
</div>
</div>
</li>
Upvotes: 10
Views: 8260
Reputation: 1759
an asnwer (not mine) to this question is probably useful to you:
Asynchronous loading of user controls in a page
it states that there are problems with this with needing a form on the user control to post back, but that should be ok to have independent forms with ajax post. you'll have to think about what happens when posting the form(s) on the page, but shouldn't be insurmountable. shouldn't be any reason you couldn't just make it the ashx handler you have mentioned.
Upvotes: 0
Reputation: 2445
I think the best solution is to implement client call back
http://msdn.microsoft.com/en-us/library/ms178210.aspx
When user clicks on some tab,onclick event calls js func with name of tab as parameter, than that tab calls server code with same parameter.
Than in code you load controls you want depending which tab is clicked. Now you need to render controls into html and send tham back to js function. Now you have controls in js function, find where you want to insert code an insert it.
that should work in theory and it is not to complicated :))
Upvotes: 3
Reputation: 2562
In my opinion, the fastest solution to your problem (but not necessarily the best long-term) is to wrap all your UserControl
s in a .aspx page. In this situation, you'd just have to move your parent UserControl
markup to a new .aspx page, and call it via AJAX.
Assuming that you called this page something like Menu.aspx, and further assuming that you don't need any data passed into this page (that is, it can track all of its own data internally), your jQuery AJAX call would look something like this:
function GetMenu ($placeholder) {
$.ajax({ type: "POST", contentType: "application/json; charset=utf-8", dataType: "json",
url: "Menu.aspx",
done: function (result) {
$placeholder.html(result.d);
},
fail: function () {
$placeholder.html("Error loading menu.");
}
});
}
Some notes:
done
and fail
will replace success
and error
in jQuery 1.8, so any jQuery AJAX you use should plan for this transition.Depending on your feelings about tightly-coupled HTML/JavaScript, you could replace $placeholder
above with a callback function. Calling that from your the page where your menu resides would look something like:
$(document).ready(function () {
GetMenu(MenuCallback);
});
function MenuCallback(menuHtml) {
$("#menu").html(menuHtml); // I'm assuming the ID of your ul/span/div tag here.
}
Some people (myself included) use the $
prefix to differentiate between JavaScript and jQuery variables. So here, $placeholder
is a jQuery variable.
$.ajax
call as a type: "GET"
, which would be a little bit more efficient, but I'm not sure if the UserControl
s would cause problems in that regard. Normally, if I'm loading an entire .aspx page via AJAX, I use GET
instead of POST
. You don't have to change much to try it out: just switch out the type
property and change result.d
to result
.Upvotes: 3
Reputation: 718
You will need to make an Ajax call in order to make this. now you have options to call AJAX:
1 - Call via SOAP web service (ASP AjaxScriptManager referencing will be needed for every web method).
2- Call via WCF Service as the previous answer.
3 - Call via Rest service.
4- Call via Jquery ajax method but the request must going to external page like "Actions.aspx" so when you call your method an HTTPRequest will be made into Actions page then it will have the returned data within its response. $.Ajax(url,data,action,successMethod); // this is the fastest way I tried them all.
Here is what you should to do: 1- on the change tab event call your method by using the appropriate Ajax calling method from the above options.
2- from the success method use the returned data but it's better for you to use eval(data) for the DataTime objects.
here is some example explains how to make this call:
var helper = {
callAjax: function(sentData, successFun) {
jQuery.ajax({
url: "/Actions.aspx",
type: "Get",
data: sentData,
cache: true,
dataType: "json",
success: successFun
});
}
};
helper.callAjax('request=getCities&countryID=' + countryID, function (args) {
var result = eval(args); // this object will contain the returned data
var htmlData = '';
for (var i=0;i<result.length;i++){
// write your HTML code by jQuery like this
htmlData += '<div>' + result[i].title + '</div>';
}
$('#tab3').html(htmlData);
});
now at the Actions.ASPX code use the following:
protected void Page_Load(object sender, EventArgs e)
{
object _return = new
{
error = "",
status = true
};
JavaScriptSerializer _serializer = new JavaScriptSerializer();
if (!Page.IsPostBack)
{
string str = Request.QueryString["request"].ToString();
switch (str.ToLower())
{
case "getcities":
int countryID = Convert.ToInt32(Request.QueryString["countryID"].ToString());
_return = JQueryJson.Core.City.getAllCitiesByCountry(countryID).Select(_city => new
{
id = _city.ID,
title = _city.Name
});
_serializer = new JavaScriptSerializer();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "text/json";
Response.Write(_serializer.Serialize(_return));
break;
}
// etc........
}
Upvotes: 5
Reputation: 1298
The second link you mentioned should work. You don't need to define any user controls in your markup.
<ul id="tabs">
<li class="active">Rewards</li>
<li id="liCoupons">Coupons</li>
<li id="liLibrary">Library</li>
<li id="liProducts">Favorite</li>
<li id="liPreferences">Preferences</li>
</ul>
<div id="results" class="wrapper"></div>
Each tab click will do an ajax call
$.ajax({
type: "POST",
url: "Default.aspx/WebMetodToCall",
data: data, // I wouldn't prefer passing webmethod name here
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$('#result').html(msg.d);
},
failure: function (msg)
//error
}
});
to the web methods.
[WebMethod]
public static string Rewards()
{
return RenderControl("~/controls/rewardsControl.ascx");
}
[WebMethod]
public static string Coupons()
{
return RenderControl("~/controls/couponsControl.ascx");
}
...
Each method will render only the requested control. Also in your method you can keep or extract the viewstate depending on your needs. After rendering, the webmethod should pass back the html string to be injected into the placeholders.
If you tried this and were successful rendering one control at a time but still seeing slowness then you have some back end issues while getting the data. If your controls are data heavy I would recommend doing some server side caching.
Hope this helps.
Upvotes: 12
Reputation: 91
You should go for the second link using jquery and webmethod. That way you will actually populate the tabs on demand without making you page heavy.
Upvotes: 3
Reputation: 2921
perhaps use an anchor that points to the service defined below. For instance,
<li><a href="...webservices/ControlServce.svc/Content?cType=Rewards" class="wrapper active"></a></li>
/// <summary>
/// Service used by ajax for loading social media content
/// </summary>
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ControlService
{
/// <summary>
/// Streams html content
/// </summary>
/// <param name="type">type of control</param>
/// <returns>html stream of content</returns>
[OperationContract]
[WebGet(UriTemplate = "Content?cType={cType}")]
public Stream GetContent(string cType)
{
var tw = new StringWriter();
var writer = new Html32TextWriter(tw);
var page = new Page();
var control = page.LoadControl(cType);
control.RenderControl(writer);
writer.Close();
var stream = new MemoryStream(Encoding.UTF8.GetBytes(tw.ToString()));
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache");
return stream;
}
}
Upvotes: 5
Reputation: 12703
If you adjust it a little with jquery, this should work:
http://blogs.msdn.com/b/sburke/archive/2007/06/13/how-to-make-tab-control-panels-load-on-demand.aspx
Or you just use the asp.net tabs.
Upvotes: 3
Reputation: 49195
Does your user controls rely on post-backs and view-state for there working? It will be relative easy to fetch the user control HTML to be displayed in the tab using AJAX but then post-back on that control will send the entire data to the actual page (that may not have the user control loaded). So the basic outline would be
Upvotes: 6