Wednesday, March 28, 2012

Dynamic generated control in UpdatePanel

Hi,

I have an updatepanel, a datagrid (initially whose visible property is false) and few buttons on a webpage. On click of one of button I bind the panel with a collection and set visible property to true in turn displaying bounded datagrid.

-Now when I go to view html source for the page I didn't find any grid(or its table equivalent) control there. Why so? I want to know how new rows are displayed without any corresponding markup generated in the html source?

-Now on click of another button I dynamically create a template column in the datagrid and adds some dynamically generated controls say checkbox in that column of the datagrid. Now my questions are :-

--How can I use those dynamically generated controls in my server side code?

--How can I access them in javascript so as to find out which checkboxes are checked and which are not?

--That newly added column is visible till grid is not updated. How can I make newly generated column persists permanently?

-Also I have added CheckedChanged event handler on that dynamic check box but that event doesn't fire. How can I get that event work?

Sorry for a long post.

Thanks in advance.


1. You don't see the HTML because you're only seeing the original HTML the page first rendered with. The update caused by the update panel is done dynamically with script. That is, the HTML content of the page is altered at runtime, and you're only seeing the request time HTML.

2a. You should follow the link to my blog in my signature and read about dynamically creating server controls. Using the controls is easy -- you created them, that means you have a reference to them.

2b. You know their client side IDs with the ClientID property. You can use the ClientID property to render out javascript that uses it. You can pass the ID to document.getElementById or use the shortcut for that, $get. For example, $get("<%= MyControl.ClientID%>");. Exactly how you do this depends on your needs -- but the basic idea is to render the ClientID into javascript code, by whatever means.

2c. Dynamically created controls do not recreate themselves on postbacks, and that includes asynchronous postbacks from an UpdatePanel. When you dynamically create a control it is up to you to make sure that control is recreated each and every request. Creating them from an event handler isn't enough, because that event won't fire again on a postback unless the user performs the same action. Read my articles on dynamic controls to get some ideas of how to handle this better.

3. It doesn't fire because it doesnt exist... for the reason in 2c.

Hope that helps :)


If you'd Like to see the HTML of the partial-render i suggest using opera (http://www.opera.com/) and download the Developer Console and DOM Snapshot plugins for it. It'll allow you to take a snapshot of the DOM of the page at any given moment, not just the original source.

Hello,

I am new to this forun, I have tried my best to explain my problem but sorry for long description.

I am also facing the same problem, dynamically generated server side code is not reflected in the HTML.

I am using AJAX on that page, if enablepartialrender = false then it works fine.

in the custom control i am adding dynamic control as follows.

protectedoverridevoidCreateChildControls{

StringBuilder builder = new StringBuilder();

builder.Append("some script");.

builder.Append("some html");

LiteralControl ctrl =newLiteralControl(builder.ToString());

Controls.Add(ctrl); }

this control is added on page with UpdatePanel & ScriptManger , now I am modifying the builder contents dynamically , during poastback,

but when I check the view source I am it shows me the original source.

I am gone though all your documents about following

Part 1: Dynamic vs. Static
Part 2: Creating Dynamic Controls
Part 3: Adding Dynamic Controls to the Control Tree

but I haven't found any thing which solves my this issue,

I mean in case of AJAX how to add dynamic controls?


The original HTML source is never going to change. The HTML is dynamically updated with javascript as the result of a partial update. The result is, the browser displays the new HTML, but the "source" of the page is unchanged. With a regular postback, the entire source is redownloaded, so you see the updates with View Source. I hope that makes sense.

As for why or why not you are actually seeing the new content (isn't clear whether thats the case), you'll have to post some more code so we can figure that out. But one thing I notice, you have builder.Append("some script"). Statically written script in the html isn't going to execute.. you will need to use the ScriptManager.Register_ APIs (e.g. RegisterStartupScript), or the script simply won't execute. The reason is because browsers do not execute script in dynamically injected HTML, they have to be dealt with specially, which the framework handles for you if you just use the correct API.


Thanks for quick reply,

Following is the code of custom control. In the CreateControl method I am generating the HTML

also m_listItems this list contents are set from page where I am putting this control.

I am modifying this list on postback, now here is the problem , if I debug the code the i found that every thing is OK

but in the browser those changes are not reflecting , when AJAX is enabled.

Please suggest me solution.

--Kiran

-------- Custom Control Code ----------------

[assembly: WebResource("TestNameSpace.CustomControl.ctrl.js", "text/javascript")]

namespace AtlasWeb.MultiSelectDropDown
{
[ParseChildren(true, "ListItems")]
public class CustomControl : CompositeControl, IScriptControl
{
private ArrayList m_listItems = new ArrayList();
private ScriptManager sm;
private StringBuilder builder = new StringBuilder();

public ArrayList ListItems
{
get { return m_listItems; }
set { m_listItems = value; }
}

protected override void OnPreRender(EventArgs e)
{
if (!this.DesignMode)
{
// Test for ScriptManager and register if it exists
sm = ScriptManager.GetCurrent(Page);

if (sm == null)
throw new HttpException("A ScriptManager control must exist on the current page.");

sm.RegisterScriptControl(this);
}

base.OnPreRender(e);
}

protected override void CreateChildControls()
{
CreateControl();
LiteralControl ctrl = new LiteralControl(builder.ToString());
Controls.Add(ctrl);
}

protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
if (!this.DesignMode)
{
sm.RegisterScriptDescriptors(this);
}
}

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
ScriptReference htmlEditorReference = new ScriptReference("TestNameSpace.CustomControl.ctrl.js", "TestNameSpace.CustomControl");
return new ScriptReference[] { htmlEditorReference };
}

protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
ScriptControlDescriptor descriptor = new ScriptControlDescriptor("TestNameSpace.CustomControl", this.ClientID);
return new ScriptDescriptor[] { descriptor };
}

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
{
return GetScriptReferences();
}

IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
{
return GetScriptDescriptors();
}

protected void CreateControl()
{
builder.Append("<script language=\"Javascript\">var ms1 = new TestNameSpace.CustomControl([");
int index = 1;
foreach (ListItemData itemData1 in m_listItems)
{
builder.Append("{name:\"");
builder.Append(itemData1.CtrlID.ToString());
builder.Append("\", value: \"");
builder.Append(itemData1.Value.ToString());
builder.Append("\", isSelected: ");
builder.Append(itemData1.IsSelected.ToString());

if (index == m_listItems.Count)
builder.Append("}");
else
builder.Append("},");

index++;
}

builder.Append("],\"ms1\", \"ms1\", \"" + this.ID + "\");");
builder.Append("Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(pageLoaded);");
builder.Append("function pageLoaded(sender, args)");
builder.Append("{");
builder.Append("javascript:ms1.RenderHtml();");
builder.Append("}");
builder.Append("</script>");
}
}

/// <summary>
/// Summary description for ListItems.
/// </summary>
public class ListItemData : Control
{
#region Constructors

public ListItemData()
{
m_ID = string.Empty;
m_value = string.Empty;
m_isSelected = "false";
}

#endregion

#region public properties

public string CtrlID
{
get { return m_ID; }
set { m_ID = value; }
}

public string Value
{
get { return m_value; }
set { m_value = value; }
}

public string IsSelected
{
get { return m_isSelected; }
set { m_isSelected = value; }
}

#endregion

#region private class data

private string m_ID;
private string m_value;
private string m_isSelected;

#endregion
}
}
-------- Custom Control Code ----------------


Right... the problem is what I said. You are registering your script by rendering it directly into the HTML from your control, because you just add the script to a literal control. That definitely will not work in an update panel. You have a script descriptor there-- but you aren't using it. That script descriptor will cause an instance of your client side control to be created. All you need to do is feed it the data you want though a property on the client side control. Then you assign the data to a property on the script descriptor (AddProperty or something like that). Then the control is created that value will have been set. Here...

MyType = function(element) {
MyType.initializeBase(this, [element]);
}
MyType.prototype = {
_data: null,
get_data: function() { return this._data; },
set_data: function(value) { this._data = value; },

initialize: function() {
var data = this.get_data();
// render the data, or whatever you want to do with it
MyType.callBaseMethod("initialize");
}

}
MyType.registerClass("MyType", Sys.UI.Control);

Then on the server side you feed that property with your ScriptControlDescriptor something like so:

// build up an array of items where each item is a dictionary
ArrayList data = new ArrayList();
Hashtable ht = new Hashtable();
ht["name"] = "name";
data.Add(ht);
// ... add more
ScriptControlDescriptor d = new ScriptControlDescriptor("MyType", this.ClientID);
d.AddProperty("data", data);
return new ScriptDescriptor[] { d };


Hello,

Thanks for reply.


Now when from server side any property is modified, does it reflect at client sie?

I mean on client side I am able to see the property vales, which are set when page is loaded.

now on some event i am modifying that property value, does it reflect at client side?

Currently this is not happening in my code.


If your component is in an update panel, yes it should be recreated and the initialize method called again. It should have the new server side values because the descriptor is recreated.

If you're not seeing that, sorry, you'll have to provide some more examples.


Hello,

Thanks for reply.

I have tested by putting alert in the javascript , it is showing that property vale is updating on event, but not refleting it at client side.

Initialise & despose methods are getting called , when I do button click first despose is called and then initialise is called.

Are there any sample applications or document availble on net for the same?

please let me know.

No comments:

Post a Comment