Loading UserControl via AJAX, and posting back to the server - asp.net

Summary
Is it possible to dynamically download the contents of a UserControl via AJAX, insert that into the HTML, post-back the page to the server and for the server to be able to process the dynamically loaded controls?
In particular I'm looking at doing this multiple times, to create the ability to "add rows" to an existing table structure in the page.
More Detail
I have already written ASP.NET code that successfully downloads the contents of a UserControl via AJAX using the <asp:ScriptManager>, and for that new downloaded HTML to be placed into the current document in the correct position.
This is fine, because all saving of data takes also takes place via AJAX, so it's simple for me to build the data to return to the server.
Part of the problem is that if the UserControl had been loaded as part of the original page, the controls within it would have been given UniqueId along the lines of...
ctl100$container$repeater$ctl100$myTextBox
But when loaded outside of the structure via the AJAX route, it is given a UniqueId along the lines of...
ctl100$myTextBox
... with the result that (obviously) the server doesn't know what to do with it.
So what I'm looking to do is be able to download dynamically a usercontrol, and be able to post that back as part of the page.
What is the standard approach to achieving this?

The standard ASP.NET Web Forms approach is using of UpdatePanel control. There are a lot of functionality like controls state maintaining, events handling, request validation that requires that server controls must be rendered and added to page's control's tree on postback.

Related

How can I do a partial page update with ajax using Sitecore?

I have a specific page (sitecore content item) in my web application composed of a sitecore layout and many sublayouts. One of those sublayouts is a user control that I would like to have refreshed once a certain button is clicked. I would like only that sublayout to be refreshed and the rest of the page to remain unchanged (typical ajax situation here). How do I accomplish this with sitecore when all of my sitecore content items are directly related to a full page in my web application (layout with sublayouts)? In my case, I want to use ajax to return the content of a specific, single sublayout only. What is the best practice for this kind of ajax situation with sitecore? I'm using sitecore 6.5.
Since you use the phrase "partial page update", I assume you are using an UpdatePanel. This doesn't really function any different than it would in a traditional ASP.NET application. You will handle the button click in a server-side handler method, modify properties on controls and let the update panel handle the rest.
If you are not using update panel, you have a few options depending on exactly what you want to achieve.
Typically, if you are clicking a button to trigger an ajax request, you are posting some data back to the server. For this case you would usually set up a web service to process the data and return some result. Your service can access Sitecore data, but does not utilize the Sitecore presentation engine.
Another option would be to make the request to a Sitecore page (possibly the same as the original request), but include a querystring parameter to trigger a different device. You could configure this device to render JSON, XML or a fragment of HTML rather than the normal Layout and battery of sublayouts.
Another option would be to use the Sitecore Item Web API. If you go this route, you will have another array of options (and a bit of a learning curve as well). Start by reading the documentation on SDN or some of the many blog posts on the topic.
There are a number of options available for achieving asynchronous behavior. None of these really relate to Sitecore directly, however, there are some Sitecore specific things to watch out for which I have highlighted below.
UpdatePanel Control
If you are performing something trivial where ultra-fast performance isn't a concern, simply wrap your button (and any other .NET controls that you would
like updated) in an UpdatePanel Control. You will also need to drop
a ScriptManager control into your base layout near the top inside
the <form> element. NOTE: When using this method, you will need to ensure that that your Sublayout does NOT have caching enabled, otherwise your button will not postback properly
Create your own web service
In this scenario, there are many client-side frameworks available for achieving the same result. My preferred method is to hook onto the client-side button click event with jQuery, prepare a request object, and post it to the server (getting back the information you need to update the client).
Here are a number of web service options that work with Sitecore - allowing you to have access to the Sitecore.Context and all of the subsequent Sitecore APIs.
Create an empty ASPX Web Form that accepts parameters as query strings. In the Page_Load method, do some work with the parameters and write directly to the response using Response.Write(). A JavaScriptSerializer comes in handy for serializing to JSON, just be sure to set Response.ContentType = "text/javascript";
Create an ASMX Web Service and decorate your methods with [WebMethod] (or [WebMethod(EnableSession = true)] if you need access to Session data).
Use MVC Controllers (ex: ASP.NET Web Api) to create an API. I believe there are some issues to work around in Sitecore 6.5 as described here.
Since this is all contained within a single Sublayout, you could simply use a standard <asp:UpdatePanel> surrounding your button and the usercontrol. In the code-behind, you can then do whatever databinding / data retrieval necessary to update the content of the usercontrol.
Note, if the button was on a different sublayout to the one where the content needs to be updated, you can use the approach described in this question as long as both controls have their content within <asp:UpdatePanel>.
In answer to your other question:
What is the best practice for this kind of ajax situation with sitecore?
There's not really a Sitecore-specific best practice for this sort of thing. In this case, any approach which works for plain ASP.NET will also work with Sitecore. The approach I described above is probably the simplest and quickest to implement, but you could also do this via jQuery and ajax to call a web service to load updated content.

