Wednesday, March 28, 2012

Dynamic HTML ToolTip that loads OnHover/OnMouseOver

right now i have a web app that has a repeater (rather large) with a literal for one of the columns. this literal is a number based on the amount of entries and on load has javascript added to it that displays row specific information built from a database when you hover over it. the problem is that every time the page loads, every tooltip is loaded. i want to only go to the DB and get this info when they hover over that literal. so onmouseover of this literal would trigger an event that builds the tooltip and displays it as before.

i've searched this forum (which by the way isn't efficient) along with some good old Google hunting with no luck. can anyone point me in the right direction? oh yeah, i also would prefer not to use some random 3rd party tool. =)

This is fairly easy. Follow this tutorial:http://ajax.asp.net/docs/tutorials/ConsumingWebServicesWithAJAXTutorial.aspx except that in the 'OnComplete' javascript function that fires when the web service returns, have it fill whatever container you're currently using to display the tooltip (mostly this ends up being the title attribute of one element or another).


I'll check it out and see how it goes. Thanks for the reply =)

dynamic html production to call ajax post via javascript

I am maintaining a page that creates html (not server controls) elements dynamically and when one changes I need to call the ajax postback. Is that possible? The page that is created can't know ahead of time that it will need to post through ajax....

So long as you add a client-side Event handler to your html control when you create it, yes, you can wire it up to make asynchronous requests:http://www.mikesdotnetting.com/Article.aspx?ArticleID=40. Note, the methodology outlined in the article doesn't make an ASP.NET Ajax request or postback. It differs in that it only makes a call to the server-side method you want to invoke. This can be better than using ASP.NET Ajax, in that you aren't recreating all the controls on the page.

Dynamic highlight should be easy! (UpdatePanelAnimationExtender)

Hi,

I have a page fragment which looks roughly like:


<UpdatePanel>
<Repeater>
<Item>
<div id="something-#">item text</div>
</Item>
</Repeater>
</UpdatePanel>


When a new item is added, I want to have the newly added <div> higlight. So far I've manged to get the first item to highlight with an UpdatePanelAnimationExtender:

<ajaxToolkit:UpdatePanelAnimationExtender ID="upae" BehaviorID="Highlight"
runat="server" TargetControlID="UpdatePanel1">
<Animations>
<OnUpdated>
<Sequence>
<Color AnimationTarget="something-1"
Duration=".5" PropertyKey="backgroundColor"
StartValue="#FFFF90" EndValue="#FFFFFF" />
</Sequence>
</OnUpdated>
</Animations>
</ajaxToolkit:UpdatePanelAnimationExtender>

What I can't figure out how to do is get the most recently added item to highlight. It seems like I need to be able to set the "AnimationTarget=" attribute in server code, but after reading posts on here I believe I can't.

Is there any easy way to do this?

Well, to reply to myself, here's how I achieved it. (I'm sure there must be an easier way though).

In my button click event handler I add a data item with the Id of the new object.

if (ScriptManager.IsInAsyncPostBack)
{
System.Web.Script.Serialization.JavaScriptSerializer json =
new System.Web.Script.Serialization.JavaScriptSerializer();

// Return the new CommentId ScriptManager.RegisterDataItem(CommentsUpdatePanel, json.Serialize(comment.CommentId),true);
}

Then in my page, use the EndRequestHandler to pick up the new Id. I then dynamically create some animation code
using the client ID that I've just created.

 function EndRequestHandler(sender, args)
{
var dataItems = args.get_dataItems();
var newCommentId;

if (dataItems[CommentsUpdatePanel] != null)
{
newCommentId = dataItems[CommentsUpdatePanel];
}

 var colorAni = new AjaxControlToolkit.Animation.ColorAnimation(newCommentEl,
2, 30, "style", "backgroundColor", "#FFEF3F", "#FFFFFF");
/// More animation code }
It works, but it seems very clunky to me. 

Hi,

There are a couple of ways you could do this that are a little easier. A better approach would be something like <Color TargetScript="GetLatestDiv()" ... > combined with function GetLatestDiv that does a look up on the ID stored in your data item and returns its element.

Thanks,
Ted

Ted,Thanks for your reply.

I did consider this method, but the problem I faced is getting to the dataItem in the 'GetLatestDiv()' method. The documentation says that:

"If you use the RegisterDataItem method of the ScriptManagercontrol to send extra data during an asynchronous postback, you canaccess that data from the PageLoadingEventArgs, PageLoadedEventArgs,and EndRequestEventArgs objects"

In other words, as far as I can tell, I need to be in the EndRequestHandler method to get at the dataItem. It appears that EndRequestHandler() is called after GetLatestDiv() is evaluated, so I can't even use a shared variable, which would be quite nasty anyway.

Is there any other way I can get at the DataItem?

Hi,

Right - you'll still need your handler to pull the DataItem out. I was thinking you could then store that in a global var that's later read by GetLatestDiv(). Better yet though, you could make it one step simpler and just say TargetScript="_lastDiv" where _lastDiv is a global reference to the element you obtained from your handler.

Thanks,
Ted

Dynamic Gridview

Hi!

I've got a quetion on dynamic gridview load. In my atlas website project i have a gridview that i want to load dynamically. That is, I don't want to load all the data in my datasource because the web page could charge slowly; so, i want to charge only part of the data as fast as possible then, load the other paghes when the user asks for it. How can I do it? Am I to write a C# class in order to manage the load?

Thanks

hi,

it depends on what level do u want to do this ,at what level is it loading slowly.....1)from the dataserver to the dataobject or 2)the control to the current instance of the page...?


