PDA

View Full Version : Ext.ux.tree.CheckTreePanel



jsakalos
9 Jan 2009, 6:03 AM
Hi all,

I've just uploaded Ext.ux.tree.CheckTreePanel, example of extension that displays tree node checkboxes and implements various handling of checked nodes.

This is meant for those, including myself, for whom the default TreeNode checkbox implementation is not enough but are seeking for more.

Let me know what you think.

Live Demo: http://checktree.extjs.eu

jay@moduscreate.com
9 Jan 2009, 1:01 PM
Saki, you should consider using cache fly for your ext-js files.


Also, (suggestion) the remote tree panel should only fire a request if the data has changed.

jsakalos
9 Jan 2009, 1:44 PM
What is cache fly?

watrboy00
9 Jan 2009, 5:02 PM
http://extjs.com/blog/2008/11/18/ext-cdn-custom-builds-compression-and-fast-performance/

jsakalos
9 Jan 2009, 5:38 PM
http://extjs.com/blog/2008/11/18/ext-cdn-custom-builds-compression-and-fast-performance/
Thanks for the link.

mjlecomte
13 Jan 2009, 2:34 PM
Saki, you should consider using cache fly for your ext-js files.


Also, (suggestion) the remote tree panel should only fire a request if the data has changed.

I missed this one, interesting. I guess the down side is that you can't have the latest from svn.

jsakalos
13 Jan 2009, 2:53 PM
?

mjlecomte
13 Jan 2009, 3:31 PM
http://extjs.com/blog/2008/11/18/ext-cdn-custom-builds-compression-and-fast-performance/

Saki, I was talking about the link is all. I wasn't aware of it. My comment is out of context from your thread and probably should not have been made. I was merely saying that the cdn hosted build is a great offering, but has the downside that it is "old" code (not the latest from svn).

jsakalos
13 Jan 2009, 4:00 PM
Aaah, I see. Thanks for explanation.

jay@moduscreate.com
14 Jan 2009, 6:59 AM
correct jk. The question is 'do you need the latest?'. For me, the answer is generally no

YuraIM
15 Jan 2009, 8:42 AM
Hi,

a Ext.ux.tree.CheckTreePanel does not work correctly at the change of parameter cascadeCheck(Check/uncheck also child nodes.)

Ths

jsakalos
15 Jan 2009, 8:47 AM
I don't understand what you mean by "does not work correctly". Please elaborate.

YuraIM
15 Jan 2009, 11:17 PM
I don't understand what you mean by "does not work correctly". Please elaborate.

change parameters: "cascadeCheck:'all'" and checked node tree, rezult - browsers irresponsive on further actions(an error here is not generated)

jsakalos
16 Jan 2009, 5:45 AM
change parameters: "cascadeCheck:'all'" and checked node tree, rezult - browsers irresponsive on further actions(an error here is not generated)
It is race condition between cascadeCheck and bubbleCheck. Set cascadeCheck:'all' and bubbleCheck:'none' and it will work.

YuraIM
16 Jan 2009, 5:53 AM
It is race condition between cascadeCheck and bubbleCheck. Set cascadeCheck:'all' and bubbleCheck:'none' and it will work.

thanks

