I am creating a custom .NET AJAX Server Control, and need to get access to the JavaScript object functionality associated with that control. I can do this by finding the control in the ScriptManager using the $find method. However, I need to determine when I can call $find. If I do this on the "onload" event of the body of my HTML page, it can't find the control. Thus I end up having to locate the control with each event I wire up and my code ends up looking like this:
function button1_click() {
var control = $find("<%=Control.ClientID%>");
control.DoSomething();
}
function button2_click() {
var control = $find("<%=Control.ClientID%>");
control.DoSomethingElse();
}
I would rather store that control once, and use it throughout the rest of my event calls. Thus I'm hoping the code would eventually look something like this:
var _control = null;
function load() {
_control = $find("<%=Control.ClientID%>");
}
function button1_click() {
_control.DoSomething();
}
function button2_click() {
_control.DoSomethingElse();
}
Let me know if this doesn't make sense. I am new at creating these custom controls, so I'm not quite sure of the terminology yet. Thanks for your help!
The "load" DOM event occurs before the ASP.NET Ajax client-side framework is initialized. Client-side controls are initialized by handling the init event of the Sys.Application object. That's why an ASP.NET Ajax control's initialization script is output like:
Sys.Application.add_init(function() {
$create( ... )
});
You can use the load event of the Sys.Application object or its shortcut- the pageLoad method. It occurs after the init event and all ASP.NET Ajax controls will be initialized then. Here is some sample code:
var _control = null;
function pageLoad() {
_control = $find("<%= Control1.ClientID %>");
}
Related
I am using a jQuery editor and when the user hits the submit button i put the content into asp.net Panel control as html and then when i render this Panel the html i added is not
retrieved.
function MoveData() {
var sHTML = $('#summernote_1').code();
// dvFrontPageHtml is asp.net Panel
$('[id*=dvFrontPageHtml]').html(sHTML);
setTimeout(function () {
javascript: __doPostBack('ctl00$ctl00$ContentPlaceHolderBody$ContentPlaceHolderBody$lnkSave', '');
}, 10000);
return false;
}
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter stWriter = new System.IO.StringWriter(sb);
System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(stWriter);
dvFrontPageHtml.RenderControl(htmlWriter);
string Message = sb.ToString();
The message does not returning the html added.
I dont want to use jQuery ajax call as of now.
Any suggestions
without seeing all the relevant code its hard to pinpoint the problem.
but im pretty sure you are trying to find an ASP.net control by its serverside ID from clientside.
dvFrontPageHtml is the Controls ID by which asp.net identifies it, and unless you explicitly tell ASP.Net otherwise, it will generate a different ID for the control to be used by scripts at clientside
you need to retrieve the panel's clientside ID thats being generated for it by asp.net
you do it by a preprocessor directive <%=dvFrontPageHtml.ClientID%>:
$('[id*=<%=dvFrontPageHtml.ClientID%>]').html(sHTML);
alternatively, if you want the clientside ID to be same as the serverside ID, you can set the control's attribute ClientIDMode="Static".
UPDATE:
from your comment it seems the problem is elsewhere. what comes to mind, is that RenderControl() takes the control as it was when sent to the client in the Response. but the control is not being submitted to the server in next Request, so you will not be able to retrieve its altered html.
what you can do as a workaround, is hook into ASP.NET's build in postback mechanism, and submit the panel's html as a custom event argument:
for the example, lets assume this is our html:
<asp:Panel ID="dvFrontPageHtml" runat="server" ClientIDMode="Static">test</asp:Panel>
<asp:Button ID="BT_Test" runat="server" Text="Button"></asp:Button>
this will be our javascript:
$(function(){
// add custom event handler for the submit button
$("#<%=BT_Test.ClientID%>").click(function (ev) {
//prevent the default behavior and stop it from submitting the form
ev.preventDefault();
//alter the panels html as you require
var sHTML = $('#summernote_1').code();
$('[id*=dvFrontPageHtml]').html(sHTML);
//cause a postback manually, with target = BTCLICK and argument = panel's html
__doPostBack('BTCLICK', $('[id*=dvFrontPageHtml]').outerHTML());
});
});
and here we capture the postback on serverside:
//we monitor page load
protected void Page_Load(object sender, EventArgs e)
{
string Message;
//check if its a postback
if (IsPostBack)
{
//monitor for our custom target "BTCLICK"
if (Request.Form["__EVENTTARGET"].CompareTo("BTCLICK") == 0)
{
// retrieve the panels html from the event argument
Message = Request.Form["__EVENTARGUMENT"];
}
}
}
Is there a way to determine if an <asp:UpdatePanel /> has performed an Ajax postback similar to how we can use...
if(!Page.IsPostBack) { ...snip }
... to determine if a postback from a button submit is taking place.
I'm trying to detect Ajax requests from jQuery, but it's picking up UpdatePanel requests as well which I want to exclude eg...
if (Request.IsAjaxRequest() && !Page.IsUpdatePanelPostback)
{
// Deal with jQuery Ajax
}
You can check whether the postback was asynchronous and whether it was issued by an update panel looking at these properties:
ScriptManager.GetCurrent(Page).IsInAsyncPostback
ScriptManager.GetCurrent(Page).AsyncPostbackSourceElementID
I don't know if this will work any better than your solution, but have you tried?:
if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
{
Control ctrl = GetControlThatCausedPostBack(Page);
if (ctrl is UpdatePanel)
{
//handle updatepanel postback
}
}
private Control GetControlThatCausedPostBack(Page page)
{
//initialize a control and set it to null
Control ctrl = null;
//get the event target name and find the control
string ctrlName = Page.Request.Params.Get("__EVENTTARGET");
if (!String.IsNullOrEmpty(ctrlName))
ctrl = page.FindControl(ctrlName);
//return the control to the calling method
return ctrl;
}
Try out following:
var controlName = Page.Request.Params.Get("__EVENTTARGET");
if (!String.IsNullOrEmpty(controlName))
{
// Use FindControl(controlName) to see whether
// control is of UpdatePanel type
}
Helpful links:
ASP.NET: Recursive FindControl & Extension Methods
I have created a custom server side WebControl. This control calls an initialization script that uses jQuery to hookup the events with calls to bind when the page is loaded.
This control is now being used inside an UpdatePanel and obviously the client side events no longer exist after the UpdatePanel does it's thing. So, I need to re-run my initialization script if the control has been re-rendered as part of a partial page refresh and I don't see a good way of doing this.
I am aware of the ScriptManager.IsInAsyncPostBack and UpdatePanel.IsInPartialRendering, but they don't seem to provide what I need. It seems to implement this correctly that I will have to check if ScriptManager.IsInAsyncPostBack==true, then search up the control tree for an UpdatePanel that has IsInPartialRendering==true. If I find such an UpdatePanel then I re-run my initialization script.
Sounds horrible. Am I missing something simple? I can't be the only one who lives this way.
Thanks for reading!
Have you tried using the method described in the SO post below?
jQuery $(document).ready and UpdatePanels?
This is what I do when I use jQuery in update panels and it always works for me.
Have to do what I was afraid of... also, Update.IsInPartialRendering does not work, so you have to use reflection to figure out if the updatePanel is getting updated. So, if IsControlBeingRendered is true, then run your scripts.
public static bool IsControlBeingRendered(ScriptManager scriptManager, Control control)
{
if (scriptManager.SupportsPartialRendering && scriptManager.IsInAsyncPostBack)
{
UpdatePanel updatePanel = ControlHelper.FindParentByType<UpdatePanel>(control);
while (updatePanel != null)
{
if (IsBeingUpdated(updatePanel))
{
return true;
}
else
{
updatePanel = ControlHelper.FindParentByType<UpdatePanel>(updatePanel);
}
}
return false;
}
return true;
}
public static bool IsBeingUpdated(UpdatePanel updatePanel)
{
// unfortunately, updatePanel.IsInPartialRendering does not work. So, we must use reflection
// to check the protected property that actually does work..
if (updatePanel == null)
return false;
Type type = updatePanel.GetType();
BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty;
return (bool)type.InvokeMember("RequiresUpdate", bindingFlags, null, updatePanel, null);
}
When you have multiple UpdatePanels on a page, is there a way, in the code behind, find out which Update Panel triggerred the postback? It appears that the Request["__EVENTTARGET"] is not a reliable way of doing this.
An UpdatePanel doesn't trigger PostBacks, it intercepts them. The originator of the PostBack would be something like a button. If you have event handlers for all your interactive elements, you naturally know which one fired by which event handler runs.
you can get the id of the postback element on the client with the following
function pageLoad(sender, args) {
// add function to the PageRequestManager to be executed on async postback initialize
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
}
function InitializeRequest(sender, args) {
if(args._postBackElement.id === 'id_of_element_in_question' {
// do whatever
}
}
to get it on the server, presumably you'll know which control/event raised the postback as it will be handled in the relevant event handler in the code-behind.
asp.net 2.0 / jQuery / AJAX
<script type="text/javascript">
//updated to show proper method signature
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(hideMessage);
function hideMessage(sender, args)
{
var ctl = args.get_postBackElement();
//check if ctl is the disired control
//hide user notification message
}
</script>
i have several controls on the page that might initiate the AJAX request, but i only want my js to fire when i click one particular button. how do i check what control initiated the request so i can fire JS accordingly.
EDIT: I worked around it, but I'd still like to know if I can do it this way.
Clarification: I can't call the JS from onclick event, because the page is inside of the UpdatePanel, and i only want the JS to execute when AJAX Request ends and it was triggered by one particular button on the page. On server side, i set the myLabel.Text to some text, and then js checks if the $(myLabel.CliendID)'s innerHTML is not blank and fires the js. checking the innerHTML is my work-around since i can't figure out how to check the "sender" of AJAX Request. Hope this makes more sense now.
edit2: I've read some documentation, and turns out you CAN check the "sender" control.
Thank you.
This is what I am doing in my code to identify what control has initialized the request. All javascript code.
function pageLoad() {
if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(initializeRequest);
}
}
function endRequestHandler(sender, args) {
if (sender._postBackSettings.sourceElement.id == '<%= gvResults.ClientID %>') {
//do something because of this...
}
}
function initializeRequest(sender, args) {
if (CheckForSessionTimeout()) {
args.set_cancel(true);
}
else {
if (sender._postBackSettings.sourceElement.id == '<%= gvResults.ClientID %>') {
//do something because of this
}
}
}
EDITHere is the method of checking for timeout on the client side.
var sessionTimeoutDateTime = new Date();
var sessionTimeoutInterval = <%= this.SesstionTimeoutMinutes %>;
function CheckForSessionTimeout() {
var currentDateTime = new Date()
var iMiliSeconds = (currentDateTime - sessionTimeoutDateTime);
if (iMiliSeconds >= sessionTimeoutInterval) {
ShowSessionTimeout();
return true;
}
return false;
}
I would recommend that you do not have each control execute the same javascript function. OR, if they do, pass a parameter that indicates which one executed it.
Then, you can include your ajax in the js function that the control executes.
And, if I'm not understanding the issue correctly, perhaps you could explain it in more detail or post some code.
I've read some documentation, and turns out you CAN check the "sender" control. JS in the question is updated to show the proper method signature.
This article gives even better explanation.