-
16 Oct 2008 11:10 PM #1
Radio support to tree probleam
Radio support to tree probleam
I add my owne radio/checkbox support to tree.For checkbox it works fine.But when I click a radio it can't be check[checked
and then unchecked by some code I dont know where it is]
The class:[I use extjs version 2.0.2]
Code:/** * @class Ext.ux.TreeNodeRichUI * @extends Ext.tree.TreeNodeUI * * 对 Ext.tree.TreeNodeUI 进行checkbox功能的扩展,后台返回的结点信息不用非要包含checked属性 * * 扩展的功能点有: * 一、支持只对树的叶子进行选择 * 只有当返回的树结点属性leaf = true 时,结点才有checkbox可选 * 使用时,只需在声明树时,加上属性 onlyLeafCheckable: true 既可,默认是false * * 二、支持对树的单选 * 只允许选择一个结点 * 使用时,只需在声明树时,加上属性 checkModel: "radio" 既可 * * 二、支持对树的级联多选 去掉了 * 当选择结点时,自动选择该结点下的所有子结点,或该结点的所有父结点(根结点除外),特别是支持异步,当子结点还没显示时,会从后台取得子结点,然后将其选中/取消选中 * 使用时,只需在声明树时,加上属性 checkModel: "cascade" 或"parentCascade"或"childCascade"既可 * * 三、添加"check"事件 * 该事件会在树结点的checkbox发生改变时触发 * 使用时,只需给树注册事件,如: * tree.on("check",function(node,checked){...}); * * 四、添加"beforeCheck"事件 * 该事件在树节点的checkbox发生改变前触发,如果该事件返回false,则check事件被终止 * * 默认情况下,checkModel为'checkbox',也就是多选,onlyLeafCheckable为false,所有结点都可选 * * 使用方法:在loader里加上 baseAttrs:{uiProvider:Ext.ux.TreeNodeRichUI} 既可. * 例如: * var tree = new Ext.tree.TreePanel({ * el:'tree-ct', * width:568, * height:300, * checkModel: 'cascade', //对树的级联多选 * onlyLeafCheckable: false,//对树所有结点都可选 * animate: false, * rootVisible: false, * autoScroll:true, * loader: new Ext.tree.DWRTreeLoader({ * dwrCall:Tmplt.getTmpltTree, * baseAttrs: { uiProvider: Ext.ux.TreeNodeRichUI } //添加 uiProvider 属性 * }), * root: new Ext.tree.AsyncTreeNode({ id:'0' }) * }); * tree.on("check",function(node,checked){alert(node.text+" = "+checked)}); //注册"check"事件 * tree.render(); * */ Ext.namespace("Ext.ux"); Ext.ux.TreeNodeRichUI = function() { //checkbox:多选框(默认) //radio:单选框 //none:没有选择框 this.checkModel = 'checkbox'; //only leaf can checked this.onlyLeafCheckable = false; //如果是checkbox,双击时是否触发check事件 this.checkedOnDblClick = false; Ext.ux.TreeNodeRichUI.superclass.constructor.apply(this, arguments); }; Ext.extend(Ext.ux.TreeNodeRichUI, Ext.tree.TreeNodeUI, { renderElements : function(n, a, targetNode, bulkRender) { var tree = n.getOwnerTree(); this.checkModel = tree.checkModel || this.checkModel; this.onlyLeafCheckable = tree.onlyLeafCheckable || false; this.checkedOnDblClick = tree.checkedOnDblClick || false; // add some indent caching, this helps performance when rendering a large tree this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : ''; //var cb = typeof a.checked == 'boolean'; var cb = (this.checkModel != "none")&&(!this.onlyLeafCheckable || a.leaf); var radioType = cb ? (this.checkModel == 'radio' ? true : false) : ''; var inputName; if (radioType) { if (!tree.inputName) { inputName = Ext.id(); tree.inputName = inputName; } else inputName = tree.inputName; } var href = a.href ? a.href : Ext.isGecko ? "" : "#"; var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">', '<span class="x-tree-node-indent">',this.indentMarkup,"</span>", '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />', '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " " + a.iconCls : ""),'" unselectable="on" />', cb ? (radioType ? '<input class="x-tree-node-cb" type="radio" name="' + inputName + '" ' : '<input class="x-tree-node-cb" type="checkbox" ') + (a.checked ? 'checked="checked" />' : '/>') : '', '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ', a.hrefTarget ? ' target="' + a.hrefTarget + '"' : "", '><span unselectable="on">',n.text,"</span></a></div>", '<ul class="x-tree-node-ct" style="display:none;"></ul>', "</li>"].join(''); var nel; if (bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())) { this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf); } else { this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf); } this.elNode = this.wrap.childNodes[0]; this.ctNode = this.wrap.childNodes[1]; var cs = this.elNode.childNodes; this.indentNode = cs[0]; this.ecNode = cs[1]; this.iconNode = cs[2]; var index = 3; if (cb) { this.checkbox = cs[3]; Ext.fly(this.checkbox).on('click', this.checkboxclick.createDelegate(this, [null])); index++; } this.anchor = cs[index]; this.textNode = cs[index].firstChild; }, onDblClick : function(e) { e.preventDefault(); if (this.disabled) { return; } if (this.checkbox && this.checkedOnDblClick) { if (this.checkModel == "checkbox") this.toggleCheck(); else { this.check(true); } } if (!this.animating && this.node.hasChildNodes()) { this.node.toggle(); } this.fireEvent("dblclick", this.node, e); }, checkboxclick:function() { if (this.checkModel == "radio") this.check(true); else this.check(null); }, // private check : function(checked) { var n = this.node; var tree = n.getOwnerTree(); this.checkModel = tree.checkModel || this.checkModel; if (checked === null) { checked = this.checkbox.checked; } else { this.checkbox.checked = checked; } /*if (tree.fireEvent("beforecheck", n, checked) === false) { this.checkbox.checked = !checked; n.attributes.checked = !checked; return; }*/ n.attributes.checked = checked; tree.fireEvent('check', n, checked); /** * todo:重构以下代码 * 是否级联选择应当放在业务代码中控制,否则有很多弊端 * eg.我点击节点时要和用户交互一下,但是点击后有级联的时候不应该发生这个交互, * 如果级联操作放在这里要屏蔽交互就显得相当棘手。 * 所以checkModel换成三个属性:none,radiobox,checkbox */ /*if (this.checkModel == 'single') { var checkedNodes = tree.getChecked(); for (var i = 0; i < checkedNodes.length; i++) { var node = checkedNodes[i]; if (node.id != n.id) { node.getUI().checkbox.checked = false; node.attributes.checked = false; tree.fireEvent('check', node, false); } } } else if (!this.onlyLeafCheckable) { if (this.checkModel == 'cascade' || this.checkModel == 'parentCascade') { var parentNode = n.parentNode; if (parentNode !== null) { this.parentCheck(parentNode, checked); } } if (this.checkModel == 'cascade' || this.checkModel == 'childCascade') { if (!n.expanded && !n.childrenRendered) { n.expand(false, this.animate, this.childCheck); } else { this.childCheck(n); } } if (this.checkModel == 'leafCascade') { if (!n.expanded && !n.childrenRendered) { n.expand(false, this.animate, this.leafCheck); } else { this.leafCheck(n); var parentNode = n.parentNode; if (parentNode !== null) { this.parentCheck(parentNode, checked); } } } }*/ }, childCheck : function(node) { var a = node.attributes; var t = node.getOwnerTree(); if (!a.leaf) { var cs = node.childNodes; var csui; for (var i = 0; i < cs.length; i++) { csui = cs[i].getUI(); if (csui.checkbox.checked ^ a.checked) { csui.check(a.checked); } } } }, leafCheck : function(node) { var a = node.attributes; if (!a.leaf) { var cs = node.childNodes; var csui; for (var i = 0; i < cs.length; i++) { if (cs[i].leaf) { csui = cs[i].getUI(); if (csui.checkbox.checked ^ a.checked) csui.check(a.checked); } } } }, // private parentCheck : function(node, checked) { var checkbox = node.getUI().checkbox; if (typeof checkbox == 'undefined')return; if (!(checked ^ checkbox.checked))return; if (!checked && this.childHasChecked(node))return; checkbox.checked = checked; node.attributes.checked = checked; node.getOwnerTree().fireEvent('check', node, checked); var parentNode = node.parentNode; if (parentNode !== null) { this.parentCheck(parentNode, checked); } }, // private childHasChecked : function(node) { var childNodes = node.childNodes; if (childNodes || childNodes.length > 0) { for (var i = 0; i < childNodes.length; i++) { if (childNodes[i].getUI().checkbox.checked) return true; } } return false; }, toggleCheck : function(value) { var cb = this.checkbox; if (cb) { var checked = (value === undefined ? !cb.checked : value); this.check(checked); } } }); /** * @class Ext.tree.RootTreeNodeUI * */ Ext.tree.RootTreeNodeRichUI = Ext.extend(Ext.tree.TreeNodeRichUI, { // private render : function(){ if(!this.rendered){ var targetNode = this.node.ownerTree.innerCt.dom; this.node.expanded = true; targetNode.innerHTML = '<div class="x-tree-root-node"></div>'; this.wrap = this.ctNode = targetNode.firstChild; } }, collapse : Ext.emptyFn, expand : Ext.emptyFn });
-
17 Oct 2008 4:11 AM #2
-
17 Oct 2008 7:10 AM #3
look at this demo:
http://125.78.107.142/ext/examples/tree/reorder.html
The first check is fine,and then not.
After debug I found that after these codes executed the radio status was reset:
OKCode:/** * These codes come from ext-base.js */ var wrappedFn = function(e) { return typeof Ext != 'undefined' ? fn(Ext.lib.Event.getEvent(e)) : false; };
I change the above code to these:
Code:var wrappedFn = function(e) { if(e.target.type=='radio') return true; return typeof Ext != 'undefined' ? fn(Ext.lib.Event.getEvent(e)) : false; };OO.It doesnot work in IE7 and can checked in IE6 and Firefox but the check event registerd to it not work.Now,it works fine.But I don't know why.Who can explain it for me?Please.
-
17 Oct 2008 7:28 PM #4
-
18 Oct 2008 6:19 PM #5
Resolved!
Resolved!
After hard debug,I resolved the problem.
It's the TreeEventModel,which just register delegate for checkbox's click event except radio.So add this code to the js then it works fine:
Code:Ext.tree.TreeEventModel.prototype.delegateClick=function(e,t){ //......Same as the original if (e.getTarget("input[type=checkbox]",1)||e.getTarget("input[type=radio]",1)) { this.onCheckboxClick(e, this.getNode(e)) } //......Same as the original }
-
18 Oct 2008 7:31 PM #6Ext User
- Join Date
- Sep 2008
- Location
- zisha cun no.4 at china GD GZ Panyu Lanhe
- Posts
- 3
- Vote Rating
- 0
this message by china中国人支持你!!!
-
18 Oct 2008 7:34 PM #7sexy22Guest
我是新手。。。。。先顶你。。再说。。

-
18 Oct 2008 8:31 PM #8
I am a Chinese!
I will post the whole code later.This extension support radio and checkbox perfect.And have some extra properties usefully.Hope it is helpful,and feel free for giving you suggest to make it better.
-
10 Jan 2009 2:47 PM #9
thanx for the great work
I know it is a little bit late to post in the thread, but would u please provide your full code ?
Thanx in advance
-
11 Jan 2009 6:19 PM #10
Here is it
Here is it
Code:/** * @author Vincent Chan * */ Ext.namespace("Ext.ux"); //TreeEventModel仅仅对checkbox进行了处理,这里进行修正,加上radio的事件处理 //Fix the TreeEventModel.Add delegate on radio click event. Ext.tree.TreeEventModel.prototype.delegateClick = function(e, t){ if(!this.beforeEvent(e)){ return; } if(e.getTarget('input[type=checkbox]', 1)||e.getTarget('input[type=radio]', 1)){ this.onCheckboxClick(e, this.getNode(e)); } else if(e.getTarget('.x-tree-ec-icon', 1)){ this.onIconClick(e, this.getNode(e)); } else if(this.getNodeTarget(e)){ this.onNodeClick(e, this.getNode(e)); } }; /** * @class Ext.ux.TreeNodeRichUI * @extends Ext.tree.TreeNodeUI * * 对 Ext.tree.TreeNodeUI 进行checkbox功能的扩展,后台返回的结点信息不用非要包含checked属性 * * 扩展的功能点有: * 一、支持只对树的叶子进行选择 * 只有当返回的树结点属性leaf = true 时,结点才有checkbox可选 * 使用时,只需在声明树时,加上属性 onlyLeafCheckable: true 既可,默认是false * * 二、对checkbox扩展 * 增加属性checkModel,有三个可选值:checkbox,radio,none,默认checkbox * 使用时,只需在声明树时,加上属性 checkModel: "radio"/"checkbox"/"none" 既可 * * * 三、添加"check"事件 * 该事件会在树结点的checkbox发生改变时触发 * 使用时,只需给树注册事件,如: * tree.on("check",function(node,checked){...}); * * 四、添加"beforecheck"事件 * 该事件在树节点的checkbox发生改变前触发,如果该事件返回false,则check事件被终止, * 注意该事件其实是在checkbox/radio点击后但是相关属性还没修改前触发,只是一个模拟 * * 五、增加属性checkOnDblClick * Ext默认双击进行check操作。这里添加这个属性可以灵活选择 * * 使用方法:在loader里加上 baseAttrs:{uiProvider:Ext.ux.TreeNodeRichUI} 既可. * 例如: * var tree = new Ext.tree.TreePanel({ * el:'tree-ct', * width:568, * height:300, * checkModel: 'checkbox', * onlyLeafCheckable: false, * checkOnDblClick:false, * animate: false, * rootVisible: false, * autoScroll:true, * loader: new Ext.tree.DWRTreeLoader({ * dwrCall:Tmplt.getTmpltTree, * baseAttrs: { uiProvider: Ext.ux.TreeNodeRichUI } //添加 uiProvider 属性 * baseParams:{}//options * }), * root: new Ext.tree.AsyncTreeNode({ id:'0' }) * }); * tree.on("check",function(node,checked){alert(node.text+" = "+checked?" check ":" uncheck ")}); //注册"check"事件 * tree.on("beforecheck",function(node,checked){ * if(confirm("Do you want to "+checked?" check ":" uncheck " +node.text)) * return true; * esle return false; * }); //注册"beforecheck"事件 * tree.render(); * */ /** * * @class Ext.ux.TreeNodeRichUI * @extends Ext.tree.TreeNodeUI * * Extend the Ext.tree.TreeNodeUI.Add fully support for checkbox and radio. * * Note:Be careful,this would drop the checked of the node. * * 1. Add checkModel config option to TreePanel.It's value should be one of below: * 1)none. The tree will act as no checkbox/radio tree as origial model[without checkbox]. * 2)radio. Add radio to the tree. * 3)checkbox. Add checkbox to the tree. * It is the default value if the treepanel not got checkModel config. * * 2. Add onlyLeafCheckable config option to TreePanel. * If it is true,only add checkbox/radio to leaf node. * * 3. Add checkedOnDblClick config option to TreePanel. * An option to let you decide if it should be checked when dblclick on the node.Default value is false. * * 4. Add check and beforecheck event on the checkbox/radio. * So you can do something after check,or give the user a confirm before check. * As you would be attention,is not a really beforecheck.But it act like a before check. * You can just return false to avoid the check. * * 5. An addition cheable option to TreeNode. * This is just effective when the checkModel is set to radio/checkbox. * And it have the highest priority to decide if should place a radio/checkbox to the tree. * */ Ext.ux.TreeNodeRichUI = function() { //checkbox:多选框(默认) //radio:单选框 //none:没有选择框 this.checkModel = 'checkbox'; //only leaf can checked this.onlyLeafCheckable = false; //如果是checkbox,双击时是否触发check事件 this.checkedOnDblClick = false; Ext.ux.TreeNodeRichUI.superclass.constructor.apply(this, arguments); }; Ext.extend(Ext.ux.TreeNodeRichUI, Ext.tree.TreeNodeUI, { renderElements : function(n, a, targetNode, bulkRender) { var tree = n.getOwnerTree(); this.checkModel = tree.checkModel || this.checkModel; this.onlyLeafCheckable = tree.onlyLeafCheckable || false; this.checkedOnDblClick = tree.checkedOnDblClick || false; // add some indent caching, this helps performance when rendering a large tree this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : ''; /** * Checkout if should render a radio/checkbox to this node. * Add a attribute "checkable" to treenode. * If it is set,it has highest priority to decide if should place a radio/checkbox to the node. * This is useful if you've got a radio/checkbox tree * but you want some nodes(leaf or not) have not radio/checkbox. * If it is not set,it will be not effective. */ var cb = (this.checkModel != "none") && (!this.onlyLeafCheckable || a.leaf)&& (typeof n.attributes.checkable!='boolean'||n.attributes.checkable); var radioType = cb ? (this.checkModel == 'radio' ? true : false) : ''; var inputName; if (radioType) { if (!tree.inputName) { inputName = Ext.id(); tree.inputName = inputName; } else inputName = tree.inputName; } var href = a.href ? a.href : Ext.isGecko ? "" : "#"; var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">', '<span class="x-tree-node-indent">',this.indentMarkup,"</span>", '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />', '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " " + a.iconCls : ""),'" unselectable="on" />', cb ? (radioType ? '<input class="x-tree-node-cb" type="radio" name="' + inputName + '" ' : '<input class="x-tree-node-cb" type="checkbox" ') + (a.checked ? 'checked="checked" />' : '/>') : '', '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ', a.hrefTarget ? ' target="' + a.hrefTarget + '"' : "", '><span unselectable="on">',n.text,"</span></a></div>", '<ul class="x-tree-node-ct" style="display:none;"></ul>', "</li>"].join(''); var nel; if (bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())) { this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf); } else { this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf); } this.elNode = this.wrap.childNodes[0]; this.ctNode = this.wrap.childNodes[1]; var cs = this.elNode.childNodes; this.indentNode = cs[0]; this.ecNode = cs[1]; this.iconNode = cs[2]; var index = 3; if (cb) { this.checkbox = cs[3]; Ext.fly(this.checkbox).on('click', this.check.createDelegate(this, [null])); index++; } this.anchor = cs[index]; this.textNode = cs[index].firstChild; }, // private onDblClick : function(e) { e.preventDefault(); if (this.disabled) { return; } if (this.checkbox && this.checkedOnDblClick) { //this make the radio act as a radio if (this.checkModel == "checkbox") this.toggleCheck(); else { this.check(true); } } if (!this.animating && this.node.hasChildNodes()) { this.node.toggle(); } this.fireEvent("dblclick", this.node, e); }, // private check : function(checked) { var n = this.node; var tree = n.getOwnerTree(); this.checkModel = tree.checkModel || this.checkModel; if (checked === null) { checked = this.checkbox.checked; } else { this.checkbox.checked = checked; } if (tree.fireEvent("beforecheck", n, checked) === false) { this.checkbox.checked = !checked; n.attributes.checked = !checked; return; } n.attributes.checked = checked; tree.fireEvent('check', n, checked); }, toggleCheck : function(value) { var cb = this.checkbox; if (cb) { var checked = (value === undefined ? !cb.checked : value); this.check(checked); } } });


Reply With Quote

welcome to everyone