Arbor Js - Node Onclick? - javascript
I'm using arbor.js to create a graph.
How do I create an onclick event for a node, or make a node link somewhere upon being clicked?
The Arborjs.org homepage has nodes which link to external pages upon being clicked, how do I replicate this, or make the node call javascript function upon being clicked?
My current node and edges listing is in this format:
var data = {
nodes:{
threadstarter:{'color':'red','shape':'dot','label':'Animals'},
reply1:{'color':'green','shape':'dot','label':'dog'},
reply2:{'color':'blue','shape':'dot','label':'cat'}
},
edges:{
threadstarter:{ reply1:{}, reply2:{} }
}
};
sys.graft(data);
A bit of context:
I'm using arbor.js to create a graph of thread starters and replies on my forum.
I've got it working so that id's are displayed 'in orbit' around their respective thread starter.
The reference on the arbor site is really not very helpful.
Any help is much appreciated.
If you look at the atlas demo code (in github) you will see towards the bottom there are a selection of mouse event functions, if you look at:
$(canvas).mousedown(function(e){
var pos = $(this).offset();
var p = {x:e.pageX-pos.left, y:e.pageY-pos.top}
selected = nearest = dragged = particleSystem.nearest(p);
if (selected.node !== null){
// dragged.node.tempMass = 10000
dragged.node.fixed = true;
}
return false;
});
This is being used to control the default node "dragging" functionality. In here you can trigger the link you want.
I would add the link URL to the node json that you are passing back to define each node, so your original JSON posted becomes something like:
nodes:{
threadstarter:{'color':'red','shape':'dot','label':'Animals'},
reply1:{'color':'green','shape':'dot','label':'dog', link:'http://stackoverflow.com'},
reply2:{'color':'blue','shape':'dot','label':'cat', link:'http://stackoverflow.com'}
},
Then, you can update the mouseDown method to trigger the link (the current node in the mouse down method is "selected" so you can pull out the link like selected.node.data.link
If you look at the original source for the arbor site to see how they have done it, they have a clicked function that is called on mouseDown event and then essentially does:
$(that).trigger({type:"navigate", path:selected.node.data.link})
(edited for your purposes)
It is worth noting that whilst the Arbor framework and demos are open for use, their site isnt and is actually copyrighted, so only read that to see how they have done it, dont copy it ;)
With the above solutions (including the one implemented at www.arborjs.org) although nodes can open links when clicked, they also lose their ability to be dragged.
Based on a this question, that discusses how to distinguish between dragging and clicking events in JS, I wrote the following:
initMouseHandling:function(){
// no-nonsense drag and drop (thanks springy.js)
selected = null;
nearest = null;
var dragged = null;
var oldmass = 1
var mouse_is_down = false;
var mouse_is_moving = false
// set up a handler object that will initially listen for mousedowns then
// for moves and mouseups while dragging
var handler = {
mousemove:function(e){
if(!mouse_is_down){
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
nearest = particleSystem.nearest(_mouseP);
if (!nearest.node) return false
selected = (nearest.distance < 50) ? nearest : null
if(selected && selected.node.data.link){
dom.addClass('linkable')
} else {
dom.removeClass('linkable')
}
}
return false
},
clicked:function(e){
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
nearest = particleSystem.nearest(_mouseP);
if (!nearest.node) return false
selected = (nearest.distance < 50) ? nearest : null
if (nearest && selected && nearest.node===selected.node){
var link = selected.node.data.link
if (link.match(/^#/)){
$(that).trigger({type:"navigate", path:link.substr(1)})
}else{
window.open(link, "_blank")
}
return false
}
},
mousedown:function(e){
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
selected = nearest = dragged = particleSystem.nearest(_mouseP);
if (dragged.node !== null) dragged.node.fixed = true
mouse_is_down = true
mouse_is_moving = false
$(canvas).bind('mousemove', handler.dragged)
$(window).bind('mouseup', handler.dropped)
return false
},
dragged:function(e){
var old_nearest = nearest && nearest.node._id
var pos = $(canvas).offset();
var s = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
mouse_is_moving = true
if (!nearest) return
if (dragged !== null && dragged.node !== null){
var p = particleSystem.fromScreen(s)
dragged.node.p = p
}
return false
},
dropped:function(e){
if (dragged===null || dragged.node===undefined) return
if (dragged.node !== null) dragged.node.fixed = false
dragged.node.tempMass = 50
dragged = null
selected = null
$(canvas).unbind('mousemove', handler.dragged)
$(window).unbind('mouseup', handler.dropped)
_mouseP = null
if(mouse_is_moving){
// console.log("was_dragged")
} else {
handler.clicked(e)
}
mouse_is_down = false
return false
}
}
$(canvas).mousedown(handler.mousedown);
$(canvas).mousemove(handler.mousemove);
}
}
As you can see,
I made a difference between the clicked and mousedown handler functions.
I am opening links in new tabs. To simply redirect, change:
window.open(link, "_blank") for window.location = link.
The above must replace your previous initMouseHandling function in the renderer.js file.
Define "dom" as: var dom = $(canvas)
You have to add the following css code to give feedback to the user.
canvas.linkable{
cursor: pointer;
}
In the script renderer.js is the handler for the mouse events, so you can add your code to create your functions.
I modified the renderer.js to add the click and double-click functions.
var handler = {
clicked:function(e){
var pos = $(canvas).offset();
_mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
selected = nearest = dragged = particleSystem.nearest(_mouseP);
if (dragged.node !== null) dragged.node.fixed = true
$(canvas).bind('mousemove', handler.dragged)
$(window).bind('mouseup', handler.dropped)
$(canvas).bind('mouseup', handler.mypersonalfunction)
},
mypersonalfunction:function(e){
if (dragged===null || dragged.node===undefined) return
if (dragged.node !== null){
dragged.node.fixed = false
var id=dragged.node.name;
alert('Node selected: ' + id);
}
return false
},
You can check the clic and double-click functions in this page.
I add nodes and edges when a node has been clicked and I add edges to other nodes when the node has been double-clicked (the blue,yellow and green ones)
I´m looking for similar customization for selection over each node id value.
How would it be if instead of mouse-handler trigger, the selection was made via checkbox inside each node?
<input type=checkbox name=mycheckbox[]>
Related
Switch baseLayers according user preferences onLoad (init()) - OpenLayers - 3
I'm working on a project where I need to switch the base layer, according to the user preferences with the inicial zoom (already working). I don't really know where, but i've seen that by default, the base layer "Google Satellite" is the one selected. I've tried to do by triggering a click on the wanted radio button and, the radio button get clicked visually, but nothing happend (the map selected is always "Satellite", no matter if I triggered a click or I don't know). I have tried SO MANY THINGS but this is like wet soap in my hands... when I think i have got the right way, it slides away function zoominicial(){ $.getJSON('servicos/usuario.svc/getZoomInicial', function (data) { var ret = data.d; var bsNum; if (ret != "ERRO") { if(!ret){ zoomtoextent(); } else { var base_Layer = ret.split(';')[1]; var extentUsuario = ret.split(';')[0].split(','); var bsType; switch(base_Layer){ case "Google Satellite": $(".baseLayersDiv input")[0].click(); $(".baseLayersDiv input")[0].checked = true; bsNum = 0; bsType = "satellite"; checkRadio(); break; case "Google Hybrid": $(".baseLayersDiv input")[1].click(); $(".baseLayersDiv input")[1].checked = true; bsNum = 1; bsType = "hybrid"; checkRadio(); break; case "Google Street Maps": $(".baseLayersDiv input")[2].click(); $(".baseLayersDiv input")[2].checked = true; bsNum = 2; bsType = "roadmap"; checkRadio(); break; case "Sem Foto": $(".baseLayersDiv input")[3].click(); $(".baseLayersDiv input")[3].checked = true; bsNum = 3; checkRadio(); break; } function checkRadio(){ var radioBs = $('input:radio[name="' + map.layers[bsNum].name + '"]'); if(radioBs.is(':checked') === false) { radioBs.filter('[value=' + map.layers[bsNum].value + ']').prop('checked', true); } } if (map.baseLayers == undefined || map.baseLayers == "") map.layers[bsNum].type = bsType; else map.baseLayers.type = bsType; map.zoomToExtent(extentUsuario,map.layers[bsNum].projection); $(".baseLayersDiv input").on("click", function(){ $(".baseLayersDiv input")[bsNum].checked= true; }); $(""+map.layers[bsNum].id+"").trigger( "select" ); var linkEl = $('label[for="'+""+ $(".baseLayersDiv input")[bsNum].id +""+'"]'); if ( linkEl.click() === undefined ) { document.location = linkEl.attr ( 'index.aspx' ); } else { linkEl.click(); $(".baseLayersDiv input")[bsNum].click(); } } } else { $.messager.alert('cGIS', 'Não foi possível exibir o zoom inicial.'); } setTimeout(2000); }); } You see... I have tried every way to make the selection of the base layer but with no success. I just can't reach the attributes of determinated base layer, because the children of the array of radio buttons are encapsulated. Does someone knows how to do it, PLEASE? I'm about to get crazy and throw my desk through the window!
You have to find where all of the layers are defined or know where the instances are stored and call function setVisible(false) to all of them except the one you would like to have active on the begening. Changing unbined radio buttons wont change anything. Better would be to initialize them with the corresponding value to "visible" parameter. All layers are visible by deafault, and in case of full raster layers you will see only the top one. OL - setVisible API
Handsontable: adding a column moves colHeaders (how to fix?)
In the above snippet, a handsontable is created with a hook that adds a column automatically (using this.alter('insert_col')) once a user presses "right" in the rightmost column (and also removes an empty rightmost column if a user presses "left" from there). The issue with it, as you may see, is that once a column added in this manner, colHeaders shift to the right instead of staying with their columns. Is this a bug or I am doing something wrong? How do I fix this or is there a workaround? document.addEventListener("DOMContentLoaded", function() { var example = document.getElementById('example1'), hot = new Handsontable(example,{ data: Handsontable.helper.createSpreadsheetData(2, 3), colHeaders: ["one","two","three"], contextMenu: true }); Handsontable.hooks.add('beforeKeyDown',function(event) { var $right = 39, $left = 37, selected = this.getSelected(), isEditMode = this.getActiveEditor().isOpened(); if(isEditMode) return; // calc dimensions var startColNum = selected ? (selected[1]+1) : null, endColNum = selected ? (selected[3]+1) : null, // endColNum is not necessarily >= startColNum, it is where selection /has ended/ rowsNum = this.countRows(), colsNum = this.countCols(), isFirstCol = endColNum == 0, isLastCol = endColNum == colsNum, i, noData, data = this.getData(); // handle arrow keys if(isLastCol) { if(event.which == $right) this.alter('insert_col'); if(event.which == $left && !isFirstCol) { noData = true; for(i = 0; i < rowsNum; i++) if(data[i][endColNum-1]) noData = false; if(noData) { this.alter('remove_col'); Handsontable.Dom.stopImmediatePropagation(event); // don't scroll the page if(event.preventDefault) event.preventDefault(); } } } }); }); <script src="https://docs.handsontable.com/pro/1.10.2/bower_components/handsontable-pro/dist/handsontable.full.min.js"></script> <link type="text/css" rel="stylesheet" href="https://docs.handsontable.com/pro/1.10.2/bower_components/handsontable-pro/dist/handsontable.full.min.css"> <div id="example1" class="hot handsontable"></div>
As IronGeek suggest in the comment, adding the index as the second parameter to the function alter fix your issue : this.alter('insert_col', endColNum); However, I do believe that you are still right saying that it is a bug since the documentation specify that if the paramater index is null or undefined : [...] the new column will be added after the last column. Find this JSFiddle for quickly testing the fix.
Check which element mouse is over to control visiblity of another div
I am trying to build a menu which detects hover states and hide/shows relevant divs depending on where the mouse is. I need to do this with Prototype.js. The menu looks something like this : ========ONE========TWO======THREE=======FOUR======FIVE====== ============================================================ ------------------- BIG MIDDLE DIV ------------------------- ============================================================ ============================================================ -------------------- TARGET HIDDEN DIV --------------------- ============================================================ When you mouse over link one,two,three.. it will show the related target div. The trick is when you mouseout, it needs to keep that div visible if you are on the middle div or the active state div. If you mouseout anywhere else in the body it needs to hide. Here is updated code based off the answer so far. <ul><li #id="one">one</li><li>two</li><li>three</li><li>four</li></ul> <div id="middleBar"></div> <div id="container-one">1</div> <div id="container-two">2</div> <div id="container-three">3</div> <div id="container-four">4</div> <script> MouseOff = true; function getTarget(event) { var el = event.target || event.srcElement; return el.nodeType == 1? el : el.parentNode; } var ShowDiv = function(activeDiv){ $(activeDiv).addClassName('isActive'); var activeSibs = $(activeDiv).siblings(); activeSibs.invoke('removeClassName', 'isActive'); }; var HideDiv = function(){ if(MouseOff){ $$('div').invoke('removeClassName','isActive'); } }; $$('li').invoke('observe','mouseenter',function(){ console.log(getTarget(event)); MouseOff = false; var linkName = this.innerHTML; var activeDiv = 'container-' + linkName; ShowDiv(activeDiv); }); $$('li').invoke('observe','mouseleave',function(){ MouseOff = true; HideDiv(); }); $$('#middleBar').invoke('observe','mouseenter',function(){ console.log(getTarget(event)); MouseOff = false; }); </script> Here is a fiddle of this : http://jsfiddle.net/TqMtK/5/ To further clarify what I am trying to achieve, once the div is activated it needs to stay visible while on that nav trigger, the middle bar, or the active div itself. Something else I was thinking was to use that getTarget function to always check what element the mouse is above, but this just feels wrong to me and does not seem very efficient. Any opinions on that? UPDATE : Still trying to work through this.. now I am a little closer and the flag is set correctly when over middle div, but when it goes over the active div it resets the flag and the div disappears. I tried adding back a timeout.. here is latest attempt : http://jsfiddle.net/TqMtK/7/ UPDATE : Ok I think I might have this, at this point I would like to just hear any feedback on this solution. I found that because the active class is being added dynamically the observer method must be included in the function that creates it : ShowDiv. Here is what I got : http://jsfiddle.net/TqMtK/9/
UPDATED: tues night. I am sure this can be more succinct. Perhaps it is just my browser but I notice that I can only mouse over Panel1 and show that it doesn't disappear, the other Panels (because of their positioning) leave a space which is the "body" and I close on that. Hopefully this is a bit better. http://jsfiddle.net/TqMtK/12/ var tabPanels = { options : { activePanel : "", activeTab : "" }, showPanel : function(panel){ this.hidePanel(); this.options.activePanel = 'container-' + panel; this.options.activeTab = panel; $(this.options.activePanel).addClassName('isActive').setAttribute('panel',panel); }, hidePanel : function(panel){ if(Object.isElement($(panel)) && $(panel).hasAttribute('panel') ){ if($(panel).readAttribute('panel') == this.options.activeTab ){ return; }else{ if(!this.options.activePanel.blank()){ $(this.options.activePanel).removeClassName('isActive'); } } }else{ if(!this.options.activePanel.blank()){ $(this.options.activePanel).removeClassName('isActive'); } } } } document.observe('mouseover', function(e){ switch(e.target.id){ case 'middleBar': break; case 'one': case 'two': case 'three': case 'four': tabPanels.showPanel(e.target.id); break; default: tabPanels.hidePanel(e.target.id); } })
After much tinkering I finally found a working solution for this. Thanks to the idea from james I went the route of setting a flag depending on which element the mouse was over. That combined with a timeout allowed me to keep running checks on the mouse location. Part of my problem was where I was invoking the observe event on the class that was dynamically added from ShowDiv(), when I moved it in to that function I was able to get it to work. Here is the js I ended up with MouseLocator = 'off'; var ShowDiv = function(activeDiv){ $(activeDiv).addClassName('isActive'); var activeSibs = $(activeDiv).siblings(); activeSibs.invoke('removeClassName', 'isActive'); $$('.isActive').invoke('observe','mouseenter',function(){ MouseLocator = 'on'; }); $$('.isActive').invoke('observe','mouseleave',function(){ MouseLocator = 'off'; setTimeout(function(){HideDiv()},500); }); }; var HideDiv = function(){ if(MouseLocator == 'off'){ $$('div').invoke('removeClassName','isActive'); } }; $$('li').invoke('observe','mouseenter',function(){ MouseLocator = 'on'; var linkName = this.innerHTML; var activeDiv = 'container-' + linkName; ShowDiv(activeDiv); }); $$('li').invoke('observe','mouseleave',function(){ MouseLocator = 'off'; setTimeout(function(){HideDiv()},500); }); $$('#middleBar').invoke('observe','mouseenter',function(){ MouseLocator = 'on'; }); $$('#middleBar').invoke('observe','mouseleave',function(){ MouseLocator = 'off'; setTimeout(function(){HideDiv()},500); }); and a fiddle : http://jsfiddle.net/TqMtK/9/ I guess this is resolved but I am always open to suggestions on how to improve my code :)
Add new rows to jqGrid Treegrid model
We've created a jqGrid TreeGrid that represents a filesystem, where branches are folders and leafs are files. We've implemented functionality within the TreeGrid to create new "files" by using addChildNode which works well enough. However, we also want to add functionality to create new folders. Our script works which creates new folders, but they are not immediately displayed on the TreeGrid unless it or the page is reloaded. However, reloading the TreeGrid will collapse all the folders, which is particularly annoying. Is there a way to selectively refresh the nodes of the TreeGrid, or to add a new branch in that is functional? I've seen some partial documentation on addJSONData, but using this function completely purges the TreeGrid until refresh. I've also attempted to use addChildNode and change certain properties, and I've tried to add in the row manually using DOM manipulation; however, both of these methods break the node that was inserted. Edit: var grid = $("#grid"); grid.jqGrid({ treeGrid: true, treeGridModel: "adjacency", ExpandColumn: 'name', ExpandColClick: true, url:"", datatype:"json", colNames:['id','Name','Authorization','Views','Uri'], colModel:[ {name:'id', index:'id', hidden:true, key:true}, {name:'name', index:'name', sorttype:"text", width:3, sortable:false}, {name:'auth',index:'auth', sorttype:"text", sortable:false, hidden:true}, {name:'views',index:'views', sorttype:"integer", width:1, sortable:false, align:"center"}, {name:'uri',index:'uri',sorttype:'text',sortable:false,hidden:true}], jsonReader:{ root:"rows" ,page:"page" ,total:"total" ,records:"records" ,repeatitems:false ,cell:"" ,id:"0" ,userdata:"" }, multiselect:false, autowidth:true, height:"auto", sortable:false, toppager:true, hidegrid: false, loadui: 'block', pager:"#grid_pager", caption: "Files", }); A returned JSON request for the new folder looks something like this: ret = {"error":"","total":1,"page":1,"records":1,"rows":[{"id":"1113","name":"test","uri":"accounting\/test\/","parent":1,"isLeaf":false,"expanded":true,"loaded":true}]} Which I attempt to add in using: grid[0].addJSONData(ret); The initial data that is loaded is sent as JSON: {"rows":[ {"id":"1","uri":"afolder\/","parent_id":"0","name":"afolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"4","uri":"bfolder\/","parent_id":"0","name":"bfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"7","uri":"cfolder\/","parent_id":"0","name":"cfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"20","uri":"dfolder\/","parent_id":"0","name":"dfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"48","uri":"efolder\/","parent_id":"0","name":"efolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"179","uri":"ffolder\/","parent_id":"0","name":"ffolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"182","uri":"gfolder\/","parent_id":"0","name":"gfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"186","uri":"hfolder\/","parent_id":"0","name":"hfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"201","uri":"ifolder\/","parent_id":"0","name":"ifolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"239","uri":"jfolder\/","parent_id":"0","name":"jfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"253","uri":"kfolder\/","parent_id":"0","name":"kfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"262","uri":"lfolder\/","parent_id":"0","name":"lfolder","level":0,"parent":"0","isLeaf":"false"}, {"id":"274","uri":"mfolder\/","parent_id":"0","name":"mfolder","level":0,"parent":"0","isLeaf":"false"} ]}
The demo shows how to use addChildNode method to add tree node. I added in the JSON data which you posted the "loaded":true part because I use in the test no server components and I want to load the treegrid at once. To show that you should be very careful with ids of the new added row I added two buttons in the demo: "Insert tree node" and "Insert tree node with unique rowid". The first button use the id="1113" from the data which you posted. One click on the button work correct. the second click will insert rows having id duplicates which will be an error. The error you can see different in different web browsers. The second button use $.jgrid.randId() to generate unique rowid. It is probably not an option in your scenario, but it works perfect in case of local tree grid (like in my demo). Another problem is that you use "parent":"0" in your demo for the root elements. Correct will be "parent":null or "parent":"null" (see the answer). Moreover the property with the name "parent_id" will be ignored. I removed from the demo some settings, so that local sorting can be used in the treegrid.
We solved this problem by extending the functionality of the jqGrid source. First we created a function that could delete all of the child nodes of a particular folder (both folders/branches and files/leaves), so that we could reload them and hence get the latest set of children. This function takes an integer rowid just like delTreeNode(). delChildren : function (rowid) { return this.each(function () { var $t = this, rid = $t.p.localReader.id, left = $t.p.treeReader.left_field, right = $t.p.treeReader.right_field, myright, width, res, key; if(!$t.grid || !$t.p.treeGrid) {return;} var rc = $t.p._index[rowid]; if (rc !== undefined) { // nested myright = parseInt($t.p.data[rc][right],10); width = myright - parseInt($t.p.data[rc][left],10) + 1; var dr = $($t).jqGrid("getFullTreeNode",$t.p.data[rc]); if(dr.length>0){ for (var i=0;i<dr.length;i++){ if(dr[i][rid] != rowid) $($t).jqGrid("delRowData",dr[i][rid]); } } if( $t.p.treeGridModel === "nested") { // ToDo - update grid data res = $.jgrid.from($t.p.data) .greater(left,myright,{stype:'integer'}) .select(); if(res.length) { for( key in res) { res[key][left] = parseInt(res[key][left],10) - width ; } } res = $.jgrid.from($t.p.data) .greater(right,myright,{stype:'integer'}) .select(); if(res.length) { for( key in res) { res[key][right] = parseInt(res[key][right],10) - width ; } } } } }); }, Then, we created a function to force reloading of a certain node (folder). reloadNode: function(rc) { return this.each(function(){ if(!this.grid || !this.p.treeGrid) {return;} var rid = this.p.localReader.id; $(this).jqGrid("delChildren", rc[rid]); var expanded = this.p.treeReader.expanded_field, parent = this.p.treeReader.parent_id_field, loaded = this.p.treeReader.loaded, level = this.p.treeReader.level_field, lft = this.p.treeReader.left_field, rgt = this.p.treeReader.right_field; var id = $.jgrid.getAccessor(rc,this.p.localReader.id); var rc1 = $("#"+id,this.grid.bDiv)[0]; rc[expanded] = true; $("div.treeclick",rc1).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus"); this.p.treeANode = rc1.rowIndex; this.p.datatype = this.p.treedatatype; if(this.p.treeGridModel == 'nested') { $(this).jqGrid("setGridParam",{postData:{nodeid:id,n_left:rc[lft],n_right:rc[rgt],n_level:rc[level]}}); } else { $(this).jqGrid("setGridParam",{postData:{nodeid:id,parentid:rc[parent],n_level:rc[level]}} ); } $(this).trigger("reloadGrid"); rc[loaded] = true; if(this.p.treeGridModel == 'nested') { $(this).jqGrid("setGridParam",{postData:{nodeid:'',n_left:'',n_right:'',n_level:''}}); } else { $(this).jqGrid("setGridParam",{postData:{nodeid:'',parentid:'',n_level:''}}); } }); }, This is the same as expandNode() save for that it does not check if the node was expanded to begin with, and forces it to send an AJAX request for the child elements of that node. This way, we always have the latest children. Finally, we fixed a small bug in getRowData(), which prevented us from using it to supply the record argument to either expandNode() or our newly created reloadNode(). The issue was that the _id_ field in the JSON return was never created or filled. Adding that in fixed both expandNode() and reloadNode() The following is the changed source. Not ideal, but it works. getRowData : function( rowid ) { var res = {}, resall, getall=false, len, j=0; this.each(function(){ var $t = this,nm,ind; if(typeof(rowid) == 'undefined') { getall = true; resall = []; len = $t.rows.length; } else { ind = $t.rows.namedItem(rowid); if(!ind) { return res; } len = 2; } while(j<len){ if(getall) { ind = $t.rows[j]; } if( $(ind).hasClass('jqgrow') ) { $('td',ind).each( function(i) { nm = $t.p.colModel[i].name; if ( nm !== 'cb' && nm !== 'subgrid' && nm !== 'rn') { if($t.p.treeGrid===true && nm == $t.p.ExpandColumn) { res[nm] = $.jgrid.htmlDecode($("span:first",this).html()); } else { if($t.p.colModel[i].key != undefined && $t.p.colModel[i].key == true) { try { res["_" + nm + "_"] = $.unformat(this,{rowId:ind.id, colModel:$t.p.colModel[i]},i); } catch (e){ res["_" + nm + "_"] = $.jgrid.htmlDecode($(this).html()); } } try { res[nm] = $.unformat(this,{rowId:ind.id, colModel:$t.p.colModel[i]},i); } catch (e){ res[nm] = $.jgrid.htmlDecode($(this).html()); } } } }); if(getall) { resall.push(res); res={}; } } j++; } }); return resall ? resall: res; }, Finally, we pull this all together as follows, with a JSON return object from creating a folder such as {{"id":"1267", "name":"test15", "uri":"sample1\/test15\/", "parent_id":1, "parent":1, "isLeaf":false} We call the function like var parentid = ret.rows[0].parent; var parent = grid.jqGrid('getRowData', parentid); grid.jqGrid('reloadNode', parent); The functions will delete all the child nodes of parent, then send an AJAX request for the new, updated list from the database. I'm going to push this onto the jqGrid Github if possible, since a reload function maybe useful for many people. I've posted it in here in case it isn't approved.
How do I write an onblur function to kill this anchor tag?
I wrote this code for 508 compliance but after the users tabs off of it I want the element to go way how can I do this? here is the below: handleInteraction:function(focusable){ this.setElements(); var totalAllowed = (this.elements.totalChar[0].innerHTML); var value = this.obj.value; var chars = value.length; var charsLeft = parseInt(totalAllowed) - parseInt(chars); if (charsLeft >= 0 || (typeof focusable=='boolean' && focusable==false)){ this.elements.leftChar[0].innerHTML = charsLeft; this.elements.charLeftp.removeClass("error"); } else { this.obj.value = value.substring(0, totalAllowed); this.elements.leftChar[0].innerHTML = 0; this.elements.charLeftp.addClass("error") var divNA = dojo.byId("max-"+this.obj.id); if (divNA){ dojo.destroy(divNA); } divNA = dojo.create("a",{"id":"max-"+this.obj.id,"class":"hide-fromsighted","innerHTML":"<h5>This textarea has reached the maximum allowed number of characters. Please navigate backwards!</h5>","tabindex":"-1"}); dojo.place(divNA,this.obj,'after'); divNA.focus(); /* * Here apply the onblur event to kill the <a> */ }
I'm assuming you are using the Dojo Toolkit. You can destroy the <a> tag with dojo.destroy and you can use dojo.stopEvent to stop that <a> event propagation. http://www.dojotoolkit.org/reference-guide/dojo/destroy.html#dojo-destroy http://www.dojotoolkit.org/reference-guide/dojo/stopEvent.html#dojo-stopevent
what about: divNA.onblur = function() { divNA.destroy(); } Would that work?