PDA

View Full Version : [CLOSED] Refresh TreePanel



cwolcott
Nov 11, 2012, 10:21 PM
We created our TreePanel in the markup and created the individual nodes dynamically on the server-side. We have a refresh button that when clicked we need to fully update the TreePanel with new nodes. Thought this was going to be easy, but we had trouble getting the TreePanel to show the new nodes.

After searching the forum I found the thread Refresh TreePanel Server Side (http://forums.ext.net/showthread.php?21572) from Oct 16, 2012 and you suggested looking at the example Tree Panel -> Basic -> Refresh Static Tree (http://examples2.ext.net/#/TreePanel/Basic/Refresh_Static_Tree/).


Is performing the update via a Direct Method the preferred solution?
Is there a way via a direct event?


Below is a sample that I put together:


<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html >
<html>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
BuildOverviewTree();
}

[DirectMethod]
public string RefreshTree()
{
Ext.Net.NodeCollection nodes = new NodeCollection();

Ext.Net.Node root = new Ext.Net.Node();
root.Text = "root";
//rootNode.Expanded = true;
nodes.Add(root);

Ext.Net.Node personNode = new Ext.Net.Node();
personNode.Text = "John Lee Smith";
personNode.Icon = Icon.User;
personNode.Leaf = false;

ConfigItem ci = new ConfigItem();
ci.Name = "Value";
ci.Value = JSON.Serialize("Parent");
personNode.CustomAttributes.Add(ci);
root.Children.Add(personNode);

Ext.Net.Node kidNode = new Ext.Net.Node();
kidNode.Text = "Bobby Smith";
kidNode.Icon = Icon.UserBrown;
kidNode.Leaf = false;
kidNode.CustomAttributes.Add(new ConfigItem("Value", JSON.Serialize("Child")));
personNode.Children.Add(kidNode);

Ext.Net.Node sportNode = new Ext.Net.Node();
sportNode.Text = "Soccer";
sportNode.Icon = Icon.SportSoccer;
sportNode.Leaf = true;
sportNode.CustomAttributes.Add(new ConfigItem("Value", JSON.Serialize("Sport")));
kidNode.Children.Add(sportNode);

return nodes.ToJson();
}

private void BuildOverviewTree()
{
var random = new Random();
Ext.Net.TreePanel YearPanel = YearPanel01;

Ext.Net.Node rootNode = new Ext.Net.Node();
rootNode.NodeID = "root";
rootNode.Expanded = true;

YearPanel.Root.Clear();
YearPanel.Root.Add(rootNode);

for (int yeardt = 2005; yeardt <= 2012; yeardt++)
{
// Prepare the YEAR Node
Ext.Net.Node yearNode = new Ext.Net.Node()
{
Text = yeardt.ToString(),
Icon = Icon.Calendar,
CustomAttributes =
{
new ConfigItem("Value", yeardt.ToString()),
},
Expanded = false,
};

// Prepare the PENDING Requests Node
double pendingRequests = Math.Floor(Math.Max(random.NextDouble() * 100, 0));
Ext.Net.Node pendingNode = new Ext.Net.Node()
{
Text = "Pending - " + pendingRequests.ToString(),
Icon = Icon.BookOpen,
CustomAttributes =
{
new ConfigItem("Value", "Pending", ParameterMode.Value ),
},
Expanded = false
};

if (pendingRequests > 50)
{
double unassignedRequests = Math.Floor(Math.Max(random.NextDouble() * pendingRequests, 0));
Ext.Net.Node unassignedNode = new Ext.Net.Node()
{
Text = "Unassigned - " + unassignedRequests.ToString(),
Icon = Icon.UserAlert,
CustomAttributes =
{
new ConfigItem("Value", "Unassigned", ParameterMode.Value ),
},
Leaf = true
};

pendingNode.Children.Add(unassignedNode);
}
else
pendingNode.Leaf = true;

yearNode.Children.Add(pendingNode);

// Prepare the CLOSED Request Node
double closedRequests = Math.Floor(Math.Max(random.NextDouble() * 400, 0));
Ext.Net.Node closedNode = new Ext.Net.Node()
{
Text = "Closed - " + closedRequests.ToString(),
Icon = Icon.BookRed,
CustomAttributes =
{
new ConfigItem("Value", "Closed", ParameterMode.Value ),
new ConfigItem("Level", "Open", ParameterMode.Value ),
},
Expanded = false,
Leaf = true
};
yearNode.Children.Add(closedNode);

rootNode.Children.Add(yearNode);
}

}