FindControl won't find my dynamically added UserControl

I'm working on a project where the page load certain controls depending on the index available. The loading occurs in the page load where the method PopulateSearchField is called.
Within this method, all the UserControl are added on the page using : Page.LoadControl("path");
The page load and all the required controls are on the page. My problem is when the user click on the Search button the event is triggered and a query is built based on the user input int those controls. Unfortunately, the method isn't able to produce a proper query as it is unable to find any of the controls on the page.
With a temporary ControlCollection variable, I've been able to see that the number of controls on my page is 3 when it should be something from 4 to 10. Those 3 controls in the collection are the static label and buttons on the page.
I don't know if something is wrong with the code or if it's a page cycle problem as this solution used to work on framework 1.1. Yeah, I know this isn't the best thing to do so, but they did it this way and I gotta make it work.
I'm not sure if it is the migration that has caused the problem or not.
Thanks a lot, David!
When you click the button, the controls are no longer available server side when your click handler is being processed. The page, server side, has no knowledge of the controls you created dynamically since there are no server side controls for the posted values to map to. If you want to find the values, you need to inspect the posted control data and not rely on the server side asp.net control heirarchy.
You could also write all the data you require to a hidden field via javascript and then read the hidden data server side since it will will be posted.
The following is occuring:
Creating controls dynamically
Posting controls data on click
ASP.NET maps the data to the existing controls it knows about.
Your controls are not found so the data is no mapped to anything.
You need to add your controls before the mapping occurs (in PreInit). Check out the Page Lifecycle and you will see how it ties all the controls and data together.
Are you re-adding the controls to the new page when the user clicks search?
Remember... every time the user hits your server for that page... a new Page object is created. If you're dynamically adding controls, you have to do it every time the page loads.
Additionally, since you seem to want to get values out of the controls, you're going to have to make sure that the controls are created with the exact same ID property every time, and created before viewstate is loaded, if you want them to retain their values.

aspx ashx mash-up

I'm retro-fitting a .aspx page with AJAX functionality (using VB, not C#). The codebehind populates the page with data pulled from a web-service. The page has two panels that are populted (with different data, of course) in this way. On a full page refresh, one or both panels might need to be populated. But populating Panel 2 can take a long time, and I need to be able to update panel 1 without refreshing Panel 2. Hence the need for AJAX (right?)
The solution I've come up with still has the old .aspx page with .aspx.vb codebehind, but introduces a Generic Handler (.ashx) page into the mix. Those first two components do the work on the user's first visit or on a full page refresh, but when AJAX is invoked, the request is handled by the .ashx page.
First question: Is this sound architecture? I haven't found a situation online quite like mine. Originally, I wanted to make the .aspx page into the AJAX handler by having the codebehind implement IHttpRequest, and then providing "ProcessRequest" and "IsReusable" methods, but I found I couldn't separate a regular visit to the page from an AJAX request, so my AJAX handlers took over even on the first visit to the page. Second question: Am I right to think that this approach (making the .aspx page do double-duty as the AJAX handler) will never work? Is it impossible to tell whether we're getting a full-page request or a partial-page (AJAX) request?
If the architecture is good, then I need to dynamically generate a lot of HTML in the .ashx file, right? If that is right, should I send HTML back to the client, or should I encode it in some way? I've heard of JSON encryption, but haven't figured out how to use it yet. So, Third question: Is "context.Response.Write" the only pipeline for sending data back to the client? And, if so, should I send back HTML or some kind of JSON-encoded objects?
Thanks in advance.
It sounds as if the page requires some AJAX functionality added to the UI.
Suggest using an UpdatePanel for each web form element that needs to have AJAXy refresh
functionality. That'll save you from having to refactor a bunch of code, and introduce a whole lot of HTML creation on your .ashx.
It'll be more maintainable over the long run, and require a shorter development cycle.
As pointed out by others, UpdatePanel would be a easier way - but you need to use multiple update panels with UpdateMode property set as conditional. Then you can trigger the update-panel refresh using any button on the page (see AsyncPostBackTrigger) or even using java-script (see this & this). On the server side, you may decide what has triggered the partial post-back and act accordingly by bypassing certain code if not needed.
You can also go with your approach - trick here is to capture the page output using HttpServerUtility.Execute in your ashx and write it back into the response (see this article where this trick has been used to capture user control output). Only limitation with this approach is that you can only simulate GET requests to your page and so you may have to change your page to accept parameters via query string. Personally, I will suggest that you create a user control that accept parameters via method/properties and will generate necessary output and then use the control on your page and in ashx (by dynmaically loading it in a temperory page - see this article).
EDIT: I am using jquery to illustrate how to do it from grid-row-view.
$(document).ready(function() {
$("tr.ajax-grid-row").click(function() {
$("#hidden-field-id").val($(this).find(".row-id").val()); // fill hidden filed
$("#hidden-button-id").click(); // simulate button click
});
});
You can place above script in the head element in markup - it is assuming that you have decorated each grid-row-view with css class "ajax-grid-row" and each row will have hidden field decorated with css class "row-id" to store row identifier or the value that you want to pass to server for that row. You can also use cell (but then you need to use innerHTML to get the value per row). "hidden-field-id" and "hidden-button-id" are client ids for hidden field and submit button - you should use Control.ClientID to get actual control ids if those are server controls.
JSON is not for that purpose, it is to pass objects serialized with a nice light weight notation, is you need to stream dinamically generated html using ashx, response.Write is what you have. You may want to take a look at MVC
Or you could use jquery if it's just html, the simpliest would be the load function, or you can look into Ajax with jquery. Since the ashx can be served as any resource it can be used in the load function.
I agree with #p.campbell and #R0MANARMY here. UpdatePanel could be the easiest approach here.
But then like me, if you don't want to go the UpdatePanel route, I don't see anything wrong with your approach. However, generating the html dynamically (entirely) at the back end is not a route I'll personally prefer (for the maintainence reasons). I'd rather prefer implementing a solution that will keep the design separate from the data.

