I have a web application project with Infragistics 2014.2 and .net Framework 4. In my web page I put a WebDataTree that is loaded only the first level of nodes. I need to get server side events every time a node is clicked or the node's expand button is clicked in order to decide programmatically if the child nodes need to be loaded.
This scenario works fine but the user needs to click three times the expand button to fire the server side event. This happened only when the node has no children loaded. If a node has children loaded the expand events working fine.
I created a small example showing this issue.
Default.aspx
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebDataTreeTest._Default" %><%@ Register Assembly="Infragistics4.Web.v14.2, Version=14.2.20142.2480, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" Namespace="Infragistics.Web.UI.NavigationControls" TagPrefix="ig" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title></title></head><body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> <ig:WebDataTree ID="WebDataTree1" runat="server" Height="600" Width="400px" CheckBoxMode="BiState" NodeIndent="18" EnableAjaxViewState="true" OnNodeClick="WebDataTree1_NodeClick" OnNodeExpanded="WebDataTree1_NodeExpanded"> <AutoPostBackFlags NodeClick="On" NodeExpanded="On" /> </ig:WebDataTree> </div> </form></body></html>
Default.aspx.vb
Public Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then For i As Integer = 1 To 5 Dim tn As New Infragistics.Web.UI.NavigationControls.DataTreeNode() tn.Key = "1" tn.Value = "N|" & i.ToString() tn.Text = "Node" & i.ToString() tn.ToolTip = tn.Text tn.IsEmptyParent = True tn.Expanded = False WebDataTree1.Nodes.Add(tn) Next End If End Sub Protected Sub WebDataTree1_NodeClick(sender As Object, e As Infragistics.Web.UI.NavigationControls.DataTreeNodeClickEventArgs) If e.Node.HasChildren Then e.Node.Expanded = Not e.Node.Expanded Exit Sub End If AddNodes(e.Node) e.Node.Expanded = True End Sub Protected Sub WebDataTree1_NodeExpanded(sender As Object, e As Infragistics.Web.UI.NavigationControls.DataTreeNodeEventArgs) If e.Node.HasChildren Then Exit Sub End If AddNodes(e.Node) e.Node.Expanded = True End Sub Private Sub AddNodes(parentNode As Infragistics.Web.UI.NavigationControls.DataTreeNode) For i As Integer = 1 To 5 Dim tn As New Infragistics.Web.UI.NavigationControls.DataTreeNode() tn.Key = CStr(Integer.Parse(parentNode.Key) + 1) tn.Value = "N|" & parentNode.Value.Split("|")(1) & i.ToString() tn.Text = "Node" & parentNode.Value.Split("|")(1) & i.ToString() tn.ToolTip = tn.Text tn.IsEmptyParent = True tn.Expanded = False parentNode.Nodes.Add(tn) Next End SubEnd Class
In interest of having this information available to the community in case others also face such an issue, here is the explanation of this behavior and how to avoid it:
A scenario where a combination of events on the same chain (such as click and select, or populate and expand in this case) are one async and one full postback is not supported. This is done to avoid issues such cases can cause with event handlers. In reality there’s also rarely a reason to combine the two types of postbacks back to back.
For this specific scenario:
Perhaps part of the confusion comes from the multiple states of the AutoPostBackFlags – keep in mind the “On” value means full postback and there’s another enabled state that is “Async”. Combine that with the fact that Ajax is enabled by default for the Data tree (even without EnableAjaxViewState="true").
The events listing suggests the NodePopulate event should be used to handle when using IsEmptyParent, instead of NodeExpanded:
http://help.infragistics.com/Doc/ASPNET/2015.2?page=Infragistics4.Web.v15.2~Infragistics.Web.UI.NavigationControls.WebDataTree_members.html
So, as per the flags click and expand are full page reloads, but the populate is not described (therefore async) and fires right before expand to load data and prevents the following event from triggering. Nodes with loaded children will naturally not require populate and their expand event will cause normal postback as expected. So to achieve loading in child data the simply avoid such event combinations and for the tree handle the populate first:
<ig:WebDataTree ID="WebDataTree1" runat="server" Height="600" Width="400px"
CheckBoxMode="BiState" NodeIndent="18" EnableAjaxViewState="true"
OnNodeClick="WebDataTree1_NodeClick" OnNodePopulate="WebDataTree1_NodePopulate">
<AutoPostBackFlags NodeClick="On"/>
</ig:WebDataTree>
protected void WebDataTree1_NodePopulate(object sender, DataTreeNodeEventArgs e)
{
DataTreeNode tn = new DataTreeNode();
tn.Key = Convert.ToString(int.Parse(e.Node.Key) + 1);
tn.Text = e.Node.Text + "_ChildNode";
e.Node.Nodes.Add(tn);
e.Node.Expanded = true;
e.Node.DataTree.DataBind();
}
I’m attaching the full sample and hope this is helpful.
Regards,
Damyan Petev
Associate Software Developer
Infragistics, Inc.
Thank you very much for the response. I used the NodeExpanded event instead of NodePopulate because in some cases the node must be expanded (and load the child nodes) and in some cases not.
For example:
I'm loading by default the first level of the tree when the page loaded. If a node has children (not loaded yet) the expand button must be visible. When the user clicks the expand button a full post back is performed and in some cases I displayed an agreement to the user. So there are two cases here:
1) The user doesn't need to answer an agreement so I will load the child nodes. In this case the NodePopulate event covers my needs.
2) The user has to confirm or not the agreement. In this case when the event fires I will not load any children to the node. I will load the child nodes later depends on the users answer. If the user decline the agreement I want the expand button to be visible, in order to be able the user to click it again. With the NodePopulate event if I don't load any child nodes when the event fires, the tree "understands" that the node has no children and the NodePopulate event never fired again. This is the reason I used the NodeExpanded event.
Could you please suggest me a solution for the second case? Thank you in advance.
Hello Leo,
I believe I get your second case – you want to confirm the node expand action in a sense, right? Like a conditional manual load on demand. The population of node data is, however, strictly asynchronous. You could attempt to skip populating the node and force a postback after the population is "complete", but that would kind of go against the load on demand feature entirely.
The most straightforward solution I can think of is to cancel the client side NodePopulating event and save the node reference for later. Then go thought the user confirmation (show a dialog for example) and only after the user accepts, expand the node, which will go through the normal populating process as usual. This seems to make the most sense, so let me know if this is suitable for your case and I will try to provide more guidance on how to achieve that.
Hello,
Thank you for the quick reply. The solution you suggest is a possible solution but in my case all the process of showing (or not) the agreement dialog is server side. So I need a postback to load and show the dialog. Is it possible in the solution you suggest me to trigger a postback after canceling the client side NodePopulating event?
Thank you in advance!
I only assumed you can use something that can be displayed from a client API (like a Dialog Window) and frankly I would strongly suggest a similar approach. There’s rarely anything that can’t be converted from server rendering to client interaction anyway. This also assumes you can easily render if event should be canceled and verified from a general server condition. The case becomes a bit more complicated if you need server validation for each node separately (and even that can be done through simple endpoint request).
Cancelling the populating is easy enough:
<ClientEvents NodePopulating="WebDataTree1_NodePopulating"/>
<script type="text/javascript">
function WebDataTree1_NodePopulating(tree, e) {
e.set_cancel(true);
//handle validation, use e.getNode() to get a reference to the node
To force postback after that you can call in the standard __doPostback(). This article has a good explanation how to pass in arguments so your backend: http://www.codeproject.com/Articles/667531/doPostBack-function and you will need something similar to set the node information to validate and handle the server side, as there will be no event to do that for you.
Again I would only go through with the latter if the rest of the design is harder to change. I might be able to come up other solutions if you can provide a small sample with your general usage. Perhaps something other than manual load on demand can achieve the result you are looking for?
Lastly, if you think having an interruptible and fully synchronous Load on Demand for the Data Tree is important, perhaps you would consider submitting it on our Feature Suggestions site at http://ideas.infragistics.com/forums/192360-asp-net - that can be very helpful when product management decides what to add next to the product.