it downloads slowly from the dataserver to the dataobject

where is your select query placed?may be in datasource...... place it in a stored procedure as stored procedures are precompiled..... & call the stored procedure....also set EnablePaging to true of the gridview.


My query select is placed in my datasource and my EnablePaging is set to true

Dynamic generated Controls doesnt work, javascript error

I have an ajax enabled control which has a Dropdownlist that changes the Textbox when index gets changed. It is working fine if I use an ASPX page that contains the control in design time.

However, when I dynamically add this control to the ASPX in run time, I got an error when the Dropdownlist is triggered:

Javascript error: System.InvalidOperationException: A control with ID 'myDropDownList' could not be found for the trigger in UpdatePanel..etc..

What should I do? Please help..

There's a good chance that if you look at your page source you'll find that the dynamic control does not have a clientside Id of 'myDropDownList'. It'll probably have something more complex like ct100_myDropDownList or something.

Two possible fixes: 1) wire up your javascript on something other than the id (e.g. iterate over getElementsByTagName), or 2) render the control's ClientID inside a script tag on the page like: var ddl = '<%= myDropDownList.ClientID %>'

HOpe that helps.

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.

dynamic generated clientside javascript

hi,

how can i register a script on asyncPostBack and can check in the next asynPostback if the script is on side ?

i use ajax with scriptmanager and updatepanel on my website.

sometimes i will give the user (after a asyncPostBack) a alert-message about javascript...

i have tryed following:

PrivateSub RegisterMsg(ByVal strMessageAsString,ByVal strScriptTagAsString)

Dim strScriptAsString ="alert(""" & strMessage &""");"

If (Not Page.ClientScript.IsClientScriptBlockRegistered("key"))Then

ScriptManager.RegisterClientScriptBlock(Me,Me.GetType(),"key", strScript,True)

EndIf

EndSub

the IsClientScriptBlockRegistered-methode every time gives false back...thx

Use ScriptManager.RegisterStartupScript() and drop the IsBlockRegistered check.


now i have:

Private Sub RegisterMsg(ByVal strMessage As String, ByVal strScriptTag As String)
Dim strScript As String = "alert(""" & strMessage & """);"

If (Not Page.ClientScript.IsClientScriptBlockRegistered("key")) Then
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "key", strScript, True)
End If
End Sub

and it is the same...it did not work correct, the IsClientScriptBlockRegistered-Method returns every time false and because of this the script will be written a second one, and third one and so on...


Hi,

Since the script is created dynamically, it won't be persisted between different requests.

So, before the method is called on the second request, this script block does not exist.

And my suggestion is you don't have to call this multiple times, just call it on initial request and it'll always stay on the page since the page isn't fully refreshed.


the problem is that the appl. dont makes really postbacks during running, only partial postbacks...

and my wish is that i will register and unregister scripts during partial postbacks...how can i do it ?


For partial postback, you can register new scripts.

But you can't unregister existed scripts on server side.


Has there been any progress made on this issue? I am just experiencing this now.

I've overriden OnInit with the following (similar) code:

if (!Page.ClientScript.IsClientScriptBlockRegistered(typeof(Page),"MyScript")
{
// use StringBuilder/StringWriter to build script
ScriptManager.RegisterClientScriptBlock(this,typeof(Page),"MyScript",sb.ToString(),true);
}
 
But the conditional is always true so the script gets recreated every time there is an asyncPostback.
One thing I noticed (using Firebug in Firefox) is on the initial load of the page the script is created
within the form and then on each successive asyncPostback a new script is created in the <head>.
Why is there no IsClientScriptBlockRegistered function in the ScriptManager class? Is that the problem?
That the Page.ClientScript and ScriptManager are looking at two different collections of scripts?