</script>
<head runat="server">
<title></title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<form id="form1" runat="server">
<ext:Panel ID="Info" runat="server" Title="Info" Width="300" Height="100" Layout="FitLayout"
BodyPadding="5" ClientIDMode="Static" />
<ext:Panel ID="Overview" runat="server" Title="OverView" Width="300" Height="400"
Layout="FitLayout">
<HtmlBin>
<script type="text/javascript">
var overviewByYearClicked = function (panel, record) {

var aoText = "All";
var aoIcon = "icon-user";
var statusText = "All";
var statusIcon = "icon-book";

var node = record;

for (var i = record.data.depth; i >= 1; i--) {

switch (i) {
case 3:
aoText = node.raw["Value"];
aoIcon = node.raw["iconCls"];
break;

case 2:
statusText = node.raw["Value"];
statusIcon = node.raw["iconCls"];
break;

case 1:
var yearText = node.raw["Value"];
var yearIcon = node.raw["iconCls"];
break;
}
node = node.parentNode;
}

App.Info.update('Year: <b>' + yearText + ' | ' + yearIcon + '</b>' + '</br>' +
'Status: <b>' + statusText + ' | ' + statusIcon + '</b>' + '</br>' +
'AO: <b>' + aoText + ' | ' + aoIcon + '</b>');
}
</script>
<script>
var refreshTree = function (tree) {
App.direct.RefreshTree({
success: function (result) {
var nodes = eval(result);
if (nodes.length > 0) {
tree.setRootNode(nodes[0]);
}
else {
tree.getRootNode().removeAll();
}
}
});
};
</script>
</HtmlBin>
<Items>
<ext:TreePanel ID="YearPanel01" runat="server" Title="By Year" Icon="Calendar" BodyPadding="5"
RootVisible="false">
<Root>
<ext:Node Text="Root" Leaf="true" />
</Root>
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:ToolbarFill ID="ToolbarFill1" runat="server" />
<ext:Button runat="server" Icon="ApplicationCascade" ToolTip="Expand">
<Listeners>
<Click Handler="#{YearPanel01}.expandAll();" />
</Listeners>
</ext:Button>
<ext:Button runat="server" Icon="Application" ToolTip="Collapse">
<Listeners>
<Click Handler="#{YearPanel01}.collapseAll();" />
</Listeners>
</ext:Button>
<ext:Button runat="server" Icon="ArrowRefresh" ToolTip="Refresh" Handler="refreshTree(#{YearPanel01})" />
</Items>
</ext:Toolbar>
</TopBar>
<Listeners>
<ItemClick Fn="overviewByYearClicked" />
</Listeners>
</ext:TreePanel>
</Items>
</ext:Panel>
</form>
</body>
</html>

Daniil
Nov 12, 2012, 11:41 AM
Hi Chris,





Is performing the update via a Direct Method the preferred solution?



Well, generally, no. Just common things between DirectMethods and DirectEvents which affects on a solution what to choose.

Personally, I would prefer a static DirectMethod in this case.




Is there a way via a direct event?



Here is an example.

Example

<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack && !X.IsAjaxRequest)
{
this.BuildTree(TreePanel1.Root);
}
}

private Ext.Net.NodeCollection BuildTree(Ext.Net.NodeCollection nodes)
{
if (nodes == null)
{
nodes = new Ext.Net.NodeCollection();
}

Ext.Net.Node root = new Ext.Net.Node();
root.Text = "Root";
nodes.Add(root);

string prefix = DateTime.Now.Second + "_";

for (int i = 0; i < 10; i++)
{
Ext.Net.Node node = new Ext.Net.Node();
node.Text = prefix + i;
node.Leaf = true;
root.Children.Add(node);
}

return nodes;
}

public void RefreshMenu(object sender, DirectEventArgs e)
{
Ext.Net.NodeCollection nodes = this.BuildTree(null);

e.ExtraParamsResponse.Add(new Ext.Net.Parameter("nodes", nodes.ToJson(), ParameterMode.Raw));
}
</script>

<!DOCTYPE html>

<html>
<head runat="server">
<title>Refresh Static Tree - Ext.NET Examples</title>

<script type="text/javascript">
var onSuccess = function (tree, result) {
var nodes = result.extraParamsResponse.nodes;

if (nodes.length > 0) {
tree.setRootNode(nodes[0]);
} else {
tree.getRootNode().removeAll();
}
};
</script>
</head>
<body>
<form runat="server">
<ext:ResourceManager runat="server" />

