Hi. I've a small problem with adding and removing nodes on a treeview on the client and then persisting the changes on a postback, using the ClientChanges property. For the most part, it works as expected, I can Insert, Edit and Remove nodes and process the changes on the server. However, the issue arises if I Insert a node, then Remove it and then try to save the changes.
In the ClientChanges collection, there are ClientOperation items representing both the Insert and the Remove, which, despite being inefficient, should still work. As part of the Insert operation, I am capturing the index property of the node but this throws a NullReferenceException due to, I'm guessing the *pending* Remove operation.
I thought I was maybe using the trackChanges / commitChanges incorrectly and that if instead tracking and committing each operation...
// psuedo code
trackChanges();
insertNode();
commitChanges();
trackChanges();
removeNode();
commitChanges();
...I enabled tracking, performed all my edits and then commited changes, like this
// psuedo code
trackChanges();
insertNode();
removeNode();
commitChanges();
...then it might be smart enough to figure out that net effect is no change. I implemented this but the same problem exists.
Can anyone shed any light on how to
- Retrieve the index on a node that is subject to a pending Remove operation or
- Cancel the add operation for a node thatis subject to a pending Remove operation
Thanks,
Keith.
5 Answers, 1 is accepted
Could you post simple code (both server and client side) reproducing this issue, please?
Just a thought on "As part of the Insert operation, I am capturing the index property of the node":
Are you sure that you actually make the insert before searching for index?
Regards,
Nikolay Tsenkov
the Telerik team
I'm not quite sure what you mean when you say "actually make the insert" - can you explain? Perhaps my previous post wasn't clear, hopefully the source will help you reproduce the problem.
To reproduce:
- Add a child node using the context menu.
- Delete the newly added child node.
- Click Save button
Code as requested:
.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> |
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %> |
<!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"> |
</head> |
<body> |
<form id="form1" runat="server"> |
<div> |
<script type="text/javascript"> |
function ContextMenuItemClicked(sender, EventArgs) { |
// get reference to the associated node |
var node = EventArgs.get_node(); |
var item = EventArgs.get_menuItem(); |
var nodeCommmand = item.get_text(); |
var childNode = null; |
// enable change tracking |
treeview = node.get_treeView(); |
treeview.trackChanges(); |
if (nodeCommmand === "Delete") { |
node.get_parent().get_nodes().remove(node); |
} |
else { |
switch (nodeCommmand) { |
//case 0: |
case "Add Child Node": |
childNode = new Telerik.Web.UI.RadTreeNode(); |
childNode.set_contextMenuID("ChildNodeContextMenu"); |
childNode.set_text("New " + node.get_text() + " Category"); |
break; |
} |
node.expand(); |
} |
// add a new categoryItem node |
if (childNode !== null) { |
node.get_nodes().add(childNode); |
childNode.scrollIntoView(); |
childNode.startEdit(); |
} |
else { |
treeview.commitChanges(); |
} |
} |
// allow edit on doubleclick |
function NodeDoubleClick(sender, EventArgs) |
{ |
var node = EventArgs.get_node(); |
// enable change tracking |
treeview = node.get_treeView(); |
treeview.trackChanges(); |
node.startEdit(); |
} |
function NodeEditing(sender, EventArgs){ |
var node = EventArgs.get_node(); |
var newText = EventArgs.get_newText(); |
if (newText.trim() === "") { |
EventArgs.set_cancel(true); |
// cancelling this also cancels NodeEdited |
return; |
} |
// enable change tracking |
treeview = node.get_treeView(); |
treeview.trackChanges(); |
} |
function NodeEdited(sender, EventArgs) { |
var node = EventArgs.get_node(); |
// commit changes tracking |
treeview = node.get_treeView(); |
treeview.commitChanges(); |
} |
</script> |
<asp:Button ID="btnSave" runat="server" width="75" Text="Save" OnClick="btnSave_Click"/> |
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> |
<telerik:RadTreeView ID="RadTreeView1" runat="server" AllowNodeEditing="True" OnClientContextMenuItemClicked="ContextMenuItemClicked" OnClientNodeEdited="NodeEdited" OnClientNodeEditing="NodeEditing"> |
<Nodes> |
<telerik:RadTreeNode Text="Node 1" ContextMenuID="ContextMenu"> |
<Nodes> |
<telerik:RadTreeNode Text="Node 1.1" ContextMenuID="ChildNodeContextMenu"></telerik:RadTreeNode> |
<telerik:RadTreeNode Text="Node 1.2" ContextMenuID="ChildNodeContextMenu"></telerik:RadTreeNode> |
<telerik:RadTreeNode Text="Node 1.3" ContextMenuID="ChildNodeContextMenu"></telerik:RadTreeNode> |
</Nodes> |
</telerik:RadTreeNode> |
</Nodes> |
<ContextMenus> |
<telerik:RadTreeViewContextMenu ID="ContextMenu"> |
<Items> |
<telerik:RadMenuItem Text="Add Child Node" PostBack="false"></telerik:RadMenuItem> |
</Items> |
</telerik:RadTreeViewContextMenu> |
<telerik:RadTreeViewContextMenu ID="ChildNodeContextMenu"> |
<Items> |
<telerik:RadMenuItem Text="Delete" PostBack="false"></telerik:RadMenuItem> |
</Items> |
</telerik:RadTreeViewContextMenu> |
</ContextMenus> |
</telerik:RadTreeView> |
</div> |
</form> |
</body> |
</html> |
using System; |
using System.Web.UI; |
using Telerik.Web.UI; |
public partial class _Default : System.Web.UI.Page |
{ |
protected void Page_Load(object sender, EventArgs e) |
{ |
if (!IsPostBack) |
{ |
Page.DataBind(); |
} |
} |
protected void btnSave_Click(object sender, EventArgs e) |
{ |
int index; |
for (int operationIndex = 0; operationIndex < RadTreeView1.ClientChanges.Count; operationIndex++) |
{ |
ClientOperation<RadTreeNode> operation = RadTreeView1.ClientChanges[operationIndex]; |
RadTreeNode node = operation.Item; |
switch (operation.Type) |
{ |
case ClientOperationType.Insert: |
// try accessing the nodes index property |
index = node.Index; // nullreference exception thrown here |
break; |
} |
} |
} |
} |
Thanks,
Keith.
The reason why you cannot get the index of this node is that the node is already deleted (you read a log not real-time actions).
Hope this is going to help you!
Regards,
Nikolay Tsenkov
the Telerik team
Thanks for your response. I understand that I'm working with a log of sorts, but I would have expected the log to contain a copy of the node state (incuding the index) at the time of the log entry along with the other node properties.
I realise that the current code isn't optimal - it's obviously inefficient to create a node in the database only to remove it again - but given the ClientChanges returns a list of all changes (as oppose to net changes), that was the best approach available to me at the time.
I'm hoping that the control will be updated to provide either a log with all properties available or the net changes functionality I have described. In the meantime, I'll take a look at implementing some AJAX functionality to perform my node editing in real-time.
Thanks,
Keith.
The problem is that you are getting a node that is detached from any TreeNodeCollection and logically it doesn't have any index.
Hope this makes it more clear for you!
If you are not able to change your implementation in a way to achieve the desired requirements, please post the problem and we will do our best to support you with alternative solution (one that doesn't depend on this index property).
Regards,
Nikolay Tsenkov
the Telerik team