mbraak / jqTree

Tree widget for jQuery
https://mbraak.github.io/jqTree/
Apache License 2.0
1.02k stars 177 forks source link

Dynamic tree and saveState #53

Closed KyorCode closed 12 years ago

KyorCode commented 12 years ago

Based on issue #37 I have managed to implement a dynamicly loading tree. Problem is, my client also requests the feature to save the state of the tree.

Since the whole tree isn't saved to the localstorage or cookie, I need some sort of functionality to refire my ajax requests after a node has been reloaded. Thus loading the childnodes. Those childnodes have to be iterated again to To check if subtrees have to be loaded.

I spotted the onGetStateFromStorage event on the tree object, is this the spot where I can hook up the above logic and return false to further block that event from executing?

I can drop a jsFiddle with some mocked up code if you require my dynamic loading logic.

Thanks in advance!

Regards

mbraak commented 12 years ago

onGetStateFromStorage and onSetStateFromStorage allow you to override the loading and saving of the state. They are used in the unit tests.

So, if I understand you correctly, you want to restore the state of a dynamically loaded tree. Is this correct?

You mention that the state of the tree is not saved using localstorage or a cookie. I don't understand this. Do you think it would not work, or is there a reason you do not use localstorage?

Also, yes, if you can create a jsFiddle example, this would certainly help.

KyorCode commented 12 years ago

Yes, i want to restore a dynamicly created tree. The full node isn't saved, just the node id. That is what i meant. So I could use those two events to implement my logic? Or aren't they called upon restore or save?

KyorCode commented 12 years ago

Ok, I'll try that. I'll post my code as soon as I finishes it :) big thanks'

mbraak commented 12 years ago

When restoring the state, jqTree expects that the whole tree is loaded. Also, loading a subtree using ajax in the onGetStateFromStorage event would not work.

What I would do, is to restore the state myself. The problem is that jqTree has no function to get the state. But I could add a function for that.

KyorCode commented 12 years ago

that would be very kind of you! :)

excuses for all the open/closed/reopens..

mbraak commented 12 years ago

I have added the function getStateFromStorage. This functions returns the open nodes and the selected node:

{"open_nodes":[1,8,23],"selected_node":2}

The function is added to the get-state branch (https://github.com/mbraak/jqTree/tree/get-state).

KyorCode commented 12 years ago

-- old I currently kind of took out your restoreState function on the SaveStateHandler and worked with that to preload my partial tree before initializing the jqtree. Seems to work. :)

-new on a page reload the tree ain't initialized yet, how to I call your function when it is referring of to it's own internal functionality?

KyorCode commented 12 years ago

I got it all working currently: I did however had to modify your script a bit:

futhermore I loaded my state just before the tree initializes, this from outside your plugin/widget. This was done by passing the savedState (if present) as a parameter to my method that handles the initial loading of the first levels. The backend handles the rest and returns either only the first levels (if no savedstate was passed) or a partial tree (if a state was passed )

Now I just need some sort of mechanics to avoid firing extra queries when nodes are open/closed a couple of times without leaving the page. Should be easy by added a 'fetched' property of some sort. :)

mbraak commented 12 years ago

Very interesting. Can you share your code if it is finished?

KyorCode commented 12 years ago

My script: http://jsfiddle.net/h8G3b/1/ (non runnable code)

Adjusted code parts on your script: http://jsfiddle.net/WkXwp/1/ (non runnable code)

It's in c# MVC3 so my view only contains:

<div id="dataTree" data-treename="buildingtree" data-get-url="@Url.Action("GetBuildings", "Buildings")" >

treelevels are: building => floor => zone => room

with treename being the unique reference for the cookie/localstorage value and the get-url to contact my controller and receive the required JSON. As you can see in my script, I add a parameter to the GetJSON if a savedState is present.

Based on that parameter, my backend reactis accordingly an returns either a partial tree or a toplevel only tree. With the "tree.open" event I load all my ajax calls for the sublevels. The url or location where the script should go is added as a data attribute on the node object.

In c# my object looks like this: public class NodeModel { public string id { get; set; } public string label { get; set; } public string GetUrl { get; set; } public bool isGhost { get; set; } public int level { get; set; } public bool fetched { get; set; } public IList children { get; set; } public IList Actions { get; set; } }

The ActionModel: public class ActionModel { public object Link { get; set; } public object Image { get; set; } }

By using anonymous objects and the power of JQuery this is automatically mapped on html elements. Kind of cool once your realise it's potential :)

mbraak commented 12 years ago

Thank you the code.

I'm currently looking at a way to provide better support for loading nodes on demand; a better solution than the 'phantom' node trick.