ASP.NET 2.0 -how do I include files containing server-side code?

I want to be able to load a customized log in page depending on a couple of parameters passed into the querystring.
Each customized login page needs to be able to dynamically display log in errors and possibly have other variables passed in.
Let's say the dynamic login page looks like this (over-simplification here):
<form>
<% if (has_errors) { Response.Write(error_msg); } %>
<input type="text" name="email">
</form>
If the aspx page loads the file like this:
Response.writefile("path/to/custom/page");
the code shows up in the output and doesn't get processed. I have tried other ways to load the file contents (something similar to classic ASP includes) but get the same results every time.
I could have all the custom pages set up as user controls, but I need 100% control over the css, js, and html - and the documentation I read here indicates that I won't have that level of granularity.
link text
PLUS - I'm stuck in a .net 2.0 environment - so .NET MVC is not available to me
Any help/suggestions?
but I need 100% control over the css,
js, and html
You won't get 100% over the page but you will have control inside the User Control instance. Also, many times, you can override these technologies like CSS, from within your control.
In the end because all controls are solified into one big HTML page you will have the same level of control as you would in any single web page with client-side technologies.
You can build a Web UserControl to represent log/in and then include an instance of that control onto any page, in any place, across multiple pages if you wish.
(See the Topics on that MSDN help page about how to create and use it).
Other useful references (these are various angles on the same subject).
Creating a Web user Control in .NET
ASP 101 - User Controls
This should provide a good start to keep looking, if this is the kind of info you think you need.
Internals
The User Control can have its own logic, access the browser querystring, access the page Session, Application, etc. pretty much anything it needs to know for itself to work.
Object Oriented
Additionally, because a User Control is also an object, you can add your own public methods and properties to it through which you can interact to communicate with the control intance on the page (just like you interact with other web controls like Button.Text="click", TextBox.BackColor = System.Drawing.Color.Blue, etc).
Other Options - Dynamic control loading
You might want to consider loading controls dynamically at runtime using the Page.LoadControl(..) method:
Loads a Control object from a file
based on a specified virtual path.
MyControl myControl1 = (MyControl)LoadControl("TempControl_Samples1.cs.ascx");
PlaceHolder1.Controls.Add(myControl1);

dynamically load user controls using jquery ajax

I've read several articles on this issue, and technically speaking, all they end up doing is taking html code from a user control and injecting it into the containing page. I want a true user control to be loaded on to the page, so that on postback, I still have access to that loaded user control and I can validate fields on it on server side, etc. etc. What I mean to say is that once the user control has been loaded onto the page using ajax, it should there after act like it was originally created as part of page life cycle when the page was first loaded. Does that make sense? Any ideas on how to do this? UpdatePanel may be a solution, but I'd rather not use that.
Update panel is the solution since you need it to update the page's ViewState so that the newly added usercontrol needs to be part of the page lifecycle. Also, when the page does post back, you need to remember that it was added and re-add it so that the control structure gets re-created properly.
When you dynamically create user controls, you have to make sure to bind to the elements. Look into http://docs.jquery.com/Events/live

Resources