Condor
16 Jan 2009, 8:41 AM
Maybe we should merge your code an my Tri-state tree user extension (http://extjs.com/forum/showthread.php?t=44369)?

My extension supports a grayed (partial) state and bubbling + cascading (but not configurable as your extension).

ps. Small bug: Double-click on the checkbox both checks/unchecks and expands/collapses the node.

jsakalos
16 Jan 2009, 8:56 AM
I've taken your code, crediting you in comments, but I didn't want tri-state functionality. Anyway, if you have an idea how to merge them an easy way, let me know. Best is skype, nick jsakalos.

Re bug: I'll take a look.

mrsunshine
26 Jan 2009, 9:22 AM
Where i have to add a event listeners to get the 'onCheckboxClick' Event?



Test = Ext.extend(Ext.ux.tree.CheckTreePanel, {
initComponent: function(){
Ext.apply(this, {
listeners: {
onCheckboxClick: function(node){
console.log('node:',node);
}

},
height: 150,
autoScroll:true
,rootVisible:false
,root:{
nodeType:'async'


...
The place in my example doesn't work

regards

nils

jsakalos
26 Jan 2009, 9:37 AM
Have you ever seen this: http://blog.extjs.eu/know-how/events-explained/ ?

mrsunshine
26 Jan 2009, 10:48 AM
Have you ever seen this: http://blog.extjs.eu/know-how/events-explained/ ?

yes i did, an i had read it,
but i thought there would be a onCheckboxClick event fired but it only fire a click event with which i have no problems to add a eventhandler to.

jsakalos
26 Jan 2009, 10:55 AM
OK, you can find out which events are fired if you navigate to http://checktree.extjs.eu and then you type in Firebug's console:

Ext.util.Observable.capture(Ext.getCmp('t2'), function(e){console.log(e);})

This will capture events from upper right checktree panel.

mrsunshine
26 Jan 2009, 11:09 AM
OK, you can find out which events are fired if you navigate to http://checktree.extjs.eu and then you type in Firebug's console:

Ext.util.Observable.capture(Ext.getCmp('t2'), function(e){console.log(e);})

This will capture events from upper right checktree panel.

Cool thank you, the capture snippe helped me a lot.

Ext.util.Observable.capture(Ext.getCmp('t2'), function(e){console.log(e);})

:)

jbird526
4 Feb 2009, 1:45 PM
I wrote these button functions for my CheckTreePanel and would like your opinion about how long handed and badly formed they are. They do work but I just have a feeling that I am digging to far and they could be simplified.


checkAllTitles: function(){
var x = Ext.getCmp('t2');
var foo = [];
foo = x.root.firstChild.childNodes;
for (i = 0; i < foo.length; i++)
{
foo[i].ui.setChecked(true);
}
console.log('checkAllTitles');
},

checkAllTitlesTopics: function(){
var x = Ext.getCmp('t2');
var foo = [];
foo = x.root.firstChild.childNodes;
for (i = 0; i < foo.length; i++)
{
foo[i].eachChild(function(n){
var ui = n.getUI();
ui.setChecked(true);
})
}
console.log('checkAllTitlesTopics');
}


http://mysite.verizon.net/vzevn2mf/ext/checktreesaki.png

http://mysite.verizon.net/vzevn2mf/ext/checktreesaki2.png

http://mysite.verizon.net/vzevn2mf/ext/checktreesaki3.png

jsakalos
4 Feb 2009, 1:49 PM
Hmm, if it works it's fine. We could spend ages on speculating if it could have been written other way or better. Works? Yes? Go ahead and use them in your app.

jbird526
4 Feb 2009, 2:08 PM
Hmm, if it works it's fine. We could spend ages on speculating if it could have been written other way or better. Works? Yes? Go ahead and use them in your app.

Thats usually what I say also. I've been stepping thru your code to understand how everything works. Appreciate the lengths that you go thru to release code that helps those of us that are not as gray matter blessed. :D

Thanx for the reply, maybe the code will make shorter work for someone else.

wyyacyy
5 Feb 2009, 7:34 PM
I want to build a treepanel with checkbox. I user struts2,How do I return a json array ?
what should I care about?

JSON[{"checked":false,"children":[{"checked":false,"children":[],"cls":"file","id":11,"leaf":true,"text":"S600"},{"checked":false,"children":[],"cls":"file","id":12,"leaf":true,"text":"SLK200"}],"cls":"folder","id":10,"leaf":false,"text":"Benz"}]

the checkbox canot show ,why?

jsakalos
5 Feb 2009, 7:56 PM
Sorry, I cannot help you with server-side, I don't even know what is struts2. The json you posted is not valid and cannot be decoded (Ext.decode(that-what-you-posted).

wyyacyy
8 Feb 2009, 10:00 PM
Thanking for replying

jbird526
13 Feb 2009, 10:30 AM
Saki thanx again for making this extension available. It has saved me a bunch of time and has helped me understand how to manipulate trees. PS I made a donation, which I hope others will follow my example.

jsakalos
13 Feb 2009, 10:45 AM
Thank you very much for both your kind words and the donation.

jsakalos
15 Feb 2009, 12:18 PM
I've added some form compatibility methods (very simple, to-be-improved) and I've created the example of using CheckTreePanel as a form field in form.

http://examples.extjs.eu/?ex=treeinform

cybersys
22 Feb 2009, 10:06 AM
Is it possible to use the checkTreePanel in a form using AsyncTreeNode with a loader.

I test put loader:myloader but i get only the nodes that belong to the root node, when click to expand a node get nothing (loader is not calling at all).

Is it possible and i am doing something wrong or its not possible

Really great job

Thanks

jsakalos
22 Feb 2009, 10:26 AM
It has been designed for preloaded trees. That doesn't mean that it couldn't work, I only haven't tested it because purpose seems questionable to me.

cybersys
22 Feb 2009, 10:35 AM
Thanks for your reply

The only reason for AsyncTreeNode is for large trees and render time issues.In my application i have a tree with 4500 nodes (dont ask me why).

If i did not have that amount of data i would not thinking of AsyncTreeNode

Thanks again

Its really great job

jsakalos
22 Feb 2009, 10:40 AM
You are welcome to look inside and make CheckTreePanel to work with dynamic trees - I haven't done it as I don't need it.

cybersys
22 Feb 2009, 10:48 AM
The truth is that i am planning to do

Thanks Again

scosta
23 Feb 2009, 6:50 AM
Hi Saki,

First of all let me thank you for creating this extension. Really is a time saver.
I just want to point out that constructor for this component is not working quite as it should due to behavior of underlying parent class. As a result every event for this tree gets triggered twice. Obvious example is when you define "contextmenu" and it's corresponding handler. Another manifestation is that "editDelay" and click (for node editing) deferrer are not working when you define a tree editor for this extension.
Let me explain:


initComponent:function() {

// call parent initComponent
Ext.ux.tree.CheckTreePanel.superclass.initComponent.apply(this, arguments);

// pass this.baseAttrs and uiProvider down the line
var baseAttrs = Ext.apply({uiProvider:Ext.ux.tree.CheckTreeNodeUI}, this.baseAttrs);
Ext.applyIf(this.loader, {baseAttrs:baseAttrs, preloadChildren:true});

// make sure that nodes are deeply preloaded
if(true === this.loader.preloadChildren) {
this.loader.on('load', function(loader, node) {
node.cascade(function(n) {
loader.doPreload(n);
n.loaded = true;
});
});
}

// use our event model
this.eventModel = new Ext.ux.tree.CheckTreeEventModel(this);

// create tree filter
if(true === this.filter) {
var Filter = Ext.ux.tree.TreeFilterX ? Ext.ux.tree.TreeFilterX : Ext.tree.TreeFilter;
this.filter = new Filter(this, {autoClear:true});
}

}
This part creates the odd behavior :

...
// call parent initComponent
Ext.ux.tree.CheckTreePanel.superclass.initComponent.apply(this, arguments);
...cause superclass's (TreePanel) init function calls:

...
if(!this.eventModel){
this.eventModel = new Ext.tree.TreeEventModel(this);
}
...
which creates default listeners by calling initEvents in TreeEventModel.

You then proceed with redefining this.eventModel but alas default events from the original TreeEventModel are already attached thus creating troublesome overhead and potential buggy behavior.

Quick fix to fool superclass's (TreePanel) init function into beleiving that event model is already defined is:

...
this.eventModel = true;

// call parent initComponent
Ext.ux.tree.CheckTreePanel.superclass.initComponent.apply(this, arguments);
...preventing unwanted eventModel being initialized.

Hope you'll have some more elegant way of getting around this pretty bad behavior.
Thanks

jsakalos
23 Feb 2009, 7:21 AM
Thanks for pointing out. My first idea while reading this wast to move this.eventMode = .... before the parent call. Have you tested it? If it works it is the most elegant solution we can ever have.

scosta
24 Feb 2009, 12:37 AM
It seams to work - wasn't sure thou whether initComponent should add anything to this before defining event model.

There are few more things that need improving.
One is recursion deadlock when the tree has, for example, cascadeCheck set to 'all' and bubbleCheck set to 'checked'. Problem is that function onCheckChange is triggering onCheckChange both for parent node and child nodes which in return again propagate this event back to originating node.

My solution was to add propagation direction to this function preventing event backfiring to originating node:

onCheckChange:function(propagationDirection) {
var checked = this.isChecked();
var tree = this.node.getOwnerTree();
var bubble = tree.bubbleCheck;
var cascade = tree.cascadeCheck;

if ('undefined' == typeof(propagationDirection)) {
propagationDirection = 'both';
}

if ('both' == propagationDirection || 'up' == propagationDirection) {
if('all' === bubble || (checked && 'checked' === bubble) || (!checked && 'unchecked' === bubble)) {
this.updateParent(checked, 'up');
}
}
if ('both' == propagationDirection || 'down' == propagationDirection) {
if('all' === cascade || (checked && 'checked' === cascade) || (!checked && 'unchecked' === cascade)) {
this.updateChildren(checked, 'down');
}
}

this.fireEvent('checkchange', this.node, checked);
}

setChecked:function(checked, propagationDirection) {
checked = true === checked ? checked : false;
var cb = this.cbEl || false;
if(cb) {
true === checked ? cb.addClass('x-tree-node-checked') : cb.removeClass('x-tree-node-checked');
}
this.node.attributes.checked = checked;
this.onCheckChange(propagationDirection);
return checked;
}

updateParent:function(checked, propagationDirection) {
var p = this.node.parentNode;
var ui = p ? p.getUI() : false;

if(ui && ui.setChecked) {
ui.setChecked(checked, propagationDirection);
}
}

updateChildren:function(checked, propagationDirection) {
this.node.eachChild(function(n) {
var ui = n.getUI();
if(ui && ui.setChecked) {
ui.setChecked(checked, propagationDirection);
}
});
}
Also, delegateUp from Ext.ux.tree.CheckTreeEventModel is interfering with DragDropMgr cause it always returns false when node is dragged. Any idea how to preserve your original functionality (regarding disabled nodes and checkbox event) and still allow DD to happen properly?

Quickest way seams to be using:


,delegateDown:function(e, t){
if(e.getTarget('.x-tree-checkbox', 1)){
if(!this.beforeEvent(e)){
return false;
}
this.onCheckboxDown(e, this.getNode(e));
}
}
,delegateUp:function(e, t){
if(e.getTarget('.x-tree-checkbox', 1)){
if(!this.beforeEvent(e)){
return false;
}
this.onCheckboxUp(e, this.getNode(e));
}
}
instead of


,delegateDown:function(e, t){
if(!this.beforeEvent(e)){
return false;
}
if(e.getTarget('.x-tree-checkbox', 1)){
this.onCheckboxDown(e, this.getNode(e));
}
}
,delegateUp:function(e, t){
if(!this.beforeEvent(e)){
return false;
}
if(e.getTarget('.x-tree-checkbox', 1)){
this.onCheckboxUp(e, this.getNode(e));
}
}

jsakalos
24 Feb 2009, 2:13 AM
Re event model: Perfect, moving up before the parent call.
Re cascade/bubble: Yes, there are invalid combinations but they have been there also before.
Re drag: Do you really need DD? The original idea behind CheckTreePanel was: To give user a presentations of hierarchically ordered options. So, as you cannot reorder (DD) combo box items, I haven't even dreamed about any editing of CheckTreePanel. (RemoteTreePanel is the place to create the tree that will be later presented to the user.) I could only say that CheckTreePanel is read-only and doesn't support DD now.

jbird526
26 Feb 2009, 8:57 AM
I have a simple two panel wizard that has a dataview in the first and a checktreepanel in the second. I have a back button on the second panel which when I click goes back to the first card and calls the function prefiousCard in the code. In that function it removes the tree. When I select from the dataview and go to the new panel I receive an error of this.nodeHash is null. I have checked the DOM because when the tree is created I have the rootnode set from an ajax response. The DOM elements are changing to the correct children. Unsure what do next.




Ext.namespace('Ext.umuc');

Ext.umuc.ImportConferenceWizard = Ext.extend(Ext.Panel, {
id : 'wizard-panel',

layout : 'card',

closable : true,

activeItem : 0,

border : false,

frame : false,

layoutConfig : {
deferredRender : true
},

initComponent : function() {

this.items = [{
id : 'card-0',
layout : 'border',
autoScroll : true,
items : [classListPanel = new Ext.Panel({
region : 'north',
height : 40,
border : false,
frame : false,
html : '<div><p class="instructions">Select the class that you want to import from, then click Next button at bottom of the window.</p></div>'
}), classList = new Ext.Panel({
id : 'card-0-list',
region : 'center',
border : false,
items : [importForm = new Ext.umuc.ImportConferenceForm(
{
id : 'class-list-form',
border : false

})],
bbar : ['->', {
id : 'classlist-next-button',
text : 'Next',
handler : this.classListNext
}
]
})]
}, {
id : 'card-1',
// layout:'border',
autoScroll : true,
bbar : ['->', {
id : 'move-prev',
text : 'Back',
handler : this.previousCard

}, {
id : 'move-next',
text : 'Next',
handler : this.submitImport
}],
items : [

new Ext.Panel({
region : 'north',
height : 40,
border : false,
frame : false,
html : '<div><p class="instructions">Select conference titles and conference topics that you would like to import.</p></div>'
}), treeForm = new Ext.form.FormPanel({

id : 'class-form-tree',
autoScroll : true,
border : false,
labelSeparator : '',// removes colon with no fieldLabel set
layout : 'auto',// needed with labelSeparator to remove colon
bodyStyle : 'padding-left: 7px; padding-top:0px; padding-bottom:5px; border-bottom:1px solid #99BBE8;',
items : [

makeVisibleCheckbox = new Ext.form.Checkbox({
id : 'makeVisibleCheckbox ',
frame : false,
fieldLabel : 'Make Visible',
boxLabel : ' <b>On import set Available to Students to "No". By default it is set to todays date.</b>'
}),
confListField = new Ext.form.TextField({
id : 'confList',
hidden : true,
// style:'margin-top:2px',
name : 'confList',
width : 550

}),// eo value2
noteListField = new Ext.form.TextField({
id : 'noteList',
hidden : true,
// style:'margin-top:2px',
name : 'noteList',
width : 550,
listeners : {
focus : function() {
this.setValue(t2.hasChildNodes());
}
}
})// eo value3

]
}), // eo treeForm

checkTree = new Ext.ux.tree.CheckTreePanel({
region : 'center',
id : 'check-tree',
bodyStyle : 'padding-bottom: 5px',
frame : false,
border : false,
autoWidth : true,
autoHeight : true,
autoScroll : true,
rootVisible : false,
tbar : [{
id : 'move-prev',
text : 'Select all Titles',
handler : this.checkAllTitles
}, {
id : 'move-next',
text : 'Select all Titles and Topics',
handler : this.checkAllTitlesTopics
}]

})
]
}];

Ext.umuc.ImportConferenceWizard.superclass.initComponent.call(this);

},// eo initComponent

classListNext : function(btn, pressed) {

var form = Ext.getCmp('class-list-form');
form.getForm().submit({
url : tychoContext + 'conference/getImportableConferencesAndNotes.tycho',
waitMsg : 'Loading conferences...',

success : function(form, action) {
var treeResponse = [];
treeResponse[0] = Ext.decode(action.response.responseText);
checkTree.setRootNode(new Ext.tree.AsyncTreeNode({
children : treeResponse,
uiProvider : false,
expanded : true,
id : 'async-tree-node'
}));
var cardZero = Ext.getCmp('wizard-panel');
cardZero.getLayout().setActiveItem(1);
cardZero.doLayout();

},
failure : function(response, options) {
Ext.MessageBox.alert('Error loading classlist',
'Close import window and try again.');

}
});
},

submitImport : function(btn, pressed) {
var form = Ext.getCmp('class-form-tree');
var classTitles = confListField.getValue();
var classTopics = noteListField.getValue();
// var makeVisible = makeVisibleCheckbox.getValue();
var classTitles = classTitles.substring(classTitles.indexOf(',') + 1); // removes
// the
// classname
// node
// before
// submitting
// values
var progress = Ext.Msg.wait('Importing conferences...');
Ext.Ajax.request({
// form.getForm().submit({
url : tychoContext + 'conference/importConferenceList.tycho',
params : {
// visible:makeVisible,
confList : classTitles,
noteList : classTopics
},
success : function(response, options) {
progress.hide();
var win = Ext.getCmp('import-window');
win.close();
var grid = Ext.getCmp('manage-conference');
grid.store.reload.defer(100, grid.store);

},
failure : function(response, options) {
progress.hide();
Ext.MessageBox.alert('Error importing conferences',
'Close import window and try again.');

}
});
},

previousCard : function() {
var cardOne = Ext.getCmp('card-1');
cardOne.remove(checkTree);

var cardZero = Ext.getCmp('wizard-panel');
cardZero.getLayout().setActiveItem(0);
cardZero.doLayout();

},

checkAllTitles : function() {
var x = Ext.getCmp('check-tree');
var foo = [];
foo = x.root.firstChild.childNodes;
for (i = 0; i < foo.length; i++) {
foo[i].ui.setChecked(true);
}
console.log('checkAllTitles');
confListField.setValue(checkTree.isParent());// custom - added to
// enter values into
// fields
},

checkAllTitlesTopics : function() {
var x = Ext.getCmp('check-tree');
var foo = [];
foo = x.root.firstChild.childNodes;
for (i = 0; i < foo.length; i++) {
foo[i].ui.setChecked(true);
foo[i].eachChild(function(n) {
var ui = n.getUI();
ui.setChecked(true);
})
}
console.log('checkAllTitlesTopics');
confListField.setValue(checkTree.isParent());// custom - added to
// enter values into
// fields
noteListField.setValue(checkTree.hasChildNodes());// custom - added to
// enter values into
// fields
}

});
Ext.reg('importconferencewizard', Ext.umuc.ImportConferenceWizard);

jsakalos
26 Feb 2009, 9:06 AM
I wouldn't remove tree if not necessary; couldn't you just hide it?

jbird526
26 Feb 2009, 9:25 AM
When I use hide the DOM elements dont change when I select an item in the dataview and it sends me to the card with the checktree. The rootnode does change, at least thats what Firebug is showing. I am open to however I have to make the checktree view updated with the new info.

jsakalos
26 Feb 2009, 9:38 AM
I'm not quite sure if I understand what do you want to achieve. I thought that you're removing the whole tree and that that was causing the trouble, so I advised to hide. Anyway, it seems that this is not the case.

Do you need to reload the tree? tree.root.reload() ?

jbird526
26 Feb 2009, 10:02 AM
I'm sorry im being confusing. Ok I went back and commented out the hide that I just added in my function previous card.


previousCard : function() {
var cardOne = Ext.getCmp('card-1');
//cardOne.hide(checkTree);

var cardZero = Ext.getCmp('wizard-panel');
cardZero.getLayout().setActiveItem(0);
cardZero.doLayout();

},

What is happening is that when I come into the window and select something in the dataview, I then click next and it takes me to the next card with the checktree. It displays a tree with the nodes generated by a server response. The user can then select and submit the selections. Alternately the user can click back to go to the first card and that is where the issue is coming up.

When the user goes back to the first card they then select from the dataview and click next to submit the form and get the response from the server. The treenode is then set in the success by setRootNode. It appears that the rootnode is changed when I step thru Firebug and I also check the DOM and they appear to be the new nodes from this new response.

What I am seeing when the second card is displayed is the tree nodes from the first time I went thru the wizard. Essentially I guess what I need is the view to refresh in that card so it will show the new tree that is supposed to be displayed.

Hope this is a bit clearer, I am not the best at documentation. :)

jsakalos
26 Feb 2009, 10:11 AM
Aha, you want to replace the root node, right? Hmmm, I haven't done it with checktree (yet) but I'd expect that it should work like with normal tree. In any case I start to believe that the best would be if you could post a working showcase (http://extjs.com/forum/../learn/Ext_Forum_Help#Posting_a_working_showcase).

jbird526
26 Feb 2009, 10:16 AM
Aha, you want to replace the root node, right? Hmmm, I haven't done it with checktree (yet) but I'd expect that it should work like with normal tree. In any case I start to believe that the best would be if you could post a working showcase (http://extjs.com/forum/../learn/Ext_Forum_Help#Posting_a_working_showcase).

You are correct sir. I will try to post working example. I am in a bit of a closed environment so it might take me some time. Really appreciate the response.

drpepper
23 Mar 2009, 4:22 AM
Perhaps you can render a hidden field for each checkbox instead of submitting the values in one field if formField = true...

something like


<!--virtual tree checkbox html goes here-->
<input type="hidden" name="__the_tree_name[]" value="__node.attributes.value">

jsakalos
23 Mar 2009, 5:17 AM
Can you elaborate? I don't see the reason.

drpepper
23 Mar 2009, 6:14 AM
the handling of the submitted value e.g. to php is more intuitive if an array is posted to the script. static forms with checkboxes from a list are normally submitted in an array... just thought about that...

otherwise: have you read my pn?

jsakalos
23 Mar 2009, 6:39 AM
I also used [] in names before Ext ([] may use special handling in javascript). Now I use:


// having $value = "1,4,6,77";
$a = json_decode("[$value]");

drpepper
23 Mar 2009, 7:13 AM
Hi jsakalos,

i had a look at your example form with the CheckTreePanel and added it to my form (using vista-style tree arrows on expandable nodes, useArrows = true). I have added a TreeLoader to the tree and encountered a problem:

the nodes are not expandable anymore.

i traced the code and get stuck in the TreeEventModel in the delgateClick around line 724-726, on call


this.onNodeClick(e, this.getNode(e));lets the whole script die...

i have added the tree like this:




[...]

columnWidth: .3,
autoHeight: true,
xtype: 'fieldset',
labelAlign: 'top',
border: false,
items: [{
name: 'product_categories',
id: 'product_categories',
xtype: 'checktreepanel',
isFormField: true,
fieldLabel: 'categories',
height: 180,
autoScroll: true,
border: true,
bodyStyle: 'background-color:white;border:1px solid #B5B8C8',
style: 'margin-right:10px;',
rootVisible: false,
useArrows: true,

root: new Ext.tree.AsyncTreeNode({
id: 'category_root',
listeners: {
load: function(node) {
node.expandChildNodes();
}
}
}),

loader: new ProductForm.ProductCategoryLoader({
listeners : {
beforeload: function(a, node) {
this.baseParams.node_id = (node.id == 'category_root' ? '0' : node.attributes.category_id);
}
},
dataUrl: ProductForm.CATEGORY_TREE_XML_URL
}),

}]
}, {

[...]

do you have a suggestion? something that i missed out?

jsakalos
23 Mar 2009, 7:41 AM
CheckTreePanel is not meant for dynamically loaded trees but for pre-loaded, fully loaded trees. See http://checktree.extjs.eu

drpepper
23 Mar 2009, 8:03 AM
maybe we can manage to add this functionality too?

jsakalos
23 Mar 2009, 8:06 AM
No, that would change the concept. There is setValue method that can work only if it has all nodes ready/loaded.

drpepper
23 Mar 2009, 8:10 AM
ok, so perhaps we can build another component for that issue? ...and rewrite set/getValue...

regardless of this, is it possible to solve the problem why the node does not expand anymore if we click on the [+]-sign on dynamically loaded node like it does on normal tree? may you please, please have a look at your TreeModel lie i wrote in my older post?

drpepper
23 Mar 2009, 8:11 AM
...would be really kind of you! :)

jsakalos
23 Mar 2009, 8:12 AM
Look, I do not write components because users want them. I write them because I need them. Then I publish because somebody else can need them too.

You are free to do the same.

wyyacyy
7 Apr 2009, 10:16 PM
if I check parents node ,i hope childnode is also checked.
if I check child node ,i hope parent node is also checked..

how to do it?

,bubbleCheck:'checked'
,cascadeCheck:'checked' will cause problems..Have any solutions???

jsakalos
7 Apr 2009, 10:50 PM
I've never used it in this combination so there may be some problem. I'll take a look but not immediately; have some other things to do.

wyyacyy
7 Apr 2009, 10:56 PM
thanks .

Jangla
8 Apr 2009, 12:31 AM
Is there any way validation can be added to this control? For example, I want to check that the user has checked at least one node before moving on.

jsakalos
8 Apr 2009, 12:49 AM
It is not implemented but can be added quite easily. Take a look at the source code, there are already hooks for that.

ozilix
10 Apr 2009, 11:35 AM
your check tree panel is good but not best!
please check that and let me know what you think
here is the link:
http://myjui.com/latestbuild/mj/res/myjui/examples/

jsakalos
10 Apr 2009, 2:54 PM
I haven't found anything similar to CheckTreePanel on that site.

Re: good but not best: I'm always seeking solutions that are workable for me, having no time for bestsolutions. However, I'm very interested in the best solution. Can you navigate me on that page?

ozilix
10 Apr 2009, 10:14 PM
I think your tree implementation is good but have some bugs.here is the navigation for you

please check that attachment

jsakalos
11 Apr 2009, 12:57 AM
Are they Ext examples?

ozilix
11 Apr 2009, 7:02 AM
these are NOT ext! meybe you can't understand what is different between ext and myJUI!!!
Look carefully please. myJUI based on JQUERY 1.2.6. where is ext???
how can you say "Are they Ext examples?". where is the chart library for ext like this. Ok its look like ext but NOT EXT!

mjlecomte
11 Apr 2009, 7:12 AM
these are NOT ext! meybe you can't understand what is different between ext and myJUI!!!
Look carefully please. myJUI based on JQUERY 1.2.6. where is ext???
how can you say "Are they Ext examples?". where is the chart library for ext like this. Ok its look like ext but NOT EXT!

This is an ExtJS forum. I don't understand why you're posting for another framework if it's not compatible to ExtJS.

Jangla
14 Apr 2009, 1:16 AM
It is not implemented but can be added quite easily. Take a look at the source code, there are already hooks for that.
OK, so I've found the hooks down around line 300 in the code but I'm not sure how to call any validation code I'll stick in there. For example, it would seem that the easiest way to validate for my needs is to call serialize() and if it's equal to "" then it's invalid. But where do I call the validation from? I've tried looking at other code in other controls but there seems to be several different ways of doing things, therefore making it more difficult to unpick.

jsakalos
14 Apr 2009, 7:42 PM
You don't call validation, it is called by framework. You only need to supply a function that returns true if field is valid, false otherwise. There still would be no invalid mark though so you would maybe want to implement clearInvalid and markInvalid.

Anyway, I can take a look into it after the conference. Remind me then please.

edykstra
21 Apr 2009, 6:34 AM
Hello Jozef,

My application of the CheckTree is for Groups and Sub Groups. Since a Sub Group can belong to more than one Group (as long as there is no recursion) I have the requirement to set a value as checked, (for a leaf or branch) in more than one location (branch).

Now, the CheckTree readily displays a particular Sub Group in more than one location, but when I work with setValue(), it only checks ONE instance of the Sub Group.

I've found the line in the following line in the Check Tree source in the setValue function definition:

var n = this.getNodeById(id)

However, I can't find the definition of 'getNodeById' itself.

So - I realize what I am doing here is not what CheckTree was designed for - because a leaf/branch doesn't belong to more than one branch - but this (Groups and Sub Groups) does seem to be a good application for it as well.

Is there a way I can easily change the code such that a call to checkTree.setValue('12') will set ALL the nodes with ID = 12 to checked?

Thanks,

Eric

jsakalos
21 Apr 2009, 9:59 AM
Well, node ids must be unique. getNodeById: http://extjs.com/deploy/dev/docs/?class=Ext.tree.TreePanel&member=getNodeById

edykstra
21 Apr 2009, 11:50 AM
Jozef,

OK. I am understanding things a bit better now. I had followed your examples at http://checktree.extjs.eu/ to determine the syntax of the JSON data returned. There are values for 'id' and for 'nodeID'. Initially, I just set them both to the same value. Now, I have changed my code to have a unique 'nodeID', but the 'id' value is still the value of the 'id' in the appropriate DB table.

This thread sent me 'off course': http://extjs.com/forum/showthread.php?p=231754 So did the 'redundant' values for 'id' and 'nodeID'.

Perhaps a better question is to ask what the proper way to do this is?

Thanks,

Eric

jsakalos
21 Apr 2009, 2:58 PM
nodeID in the example is internal id of the backend. In the example, both ids and nodeIDs must be unique. You see, if you need a "link" logic, where some nodes are are links to another nodes already present in the tree, you need to implement this logic somehow.

Neither standard tree nor my checktree has not been designed with such links in mind.

edykstra
21 Apr 2009, 3:44 PM
Jozef,

I think I've got it straight now ..... in your example at http://checktree.extjs.eu/

id = node id property of the Tree Node

nodeID = attribute you added to reference the id of the row in the table of the back end database.

The terminology got me confused because the docs describe 'id' as the 'node id', and in most DB tables, the 'id' column is called 'id'. So, I had it backwards. To keep it straight in my code, I've renamed 'nodeID' as 'tableID'. :D

I haven't finished testing, but it looks like things are working well now.

Thanks!

Eric

jsakalos
22 Apr 2009, 3:23 AM
Perfect! Congrats!

Jangla
22 Apr 2009, 7:28 AM
Anyway, I can take a look into it after the conference. Remind me then please.
Is the conference over?

At the moment I've set the tree to invalid when it loads and defined a validator (which looking at the check tree object in firebug seems pointless as it doesn't have that property):



Ext.getCmp('regions').markInvalid();
Ext.getCmp('regions').validator = validateRegions;


The defined the function:



var validateRegions = function()
{
if ( Ext.getCmp('regions').getValue() == "" )
{
return "You must select at least one region";
} else {
Ext.getCmp('regions').clearInvalid();
return true;
}
}


...but nothing. Presumably because, as mentioned above, the check tree doesn't have a validator property so the function can never get called.

Also tried adding a click listener and a check listener to no avail - function still isn't called.

thirstypixel
24 Apr 2009, 1:46 PM
Thanks for this Plugin, it is very useful!

I have ran into a scenario where I need to have the functionality of both cascadeCheck: all and bubbleCheck: all. It lags FF for a bit then spits out a bunch of recursion errors. I will try to poke around in the source and see if I can fix the problem... in theory both of these options set to 'all' should be a valid configuration option.

Cheers

jsakalos
24 Apr 2009, 2:15 PM
Yeah, I know, I was just too lazy to fix it as I don't need this combination. :">

Jangla
27 Apr 2009, 2:17 AM
jsakalos - are you able to assist with this validation issue we're having? Essentially all we want it to do is insist that at least one node is checked - for the moment. Once we can get this basic stuff set up we should be able to scale it to more complex stuff but at the moment I can't even get off th ground :-/

jsakalos
27 Apr 2009, 6:39 AM
How far have you got so far?

Jangla
27 Apr 2009, 7:34 AM
Just in case it was required, I added in some code I found on the forums to add validation to check boxes:



Ext.override(Ext.form.Checkbox, {
onRender: function(ct, position){
Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
if(this.inputValue !== undefined){
this.el.dom.value = this.inputValue;
}
this.el.removeClass(this.baseCls);
//this.el.addClass('x-hidden');
this.innerWrap = this.el.wrap({
//tabIndex: this.tabIndex,
cls: this.baseCls+'-wrap-inner'
});
this.wrap = this.innerWrap.wrap({cls: this.baseCls+'-wrap'});
this.imageEl = this.innerWrap.createChild({
tag: 'img',
src: Ext.BLANK_IMAGE_URL,
cls: this.baseCls
});
if(this.boxLabel){
this.labelEl = this.innerWrap.createChild({
tag: 'label',
htmlFor: this.el.id,
cls: 'x-form-cb-label',
html: this.boxLabel
});
}
//this.imageEl = this.innerWrap.createChild({
//tag: 'img',
//src: Ext.BLANK_IMAGE_URL,
//cls: this.baseCls
//}, this.el);
if(this.checked){
this.setValue(true);
}else{
this.checked = this.el.dom.checked;
}
this.originalValue = this.checked;
this.markEl = this.innerWrap;
},
afterRender: function(){
Ext.form.Checkbox.superclass.afterRender.call(this);
//this.wrap[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
this.imageEl[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
},
initCheckEvents: function(){
//this.innerWrap.removeAllListeners();
this.innerWrap.addClassOnOver(this.overCls);
this.innerWrap.addClassOnClick(this.mouseDownCls);
this.innerWrap.on('click', this.onClick, this);
//this.innerWrap.on('keyup', this.onKeyUp, this);
if(this.validationEvent !== false){
this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
}
},
onFocus: function(e) {
Ext.form.Checkbox.superclass.onFocus.call(this, e);
//this.el.addClass(this.focusCls);
this.innerWrap.addClass(this.focusCls);
},
onBlur: function(e) {
Ext.form.Checkbox.superclass.onBlur.call(this, e);
//this.el.removeClass(this.focusCls);
this.innerWrap.removeClass(this.focusCls);
},
onClick: function(e){
if (e.getTarget().htmlFor != this.el.dom.id) {
if (e.getTarget() != this.el.dom) {
this.el.focus();
}
if (!this.disabled && !this.readOnly) {
this.toggleValue();
}
}
//e.stopEvent();
},
onEnable: Ext.form.Checkbox.superclass.onEnable,
onDisable: Ext.form.Checkbox.superclass.onDisable,
onKeyUp: undefined,
setValue: function(v) {
var checked = this.checked;
this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
if(this.rendered){
this.el.dom.checked = this.checked;
this.el.dom.defaultChecked = this.checked;
//this.wrap[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
this.imageEl[this.checked ? 'addClass' : 'removeClass'](this.checkedCls);
}
if(checked != this.checked){
this.fireEvent("check", this, this.checked);
if(this.handler){
this.handler.call(this.scope || this, this, this.checked);
}
}
},
getResizeEl: function() {
//if(!this.resizeEl){
//this.resizeEl = Ext.isSafari ? this.wrap : (this.wrap.up('.x-form-element', 5) || this.wrap);
//}
//return this.resizeEl;
return this.wrap;
},
markInvalid: Ext.form.Checkbox.superclass.markInvalid,
clearInvalid: Ext.form.Checkbox.superclass.clearInvalid,
validationEvent: 'click',
validateOnBlur: false,
validateValue: function(value){
if(this.vtype){
var vt = Ext.form.VTypes;
if(!vt[this.vtype](value, this)){
this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
return false;
}
}
if(typeof this.validator == "function"){
var msg = this.validator(value);
if(msg !== true){
this.markInvalid(msg);
return false;
}
}
return true;
}
});



I've then tried setting the Invalid state of the control and then adding a listener for the click event:



var validateRegions = function()
{
if ( Ext.getCmp('regions').getValue() == "" )
{
return "You must select at least one region";
} else {
Ext.getCmp('regions').clearInvalid();
return true;
}
}

.....

Ext.getCmp('regions').markInvalid();
Ext.getCmp('regions').on('click', validateRegions);



...but the click event never fires - and I've tried changing it to a 'check' event. Still doesn't fire.

jsakalos
27 Apr 2009, 8:20 AM
Hmmm, I would choose a different route. CheckTreePanel (CTP) already has the concept of value so you can test if getValue() returns a non-empty array. If allowBlank would be false and the getValue() would return an empty array I'd marked the field (CTP) invalid.

Jangla
28 Apr 2009, 3:46 AM
Hmmm, I would choose a different route. CheckTreePanel (CTP) already has the concept of value so you can test if getValue() returns a non-empty array. If allowBlank would be false and the getValue() would return an empty array I'd marked the field (CTP) invalid.
Sorry but I don't understand. I already am looking at the value in the tree by using getValue(). The issue is that there is no click or check events on the tree so the function to mark it valid or invalid is inconsequential, regardless of whether I use getValue() or step through each individual checkbox.

jsakalos
28 Apr 2009, 6:23 AM
1. Navigate to http://checktree.extjs.eu/
2. Type in Firebug console: Ext.util.Observable.capture(Ext.getCmp('t2'),function(e){console.log(e);})
3. Play with upper-right checktree and watch Firebug Console pane.

mystix
28 Apr 2009, 6:26 AM
1. Navigate to http://checktree.extjs.eu/
2. Type in Firebug console: Ext.util.Observable.capture(Ext.getCmp('t2'),function(e){console.log(e);})
3. Play with upper-right checktree and watch Firebug Console pane.

tiny tip:
console.log is a function reference, so you could just do this:


Ext.util.Observable.capture(Ext.getCmp('t2'), console.log);

HTH ;)

jsakalos
28 Apr 2009, 6:43 AM
Yes, than it outputs all arguments that can be even more useful sometimes.

Thank you mystix.

Jangla
28 Apr 2009, 7:04 AM
AHA! So it's the click event for the node text and the checkchange event for the checkboxes. That at least sorts out one mystery! Now the tricky bit - working out why the markInvalid() doesn't do what it should i.e. prevent moving on to the next step of the wizard but I guess that's a question for the developer of that extension.

isoloist
3 Jun 2009, 1:44 AM
Is it possible to use the checkTreePanel in a form using AsyncTreeNode with a loader.

I test put loader:myloader but i get only the nodes that belong to the root node, when click to expand a node get nothing (loader is not calling at all).

Is it possible and i am doing something wrong or its not possible

Really great job

Thanks


comment these code in Ext.ux.tree.CheckTreePanel.js, you can find something different.
/*
if(true === this.loader.preloadChildren) {
this.loader.on('load', function(loader, node) {
node.cascade(function(n) {
loader.doPreload(n);
n.loaded = true;
});
});
}*/

jsakalos
3 Jun 2009, 1:48 AM
CheckTreePanel is designed for fully loaded trees. Of course, you can disable preloading but then you drop the original design idea so I don't know what it will do.

hypspecter
8 Jun 2009, 9:05 AM
Saki,
Hey, I used the CheckTreePanel and configured as needed. I don't get the checkboxes, just a tree. I am assuming that is because I don't have CheckTreePanel.css. Could you point me in the right direction?

jsakalos
8 Jun 2009, 11:19 AM
The file is in the download package. Make sure that you include it correctly.

allistar
8 Jun 2009, 4:06 PM
Hi there,
I need to know when an individual item has it's check changed. This event needs to take a couple of application specific parameters. No big deal - I just add a listener to the panel like this:



listeners: {'checkchange': triggerCheckTreePanelClicked.createDelegate(this, ['myvalue1','myvalue2'], true)}
Where my function is defined like this:



triggerCheckTreePanelClicked = function(treePanel, isChecked, myarg1, myarg2) {
console.log(myarg1 + ' ' + myarg2);
}
The problem is that "myarg1" and "myarg2" are always "undefined". I have debugged the "createDelegate" method and discovered that there are 4 additional unexplained arguments to the "checkchange" method. If I change my function to this:



triggerCheckTreePanelClicked = function(treePanel, isChecked, arg1, arg2, arg3, arg4, myarg1, myarg2) {
console.log(myarg1 + ' ' + myarg2);
}
It now receives my arguments as expected.

The question is: what are the additional 4 arguments for? I cannot find their origin in the source code anywhere, and the documentation doesn't reveal anything either.

jsakalos
8 Jun 2009, 11:55 PM
Hmmm, I do not add any extra arguments:



,onCheckChange:function() {
var checked = this.isChecked();
var tree = this.node.getOwnerTree();
var bubble = tree.bubbleCheck;
var cascade = tree.cascadeCheck;

if('all' === bubble || (checked && 'checked' === bubble) || (!checked && 'unchecked' === bubble)) {
this.updateParent(checked);
}
if('all' === cascade || (checked && 'checked' === cascade) || (!checked && 'unchecked' === cascade)) {
this.updateChildren(checked);
}

tree.updateHidden();
this.fireEvent('checkchange', this.node, checked);
} // eo function onCheckChange

allistar
9 Jun 2009, 12:13 AM
I know - which is why I'm confused. If you run this in firebug on the http://checktree.extjs.eu/ page you see the 4 additional "undefined" parameters to the event when you check on a check box in the top right example:


Ext.util.Observable.capture(Ext.getCmp('t2'), console.log);I have a good workaround for this (to add the 4 extra parameters to my delegate method) but I don't like unexplainable things like this. I'd rather know why. If I find the time I'll debug it further.

dbassett74
9 Jun 2009, 1:10 PM
Very cool, but usually the checkboxes are to the left of the icon in any tree that implements checkboxes. Can this be changed?

jsakalos
9 Jun 2009, 1:27 PM
You can modify TreeNodeUI to swap them.

allistar
9 Jun 2009, 1:36 PM
You can modify TreeNodeUI to swap them.

Yes, in particular the renderElements function. If the "buf" variable were to be returned by a method (maybe "getRenderFormat") then someone could extend TreeNodeUI and reimplement "getRenderFormat" to specify a different display format.

hypspecter
10 Jun 2009, 4:33 AM
I am not a css/html expert, but I have tried to remove the image for the tree node so that it doesn't show the folder or file icons. When I remove that src tag from buf it makes the tree only show the first value and the checkboxes don't work. Any help or explanation of the code as I would like to understand what the render is doing so I can modify it to do what I want.

jsakalos
10 Jun 2009, 8:10 AM
I haven't tried it myself so I also don't know, however, studying sources is always the best way to find out answers.

yuer2084
12 Jun 2009, 11:16 PM
/*
* Set nodes checked/unchecked
* @param {Mixed} val variable number of arguments, e.g. setValue('1,8,7', 3, [9,4])
* @return {Array} value. Array of checked nodes
*/

-----------------------------------
above is the setValue 's comments, I just want to know what 's the three params mean of '1,8,7',3,[9,4] ....

jsakalos
13 Jun 2009, 12:10 PM
It is example of all possible types. Nodes with ids 1, 8, 7, 3, 9 and 4 would be checked.

mholyszko
18 Jun 2009, 6:41 AM
Hi Saki,

You may want to take a look at this:



Index: Ext.ux.tree.CheckTreePanel.js
===================================================================
--- Ext.ux.tree.CheckTreePanel.js (revision 1937)
+++ Ext.ux.tree.CheckTreePanel.js (working copy)
@@ -452,19 +452,20 @@
// {{{
/**
* Called when check changes
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,onCheckChange:function() {
+ ,onCheckChange:function(callerNode) {
var checked = this.isChecked();
var tree = this.node.getOwnerTree();
var bubble = tree.bubbleCheck;
var cascade = tree.cascadeCheck;

if('all' === bubble || (checked && 'checked' === bubble) || (!checked && 'unchecked' === bubble)) {
- this.updateParent(checked);
+ this.updateParent(checked, callerNode);
}
if('all' === cascade || (checked && 'checked' === cascade) || (!checked && 'unchecked' === cascade)) {
- this.updateChildren(checked);
+ this.updateChildren(checked, callerNode);
}

tree.updateHidden();
@@ -475,16 +476,17 @@
/**
* Sets node UI checked/unchecked
* @param {Boolean} checked true to set node checked, false to uncheck
+ * @param {TreeNode} callerNode a node which requested the change
* @return {Boolean} checked
*/
- ,setChecked:function(checked) {
+ ,setChecked:function(checked, callerNode) {
checked = true === checked ? checked : false;
var cb = this.cbEl || false;
if(cb) {
true === checked ? cb.addClass('x-tree-node-checked') : cb.removeClass('x-tree-node-checked');
}
this.node.attributes.checked = checked;
- this.onCheckChange();
+ this.onCheckChange(callerNode);
return checked;
} // eo function setChecked
// }}}
@@ -503,14 +505,17 @@
/**
* Sets parents checked/unchecked. Used if bubbleCheck is not 'none'
* @param {Boolean} checked
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,updateParent:function(checked) {
+ ,updateParent:function(checked, callerNode) {
+ if(callerNode && this.node == callerNode) return;
+
var p = this.node.parentNode;
var ui = p ? p.getUI() : false;

if(ui && ui.setChecked) {
- ui.setChecked(checked);
+ ui.setChecked(checked, this.node);
}
} // eo function updateParent
// }}}
@@ -518,13 +523,16 @@
/**
* Sets children checked/unchecked. Used if cascadeCheck is not 'none'
* @param {Boolean} checked
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,updateChildren:function(checked) {
+ ,updateChildren:function(checked, callerNode) {
+ if(callerNode && this.node.childNodes.indexOf(callerNode) > -1) return;
+
this.node.eachChild(function(n) {
var ui = n.getUI();
if(ui && ui.setChecked) {
- ui.setChecked(checked);
+ ui.setChecked(checked, this.node);
}
});
} // eo function updateChildren
It should solve the problem of too much recursion with cascadeCheck: 'all' and bubbleCheck: 'all' setting (also with other combinations).

As usual, I'd like thank you a lot for your work. A developer's life would be much harder without your submissions ;)

Regards,
mh

jsakalos
18 Jun 2009, 9:01 AM
Perfect! I'll take a look soon, will let you know the result.

Thank you.

nintondo
25 Jul 2009, 9:33 AM
hi,
how do i checkall nodes on preload?

jsakalos
26 Jul 2009, 12:37 AM
You could iterate through nodes and set them checked. Most likely you would need to suppress events before the loop and resume them after the loop.

LupusC
30 Jul 2009, 11:32 PM
Hi,

Is it possible to use CTP with the 2.0.1 version of ext-js? It is not possible to upgrade to any other version because the online shop (xtCommerce veyton) I have to modify uses 2.0.1.

Sorry, if this is a noob question, but I am only for a short time with ext-js.

Many thaks in advance

jsakalos
31 Jul 2009, 12:05 AM
Try it - I've never tried myself.

Jangla
8 Oct 2009, 4:32 AM
I'm trying to use this extension in a wizard.

So far I've managed to get the tree populated with nodes from the database but there are a couple of issues.

Here's the set up script:



xtype : 'checktreepanel',
title : 'Countries/regions',
id : 'regions',
width:300,
height:250,
autoScroll:true,
rootVisible:false,
root : {
nodeType : 'async',
id : 'root',
text : 'root',
expanded : true,
uiProvider : false
},
dataUrl : 'index.php?eID=tx_supersearch_pi1&mode=getRegions'
}



The issues I've got are:
1. Despite setting rootVsisble: false, the root node is visible.
2. Despite setting expanded: true, the tree is not expanded.
3. There's no check boxes visible in the tree.

You can see the working version here: http://www.holiday-chateau.com/index.php?id=10790

Click the Availability Search tab and go to the next step in the wizard.

Apologies if it's a little slow - I intend to load the wizard only once the tab is selected in the final version, which should improve performance.

Any pointers greatly appreciated.

jsakalos
8 Oct 2009, 5:18 AM
1. Root is hidden at http://checktree.extjs.eu
1. Hidden root, if expanded, shows first level nodes - that is also used at the above demo page
3. Check Ext.BLANK_IMAGE_URL

Jangla
8 Oct 2009, 5:39 AM
Hi jsakalos. You'll notice from my code that I've copied the code from your demo page and it still doesn't work. Will check the image thing though - possible that will sort it...at least it will be one issue out the way :)

Edit: Blank image is fine. CMS was missing out the checktree css file which explains the missing check boxes but not the visible root node or unexpanded initial view issues.

Jangla
8 Oct 2009, 8:07 AM
I am not a css/html expert, but I have tried to remove the image for the tree node so that it doesn't show the folder or file icons. When I remove that src tag from buf it makes the tree only show the first value and the checkboxes don't work. Any help or explanation of the code as I would like to understand what the render is doing so I can modify it to do what I want.
This can be achived with simple css changes. Stick these in your page or find them in the main ext css file and update them (not the preferred option as it will change all instances):



.x-tree-node-expanded .x-tree-node-icon {
background-image:none;
}
.x-tree-node-collapsed .x-tree-node-icon {
background-image:none;
}
.x-tree-node-leaf .x-tree-node-icon {
background-image:none;
}
.x-tree-node-collapsed .x-tree-node-icon, .x-tree-node-expanded .x-tree-node-icon, .x-tree-node-leaf .x-tree-node-icon {
height:0;
width:0;
}

Jangla
9 Oct 2009, 2:27 AM
1. Root is hidden at http://checktree.extjs.eu
1. Hidden root, if expanded, shows first level nodes - that is also used at the above demo page
3. Check Ext.BLANK_IMAGE_URL

Just noticed something - on your exmaple page, the nodes are not expanded and the root is visible! At least that's what I get in FF 3.5, IE8 and Google Chrome - see the attachment.

Jangla
9 Oct 2009, 4:12 AM
Update: I've noticed that if the tree is inside a wizard which is in turn inside a window, the expand works and the hide root works. I'm using a wizard which is not inside a window and the two things don't work. Don't know how to solve it, but it's interesting :)

jsakalos
10 Oct 2009, 9:09 AM
That, what you see on the demo page is not root but first level child(ren).

Dustin Graham
12 Oct 2009, 7:32 PM
Thank you Saki for this awesome plugin.
Thanks to mholyszko for the contributions to reduce recursion.

I do have one problem. I am adding a listener to 'checkchanged' to update my datastore. However, when I use tree.setValue(...); it calls clear values, which in turn calls checkchanged. Which, updates the datastore, which then thinks it needs to call tree.setValue again.

I guess I figure that calling tree.setValue(); should not trigger 'checkchanged' but maybe it should. I suppose it would be okay to call checkchanged once on the final results, but, I think it's calling checkchanged on every single change made as it's clearing values, then resetting values.

Any thoughts on this?

Again, thanks Saki for all your awesome work.

jsakalos
13 Oct 2009, 1:01 AM
tree.suspendEvents();
tree.setValue();
tree.resumeEvents();

Jangla
13 Oct 2009, 5:20 AM
That, what you see on the demo page is not root but first level child(ren).

So could you theorise why, despite me using the same config settings as your demo, I don't see the same results?

Dustin Graham
13 Oct 2009, 8:21 AM
tree.suspendEvents();
tree.setValue();
tree.resumeEvents();


Ah, thanks. Cleaner than my solution. That works nicely.


@Jangla I am using a checked tree panel inside of a panel, that's inside a portlet, that's inside a portal column, that's inside a portal, that's inside a tab panel, that's inside a region panel that's inside a viewport, and it works fine. Maybe you have some id collisions or namespace collisions for the checkedtreepanel/wizard that's not in a window.

leolima
4 Dec 2009, 7:18 AM
Hi saki,

Did you fixed the too much recursion bug?
I´m trying to use your plugin, and my Tree have 107 nodes... and its getting too much recursion... how could I fix this ?

jsakalos
4 Dec 2009, 1:36 PM
Somebody has posted the fix a couple of posts back.

j0s3_r1v3r
21 Jan 2010, 2:36 PM
Hello everyone, I'm Ext user, so often follow the forum.
This is my first time and I may share features that you might be useful to someone.
I do not know if I did it the right way, I'm just a novice programming with Ext JS.



myClass = Ext.extend(Ext.ux.tree.CheckTreePanel, {
...
initComponent: function(config) {
...
this.eventModel.onCheckboxClick = this.eventModel.onCheckboxClick.createInterceptor(function (e, node) {
if(this.tree)
{
var nodes = this.tree.getChecked();
Ext.each(nodes, function(n,i,a) {
n.ui.onCheckboxClick();
}, this);
},

reset: function () {
Ext.each(this.getChecked(), function(n,i,a) {
n.ui.onCheckboxClick();
}, this);
}
...
});


Adds createInterceptor to onCheckboxClick event, to allow select single node and add reset function, to runs form.reset(), uncheck all nodes.

Sorry for my english.

jsakalos
21 Jan 2010, 2:52 PM
Hmmm, reset shouldn't clear the form - it should revert it back to the original values. That what should uncheck the checkboxes is clearValue. clearValue is already there, implementing reset shouldn't be that difficult.

j0s3_r1v3r
21 Jan 2010, 3:14 PM
Oh, ok, I modify



reset: function() {
this.clearValue();
}


thanks

I have



myForm = Ext.extend(Ext.form.FormPanel, {
...
initComponent: function (config) {
...
items: [{
...
},{
xtype: 'myCheckTreePanel'
}],
buttons: [{
...
},{
text:'clear',
handler: function (){ this.getForm().reset(); }
}]
}
});

when clicked the clear button, I get the error attached
Then add the reset method to myCheckTreePanel (CheckTreePanel), and it worked.

Allbus
3 Feb 2010, 8:04 AM
Hello everyone,

How can I specify that one or more nodes aren't checkbox ??

I need a tree where not all nodes are checkboxes.

Thanks

jsakalos
5 Feb 2010, 12:11 PM
That is not implemented. You'd need to use traditional TreeNodeUI for the nodes w/o checkbox.

Jangla
11 Feb 2010, 7:42 AM
That, what you see on the demo page is not root but first level child(ren).
Been a while since I've been in this thread (been on other projects) but the issue still remains - the expanded config option doesn't appear to do anything.

On your site, jsakalos, all the trees have expanded set to true but none of the trees are. Same with my testing - setting expanded to true doesn't seem to affect the trees at all.

jsakalos
11 Feb 2010, 1:21 PM
What do you mean exactly? expanded is property of tree node, where/how/when do you set expanded property.

http://www.extjs.com/deploy/dev/docs/?class=Ext.tree.TreeNode&member=expanded

Jangla
12 Feb 2010, 1:19 AM
Bear in mind I'm loading my tree via MetaForm and asynchronously (has to be that way as depending on the dataURL, the nodes will differ), here's the setup:



xtype:checktreepanel,
title:Regions,
id:regions,
msgTarget:region-error,
deepestOnly:true,
width:245,
height:250,
autoScroll:true,
rootVisible:false,
root:[{
nodeType:async,
id:root,
text:root,
expanded:true,
useArrows:true,
uiProvider:false
}],
dataUrl:/pm-search/PM-PortalRegionTree.aspx?pid=123


I guess I may be wrong in my assumption of what "expanded" does - I was hoping it expanded all nodes.....

jsakalos
12 Feb 2010, 3:24 AM
The config above means only expand root, not expand all.

Jangla
12 Feb 2010, 3:27 AM
Ah I see. I presume I therefore need to expand programmatically?

jsakalos
12 Feb 2010, 3:15 PM
Try to return expanded:true as a part of children definitions, however, I haven't tested it.

jsakalos
4 Apr 2010, 10:29 AM
Hello mholyszko,

not that soon, nevertheless, I've tested your patch and it works as expected. I'll incorporate it to the next release of CheckTreePanel.

Thank you.


Hi Saki,

You may want to take a look at this:



Index: Ext.ux.tree.CheckTreePanel.js
===================================================================
--- Ext.ux.tree.CheckTreePanel.js (revision 1937)
+++ Ext.ux.tree.CheckTreePanel.js (working copy)
@@ -452,19 +452,20 @@
// {{{
/**
* Called when check changes
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,onCheckChange:function() {
+ ,onCheckChange:function(callerNode) {
var checked = this.isChecked();
var tree = this.node.getOwnerTree();
var bubble = tree.bubbleCheck;
var cascade = tree.cascadeCheck;

if('all' === bubble || (checked && 'checked' === bubble) || (!checked && 'unchecked' === bubble)) {
- this.updateParent(checked);
+ this.updateParent(checked, callerNode);
}
if('all' === cascade || (checked && 'checked' === cascade) || (!checked && 'unchecked' === cascade)) {
- this.updateChildren(checked);
+ this.updateChildren(checked, callerNode);
}

tree.updateHidden();
@@ -475,16 +476,17 @@
/**
* Sets node UI checked/unchecked
* @param {Boolean} checked true to set node checked, false to uncheck
+ * @param {TreeNode} callerNode a node which requested the change
* @return {Boolean} checked
*/
- ,setChecked:function(checked) {
+ ,setChecked:function(checked, callerNode) {
checked = true === checked ? checked : false;
var cb = this.cbEl || false;
if(cb) {
true === checked ? cb.addClass('x-tree-node-checked') : cb.removeClass('x-tree-node-checked');
}
this.node.attributes.checked = checked;
- this.onCheckChange();
+ this.onCheckChange(callerNode);
return checked;
} // eo function setChecked
// }}}
@@ -503,14 +505,17 @@
/**
* Sets parents checked/unchecked. Used if bubbleCheck is not 'none'
* @param {Boolean} checked
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,updateParent:function(checked) {
+ ,updateParent:function(checked, callerNode) {
+ if(callerNode && this.node == callerNode) return;
+
var p = this.node.parentNode;
var ui = p ? p.getUI() : false;

if(ui && ui.setChecked) {
- ui.setChecked(checked);
+ ui.setChecked(checked, this.node);
}
} // eo function updateParent
// }}}
@@ -518,13 +523,16 @@
/**
* Sets children checked/unchecked. Used if cascadeCheck is not 'none'
* @param {Boolean} checked
+ * @param {TreeNode} callerNode a node which requested the change
* @private
*/
- ,updateChildren:function(checked) {
+ ,updateChildren:function(checked, callerNode) {
+ if(callerNode && this.node.childNodes.indexOf(callerNode) > -1) return;
+
this.node.eachChild(function(n) {
var ui = n.getUI();
if(ui && ui.setChecked) {
- ui.setChecked(checked);
+ ui.setChecked(checked, this.node);
}
});
} // eo function updateChildren
It should solve the problem of too much recursion with cascadeCheck: 'all' and bubbleCheck: 'all' setting (also with other combinations).

As usual, I'd like thank you a lot for your work. A developer's life would be much harder without your submissions ;)

Regards,
mh

ldonofrio
3 Aug 2010, 2:04 PM
If you are using this as formfield and want initial load data accesible via getValue() you can use this override


Ext.override(Ext.ux.tree.CheckTreePanel, {
initComponent: function() {
// use our event model
this.eventModel = new Ext.ux.tree.CheckTreeEventModel(this);
// call parent initComponent
Ext.ux.tree.CheckTreePanel.superclass.initComponent.apply(this, arguments);
// pass this.baseAttrs and uiProvider down the line
var baseAttrs = Ext.apply({uiProvider:Ext.ux.tree.CheckTreeNodeUI}, this.baseAttrs);
Ext.applyIf(this.loader, {baseAttrs:baseAttrs, preloadChildren:true});
// make sure that nodes are deeply preloaded
if(true === this.loader.preloadChildren) {
this.loader.on('load', function(loader, node) {
node.cascade(function(n) {
loader.doPreload(n);
n.loaded = true;
});
this.updateHidden();
}, this);
}
// create tree filter
if(true === this.filter) {
var Filter = Ext.ux.tree.TreeFilterX ? Ext.ux.tree.TreeFilterX : Ext.tree.TreeFilter;
this.filter = new Filter(this, {autoClear:true});
}
}
});

scgrif32
27 Sep 2010, 4:25 PM
I would like to first say this is an excellent extension to the treePanel. I downloaded the source files and found I am missing a lot of icons as well as the PHP script that would generate the Json to be sent back to the 4 examples you are using on the checktree.html page.

Can you help me with getting these missing files so I can have a working example running on my local development environment?

Thank you,

Shawn

jsakalos
27 Sep 2010, 5:09 PM
I cannot pack mime icons (file type icons) with the bundle as they are from the various sources, some free, some proprietary and some - well, I don't know.

You could take your OS file type icons and use them together with filetype.css - you must modify this file for your icons. (Note: I'm not sure if using OS icons for this purpose is not a violation of the license agreement - check it yourself.

Another option would be to search internet and find some free mime icon pack, something like famfamfam for general purpose. (If you find one, let me know.)

scgrif32
27 Sep 2010, 7:33 PM
Well,

I was hoping to use your extension for my application but I should probably ask you does your extension fall under the same licensing conditions as Ext Js? If so, I will have to look for icons if I can use it in our licensed application and go from there.

If your answer is "yes" to the licensing then I would like to ask of your assistance because I will be needing help making a few modifications to this extension to suite our needs in a short window of time. Would you be able to assist if questions arrive during development?

Thanks,

Shawn

jsakalos
28 Sep 2010, 2:32 AM
The extension license is LGPL, that is more permissive than GPL. An assistance is possible if you're willing to pay its time (contact me on skype for further discussion on this matter).

scgrif32
28 Sep 2010, 7:47 AM
Alright,

I have it working and didn't need any additional icons to do so. All I had to do was change the path to the "checkbox.gif" in the "Ext.ux.tree.CheckTreePanel.css" file.

However, I am curious about why so many other .js & .css files were included in the .zip file? Don't I only need "Ext.ux.tree.CheckTreePanel.css" and "Ext.ux.tree.CheckTreePanel.js" files to use the CheckTreePanel? I shouldn't need additional files to use the following config options (bubbleCheck & cascadeCheck) as well, right?

What are the following (Ext.ux.tree.TreeFilterX.js & Ext.ux.menu.IconMenu.js) files used for?

What I would like to know now is how to collect the values for each checked option & how to group the parent/child relationship before sending to the server?

Thanks,

Shawn

jsakalos
28 Sep 2010, 12:11 PM
That would tell you nothing as it is only a proxy to the larger (proprietary) server-side tree library. If you need a read-only tree it is enough if you return tree nodes json exactly as in any other tree server script.

csupa
5 Oct 2010, 1:37 PM
Hi Saki,

Can I mark some items as checked at load? I use your plug-in in a form and i'd like to edit the db, so it would be nice to mark the previously checked items as checked at the load of CheckTreePanel.

Thank You,
Csupa

jsakalos
5 Oct 2010, 3:11 PM
Yes. See http://examples.extjs.eu/?ex=treeinform

dotnetwise
10 Mar 2011, 3:04 AM
Hey guys, on IE9 RC the Ext.ux.tree.CheckTreePanel doesn't do anything whatsoever when you click on any node whether you want expand or check them.

Other than Microsoft throwing a new junk on the market all other browsers including older IE7/8, FF3.6/4 beta and Chrome 9/10 beta are working well.

Any patches?

If you go with IE9 on http://checktree.extjs.eu/ a javascript error will be thrown when you even hover it. Strangely it doesn't throw up on my IE9.

Line: 36546
Error: Unable to get value of the property 'ui': object is null or undefined

jsakalos
10 Mar 2011, 6:35 AM
Try now.

dotnetwise
10 Mar 2011, 6:46 AM
Try now.
No error but still no "click" support.
Even weird I can drag but I can't click to expand/check.

http://screencast.com/t/HAWp43bKwq

I'm on a Windows 2008 R2 Server with SP1 virtual machine and IE9 Beta installed.
The screencast is under remote desktop but that should not matter as long as all other browsers are working correct, even IE7/IE8 but IE9.

jsakalos
10 Mar 2011, 7:46 AM
It's all about Browser Mode and Document Mode - I'm totally confused as to what M$ meant by that. It works fine in Browser Mode: IE9 and Document Mode: IE8 Standards. That is what I'm trying to force by


<meta http-equiv="X-UA-Compatible" content="IE=8" >

Biohazard
4 Aug 2011, 11:28 PM
Hi, this error maybe is caused by the new microsoft trend for IE9 to follow only standard functions, standard tags and it's not the only one. Forcing to IE8 compatibility it's a workaround, and it works, but isn't possible to do a fix for this issue?

Thanks!

lenoil
23 Oct 2011, 11:54 PM
Hi ,

I would like implemented markInvalid et and clearInvalid on the checkTreePanel, to show to the users
that it must check at least a value ...
Does someone already implement this function ?

Actually, I have



,clearInvalid:Ext.emptyFn
,markInvalid:Ext.emptyFn



Thanks you very much

Deniplane
21 Nov 2011, 8:40 AM
I have just the same error. But it was not with the checkTreePanel event. It was happened when the mouse pointer was over the tree note. This issue was reproduced with Browser mode: IE9 and Document mode: IE9 standards. I used ExtJs 3.4. There are some reasons, that I can't use the IE8 in the document mode and new ExtJs 4.0. Did you bring this issue to a close? If yes, please, let me know how you could do it. I will appreciate any help. Thank you.