Welcome Guest Search | Active Topics | Sign In | Register

Client Scripting with TreeView: some tips + request Options
Saed
Posted: Thursday, December 18, 2008 1:44:57 PM
Rank: Advanced Member
Groups: Member

Joined: 10/15/2008
Posts: 45
Hello there,
I have seen this situation being addressed before, but my approach here is a bit different, hence, worth presenting (I think).

Overview:
The situation is simple: a TreeView on left with some TextBox controls and a DropDownList on right to display particulars of a selected Node. My TV has only 2 levels: 17 Root Nodes (L0) and various LeafNodes (L1) per Root Node. TreeView and displaying block are placed inside 2 adjacent table cells.

Node Text should come in 2 flavours: Arabic & English depending on user selected language/culture. Therefore, I used a global localised resource to hold among others language Name & Code. During population, culture-related resources are dynamically set and passed to DB query.

Since I also need to maintain Node ID (from DB), I'm storing it as Node's Value. TV switches direction and works fine, fully localised.

Previously:
With ASP TreeView leveraging solely server-side handlers things are straightforward. Upon Node selection, SelectedNodeChanged was fired, through which I retrieve Node Value & ValuePath in order to pass to displaying block of controls. Once retrieved, I had to construct another DB query to retrieve remaining particulars of selected Node, like the Text in other language then fill associated TextBoxes and set DDL index to selected Node's parent ID in order to show parent Text.

However, due to annoying page reload on every pastback, I attempted using CallbackPanels but that wasn't successful. Then tried iFrames; worked but hated extra work for nothing.

Current:
It was evident that the only way forward is Client Scripting. So, spent sometime reviewing your documentation, in particular, supported ClientSide features, which encouraged me to go ahead. Consequently, I began my quest by switching to EO TreeView due to the great collection of ClientSide functionalities it supports and the rich Client API available. you won't believe guys the outcome; even my tough Boss was pleased!

To start with, here is my TV declaration:

Code: HTML/ASPX
<eo:TreeView id="codesTV" runat="server" EnableViewState="false" 
RaisesServerEvent="false" ClientSideOnItemClick="getSelectedInfo">
</eo:TreeView>

Although not required being the default, I kept the RaisesServerEvent="false" for illustration purposes, and in case I wish to utilise it later on.

And the JS block:

Code: JavaScript
function getSelectedInfo(e, info)
{
    var node = info.getItem();
    var parent = info.getItemGroup().getParentItem();
        
    var parentID = parent.getItemId();
    var nodeID = node.getItemId();
    var nodeText = node.getText();
    var nodeValue = node.getValue();

    passInfo(parentID, nodeID, nodeText, nodeValue);
}

function passInfo(pID, nID, nText, nValue)
{
    document.getElementById('<%= recFlag.ClientID %>').value = "U";
    document.getElementById('<%= codeCatDDL.ClientID %>').value = pID;
    document.getElementById('<%= codeValue.ClientID %>').value = nID;
        
    var activeLang = document.getElementById('<%= setCulture.ClientID %>').value;
        
    var txtSplit = nText.split("-");
    var txtOnly = txtSplit[1].slice(1);
    var arDesc = "";
    var enDesc = "";
        
    if (activeLang == "ar")
    {
        arDesc = txtOnly;
        enDesc = nValue;
    } 
    else 
    {
        enDesc = txtOnly;
        arDesc = nValue;
    }  
    document.getElementById('<%= arDesc.ClientID %>').value = arDesc;
    document.getElementById('<%= enDesc.ClientID %>').value = enDesc;
}


With such approach, I had to revisit my Server-Side strategy, in particular, node population. The presence of ItemID was indeed very helpful which I used to hold required Node ID, thus, freeing node's Value property. That was a great catch.

Instead of querying DB to retrieve Text in other language as was the case before, I utilsed empty node's Value to store said Text during Tree population, which resulted in dropping a significant server round-trip. With that accomplished, I have all needed info stored along with the Node, thus, no further need to server-side handling after the Tree is populated, which paved the road to only utilise Client Scripting to retrieve Node particulars (getSelectedInfo) then pass them to displaying block of controls and assign them to subsequent control properties (passInfo).

At present, a user can click a Node and view its particulars instantly on a fly--no postback or page/component reload; an achievement that wasn't possible without provided Client API, Objects and Methods, especially that little yet powerful object NavigationItem:-)