<ext:TreePanel
ID="TreePanel1"
runat="server"
Title="Tree"
Icon="Anchor"
Width="250"
RootVisible="false"
BodyPaddingSummary="0 0 0 10">
<Tools>
<ext:Tool Type="Refresh">
<DirectEvents>
<Click OnEvent="RefreshMenu" Success="onSuccess(#{TreePanel1}, result);" />
</DirectEvents>
<ToolTips>
<ext:ToolTip runat="server" Html="Refresh" />
</ToolTips>
</ext:Tool>
</Tools>
</ext:TreePanel>
</form>
</body>
</html>

cwolcott
Nov 12, 2012, 12:28 PM
To complete my education on this subject I have a final question (I hope).

Why are you not explicitly setting the TreePanel1 in the direct event?


Is it personal preference?
It is to hard/complicated?
Better performance?


After looking at your solution I actually like how the server side deals with the data and the client is handling the controls. Could this be a little bit of MVC creeping into the thought process?

Previously I would have built the data structure and assigned it in my code behind during the direct event.

Daniil
Nov 12, 2012, 1:16 PM
Well, you just asked for the same example but with a DirectEvent. At least, I thought so:)

Yes, this technique can be applied in MVC.

But in your case, you can populate TreePanel's Root during a DirectEvent and call its Render method to cause the changes to be rendered on client.

RCN
Nov 12, 2012, 1:17 PM
<script type="text/javascript">
var reloadRootNode = function (grid) {
var root = grid.getRootNode();
if (root.isExpanded()) {
grid.getStore().load({
node: root
});
}
else {
root.expand();
}
}
</script>




<ext:Button Text="Reload Grid" runat="server">
<Listeners>
<Click Handler="reloadRootNode(App._myGrid);" />
</Listeners>
</ext:Button>

Daniil
Nov 12, 2012, 1:25 PM
Yes, Raphael, this is also an option. But only if a TreePanel is configured with a TreeStore.

But, anyway, I agree with you - it is good to mention.

Here is some example.
http://examples2.ext.net/#/TreePanel/Loaders/Page/

RCN
Nov 12, 2012, 1:38 PM
Sure Daniil, i was aiming for providing a different approach to achieve it, although it's not suitable for Cwolcott's needs.

cwolcott
Nov 12, 2012, 2:02 PM
Daniil - You are perfect in providing responses to questions. At times I am just trying to gain insight into why a particular response is given.

Raphael - Thanks for expanding upon an alternate solution. I appreciate that others are beginning to reply to threads and make this more of a community. i hope I can assist as I get more confident with the framework.



But in your case, you can populate TreePanel's Root during a DirectEvent and call its Render method to cause the changes to be rendered on client.


public void RefreshMenu(object sender, DirectEventArgs e)
{
Ext.Net.NodeCollection nodes = this.BuildTree(null);

TreePanel1.Root.Clear();
TreePanel1.Root.Add(nodes[0]);

//How to tell TreePanel1 to render itself with the new nodes?
TreePanel1.Render();
}

Daniil
Nov 12, 2012, 3:41 PM
Daniil - You are perfect in providing responses to questions. At times I am just trying to gain insight into why a particular response is given.


Thank you for the kind words. For your part you ask them very well. Well, it sounds as a joke, but I am rather serious. It is good when a question is well formulated and no need to ask a ton of additional questions to understand what a person really asks.



Raphael - Thanks for expanding upon an alternate solution. I appreciate that others are beginning to reply to threads and make this more of a community.


Agreed, it is very cool!



i hope I can assist as I get more confident with the framework.


I believe it will happen very soon.



//How to tell TreePanel1 to render itself with the new nodes?

TreePanel1.Render();


Well, there is no need to tell it. A Render method takes a current state of the control.

Does it not work as you expect? Please provide a test case.

Daniil
Nov 12, 2012, 3:44 PM
Sure Daniil, i was aiming for providing a different approach to achieve it, although it's not suitable for Cwolcott's needs.

Thank you for that. Actually, I think it is my weak side. Sometimes I answer exactly a question, but not tell about other approaches.

cwolcott
Nov 13, 2012, 1:26 AM
Here is a small sample.






//How to tell TreePanel1 to render itself with the new nodes?

TreePanel1.Render();

Well, there is no need to tell it. A Render method takes a current state of the control..