Conclusion:
If you can achieve a task via Client Scripting, go for it. Don't use Server-Side unless it is very necessary. Ditto with using asp Controls vs HTML counterparts.

Utilise your resources thoroughly and effectively. EO products are rich with features supporting both sides of the stream. Take your time to research and read a lot. Once mastered, you will be amazed how your handling of tasks will significantly improve.

That's said, I end up with the 2 populating routines I used. Hope you find them useful:

Code: Visual Basic.NET
Protected conn As OleDbConnection = setConnection()
Public actDesc As String = setDesc()
Public altDesc, sql As String
Public imgBase As String = "~/images/objects/tree/nodes/set1/"

...

Private Sub fillTree()
     ' Initialise Tree View and Set its Title
     Dim tvIndex As UInt16
     tvIndex = 1
     tvTitle.Text = initEoTV(codesTV, tvIndex, conn)
     codesTV.Nodes.Clear()

     ' Populate the Tree
     populateLevel_0(codesTV)
End Sub

' ***** Populate LEVEL 0 Nodes
Private Sub populateLevel_0(ByVal thisTV As EO.Web.TreeView)
     Try
          thisTV.Nodes.Clear()

          Dim L1data As New DataTable
          Dim nodeFocus As String

          If actDesc = "description_ar" Then
               altDesc = "description_en"
          Else
               altDesc = "description_ar"
          End If
          sql = "SELECT maj_id, description_ar, description_en FROM t_Codes "
          sql &= "WHERE min_id = 0 ORDER BY maj_id"
          L1data = FetchData(sql, conn)

          ' Create Level nodes.
          If L1data.Rows.Count > 0 Then
               nodeFocus = "maj_id"
               Dim row As DataRow
               For Each row In L1data.Rows
                    Dim newNode As EO.Web.TreeNode = New EO.Web.TreeNode()

                    newNode.ItemID = row(nodeFocus)
                    newNode.Text = newNode.ItemID & "- " & row(actDesc)
                    newNode.Value = row(altDesc)
                    newNode.ImageUrl = imgBase & "cL1.png"
                    newNode.PopulateOnDemand = True
                    newNode.Selected = False

                    ' Add the new Node
                    thisTV.Nodes.Add(newNode)

                    ' Populate Child Nodes of current Node
                    populateLevel_1(newNode)
               Next
          End If
     Catch ex As Exception
          MsgBox(getMsgText(50, conn) & " [" & ex.ToString & "]", MsgBoxStyle.Exclamation, getMsgTitle(50, conn))
     End Try
End Sub

' ***** Populate LEVEL 1 Nodes
Private Sub populateLevel_1(ByVal node As EO.Web.TreeNode)
     Try
          Dim L2data As New DataTable
          Dim nodeFocus As String

          If actDesc = "description_ar" Then
               altDesc = "description_en"
          Else
               altDesc = "description_ar"
          End If
          sql = "SELECT maj_id, min_id, description_ar, description_en FROM t_Codes "
          sql &= "WHERE min_id > 0 and maj_id = " & node.ItemID & " ORDER BY min_id"
          L2data = FetchData(sql, conn)

          ' Create Level nodes.
          If L2data.Rows.Count > 0 Then
               nodeFocus = "min_id"
               Dim row As DataRow
               For Each row In L2data.Rows
                    Dim childNode As EO.Web.TreeNode = New EO.Web.TreeNode

                    childNode.ItemID = row(nodeFocus)
                    childNode.Text = childNode.ItemID & "- " & row(actDesc)
                    childNode.Value = row(altDesc)
                    childNode.ImageUrl = imgBase & "cL2.png"
                    childNode.EnsureVisible()

                    ' Add the new Node to the ChildNodes collection of its Parent Node
                    node.ChildNodes.Add(childNode)
               Next
          End If
     Catch ex As Exception
          MsgBox(getMsgText(50, conn) & " [" & ex.ToString & "]", MsgBoxStyle.Exclamation, getMsgTitle(50, conn))
     End Try
End Sub


Hope this helps.

Regards,

Saed Hamdan
"Man may be destroyed but not defeated" -Hemmingway
Saed
Posted: Thursday, December 18, 2008 2:08:37 PM
Rank: Advanced Member
Groups: Member

Joined: 10/15/2008
Posts: 45
OOPS... Sounds got caught in the middle and missed posting the request! here it is:

I wish to have L0 nodes (Root) with no action. When they are clicked at present, they cast their particulars to Client Script, resulting in displaying so. I don't want this to happen, i.e. they shouldn't be selectable nor poses any behavior. What should cause expanding is clicking the + not the node itself as in ASP TreeView. With ASP TV, that was achievable via

Code: Visual Basic.NET
newNode.SelectAction = TreeNodeSelectAction.None


which justifies the distinction among Expand, Select and SelectExpand (in addition to None) as possible action options in ASP TreeView; the thing I don't see in your TV or find something similar.

As you can see in above post, tried setting their Select() to False, but it didn't help. Then tried Disabled() to end up with nodes clear of any action, not even expanding! Combining both properties together didn't help either. Apparently, Expand/Collapse is governed by the Node itself in your TreeView not by the +/-, which is the situation I'm seeking after.

I even tried removing the call to ClientScript from the TreeView to L1 Nodes, to realise that ClientScript() of Nodes only supports inline JS not Function Names.

So, how to sort that out?

Thanks in advance.

Regards,

Saed Hamdan
"Man may be destroyed but not defeated" -Hemmingway
eo_support
Posted: Thursday, December 18, 2008 2:10:37 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

Thanks for the tip. I am not sure what your request is though. :) As for the code that populates the TreeView, you may not need them at all. The TreeView fully support data binding so most of the time you can just give it a data source and call DataBind to have the TreeView to automatically build all the nodes for you. You can find more information about data binding at here:

http://www.essentialobjects.com/ViewDoc.aspx?t=MenuCommon%2fDataBinding%2fDataBinding_overview.html

Thanks!
eo_support
Posted: Thursday, December 18, 2008 2:23:37 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

You can handle the TreeView's ClientSideOnItemClick and ClientSideOnItemMouseDown to silent client:

Code: HTML/ASPX
<eo:TreeView
   ClientSideOnItemClick="silent_first_level_node"
   ClientSideOnItemMouseDown="silent_first_level_node" ...>
....
</eo:TreeView>


Code: JavaScript
function silent_first_level_node(e, info)
{
    if (eventInfo.getItem().getLevel() == 0)
    {
        eventInfo.cancel();
        return false;
    }
}


Hope this helps.

Thanks
Saed
Posted: Thursday, December 18, 2008 2:29:27 PM
Rank: Advanced Member
Groups: Member

Joined: 10/15/2008
Posts: 45
eo_support wrote:

I am not sure what your request is though. :)


Simply put, I need the nodes to be Expanded/Collapsed by clicking the +/- NOT the node itself. Clicking L0 nodes should do nothing, while clicking L1 nodes should activate Client Script as it is the case now.

I thought I explained that thoroughly though?!

eo_support wrote:

I am not sure what your request is though. :) As for the code that populates the TreeView, you may not need them at all. The TreeView fully support data binding so most of the time you can just give it a data source and call DataBind to have the TreeView to automatically build all the nodes for you.


Thank you for the info, but I know that and already used it to build application Menu. There is a reason for coding tree population in such a way. We have a lot of variations with application TVs that require constructing a wide set of SQL queries for each level, which DataBinding cannot afford. The TV I presented is just a small sample of the larger TVs we have, thus, we are utilising a consistent approach across the application.

Thanks.

Regards,

Saed Hamdan
"Man may be destroyed but not defeated" -Hemmingway
Saed
Posted: Thursday, December 18, 2008 2:55:11 PM
Rank: Advanced Member
Groups: Member

Joined: 10/15/2008
Posts: 45
Sorry my friend. Your function didn't work.

First, it immediately threw an exception upon execution; only when changed EvenInfo to info it worked. However, L0 Nodes still behave as before! eo_CancelEvent() didn't help either.

Any further suggestions?

Regards,

Saed Hamdan
"Man may be destroyed but not defeated" -Hemmingway
eo_support
Posted: Thursday, December 18, 2008 2:59:06 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Sorry about the EventInfo and Info typo. We did verify the code and it works fine here though. With the above code the top level node will not be selected.
Saed
Posted: Thursday, December 18, 2008 3:23:19 PM
Rank: Advanced Member
Groups: Member

Joined: 10/15/2008
Posts: 45
OK, I got it... Since OnClickScript is executed before ClientSideOnItemClick, I moved the cancellation to be executed inline during L0 population:

Code: Visual Basic.NET
...
newNode.OnClickScript = "eo_CancelEvent();"


and it works...

Many thanks for the prompt response.

Regards,

Saed Hamdan
"Man may be destroyed but not defeated" -Hemmingway


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.