On the DirectEvent to refresh the TreePanel I called YearPanel01.Render(); to refresh the data. The data was redisplayed, but I swear I did the same thing in my code at work and it didn't refresh. So I need to look at this again tomorrow morning at work. If I remove YearPanel01.Render(); nothing refreshes.

Another odd issue is if I click the button labeled "ButtonID Undefined" twice I get an error, but I can click the "ButtonID Defined" everything works.



<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html >
<html>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
BuildOverviewTree();
}

protected void RefreshTreePanel(object sender, DirectEventArgs e)
{
BuildOverviewTree();
YearPanel01.Render();
}

private void BuildOverviewTree()
{
Ext.Net.Node rootNode = new Ext.Net.Node();
rootNode.NodeID = "Root";
rootNode.Text = "Root Node";
rootNode.Expanded = true;

YearPanel01.Root.Clear();
YearPanel01.Root.Add(rootNode);

string prefix = DateTime.Now.Second + "_";
for (int i = 0; i < 10; i++)
{
Ext.Net.Node node = new Ext.Net.Node();
node.Text = prefix + i;
node.Leaf = true;
rootNode.Children.Add(node);
}
}

</script>
<head runat="server">
<title>TreePanel Refresh - DirectEvent</title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<form id="form1" runat="server">
<ext:Panel ID="Overview" runat="server" Title="OverView" Width="300" Height="400"
Layout="FitLayout">
<Items>
<ext:TreePanel ID="YearPanel01" runat="server" Title="By Year" Icon="Calendar" BodyPadding="5"
RootVisible="false">
<Root>
<ext:Node Text="Root" Leaf="true" />
</Root>
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:ToolbarFill runat="server" />
<ext:Button ID="RefreshTree" runat="server" Text="ButtonID Defined" Icon="ArrowRefresh" OnDirectClick="RefreshTreePanel" />
<ext:Button runat="server" text="ButtonID Undefined" Icon="ArrowRefresh" OnDirectClick="RefreshTreePanel" />
</Items>
</ext:Toolbar>
</TopBar>
</ext:TreePanel>
</Items>
</ext:Panel>
</form>
</body>
</html>

Daniil
Nov 13, 2012, 5:52 AM
If I remove YearPanel01.Render(); nothing refreshes.


Just to clarify: a Render call is required to get server change of Root collection to be rendered to client.



Another odd issue is if I click the button labeled "ButtonID Undefined" twice I get an error, but I can click the "ButtonID Defined" everything works.



<%@ Page Language="C#" %>

<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<!DOCTYPE html >
<html>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
BuildOverviewTree();
}

protected void RefreshTreePanel(object sender, DirectEventArgs e)
{
BuildOverviewTree();
YearPanel01.Render();
}

private void BuildOverviewTree()
{
Ext.Net.Node rootNode = new Ext.Net.Node();
rootNode.NodeID = "Root";
rootNode.Text = "Root Node";
rootNode.Expanded = true;

YearPanel01.Root.Clear();
YearPanel01.Root.Add(rootNode);

string prefix = DateTime.Now.Second + "_";
for (int i = 0; i < 10; i++)
{
Ext.Net.Node node = new Ext.Net.Node();
node.Text = prefix + i;
node.Leaf = true;
rootNode.Children.Add(node);
}
}

</script>
<head runat="server">
<title>TreePanel Refresh - DirectEvent</title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<form id="form1" runat="server">
<ext:Panel ID="Overview" runat="server" Title="OverView" Width="300" Height="400"
Layout="FitLayout">
<Items>
<ext:TreePanel ID="YearPanel01" runat="server" Title="By Year" Icon="Calendar" BodyPadding="5"
RootVisible="false">
<Root>
<ext:Node Text="Root" Leaf="true" />
</Root>
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:ToolbarFill runat="server" />
<ext:Button ID="RefreshTree" runat="server" Text="ButtonID Defined" Icon="ArrowRefresh" OnDirectClick="RefreshTreePanel" />
<ext:Button runat="server" text="ButtonID Undefined" Icon="ArrowRefresh" OnDirectClick="RefreshTreePanel" />
</Items>
</ext:Toolbar>
</TopBar>
</ext:TreePanel>
</Items>
</ext:Panel>
</form>
</body>
</html>


Well, the Render call re-renders a Button as well. And it assigns a new ID for the Button. Then this Button is not recreated during another request.

Briefly, I think an ID is required for the Button in this case.