I have an ASP.net webForms, using .NET 4.7.2 TreeView.
I'm using the TreeView component to render a webpage. this renders the tree as a series of tables for node labels and div elements containing child nodes.
I'm trying to add a click event to the node, which is an element located in the table.
The TreeNode has been overriden, to make use of RenderPreText, which adds an attribute role="treeitem" to each of these node's label.
ie
protected override void RenderPreText(HtmlTextWriter writer) {
writer.AddAttribute("role", "treeitem");
}
The following code is what I'm using to add the click event to each node's label element:
window.addEventListener("load", (event) => {
var treeItems = document.querySelectorAll('[role="treeitem"]');
for (var i = 0; i < treeItems.length; i++)
{
treeItems[i].addEventListener('click', OnNodeSelect);
}
});
function OnNodeSelect(event) { alert('Node Selected'); }
The issue i'm having, is that when the node is selected, the event fires and is then removed, so can only be clicked a single time.
What am I doing wrong, how do I add an event that doesn't get removed after single activation?
Related
JavaFX scene has an object of class inherited from the Region. This object has a handler of MOUSE_DRAGGED event. When this handler is called, all object's child nodes are removed and new child nodes are added. The problem is when all children are removed from my object, it doesn't receive any events anymore, because target of MOUSE_DRAGGED event is removed child node. How to solve it?
I cannot use setMouseTransparent method, because some elements inside my object have mouse event handlers.
Ok, perhaps I got the question:
A region has many children. If the user left-clicks and dragges on these children, they will be modified or even removed. As the Mouse-Drag event is 'locked' to the first child where the drag started, no other child will receive further events if the mouse is dragged over some of the other children.
You might benefit from the fact, that the MouseDrag event is passed to the parent region after removing the child. So it is possible to register an onMouseDragged handler on th eparent regon receiving that event. Now the handler is able to 'pick' any childs below mouse for further actions using event.getPickEvent():
void mouseDragPop(Pane region) {
region.setOnMouseDragged(e -> {
Node node = e.getPickResult().getIntersectedNode();
if (node instanceof Circle) {
region.getChildren().remove(node);
}
});
for (int i = 1; i < 10; i++) {
final int n = i;
Circle circle = new Circle(20);
circle.setTranslateX(0);
circle.setTranslateY(0);
circle.setFill(Color.rgb(180, 200, 170));
circle.setLayoutX(System.nanoTime()/1000 % 200);
circle.setLayoutY(System.nanoTime()/3000 % 100);
region.getChildren().add(circle);
circle.setOnMouseDragged(e -> {
region.getChildren().remove(circle);
e.consume();
});
}
}
Now you are able to click and 'pop' all circle on your mouse-drag way...
I have GWT CellList and after adding items via a DataProvider I use the following code to add styling to each item.
members... we can styling if a matched item is also in members
matched... passed in as a MetaJsArray<Contact>
CellList<Contact> list = getView().getResults();
for (int i=0; i<matched.length(); i++) {
if (members.isExistingEntry(matched.get(i))) {
list.getRowElement(i).addClassName("RED");
}
}
This code works until... I click items in the list.
onCellPreview() is called for each item clicked, but the previously clicked item loses its "RED" styling.
Do I need to add styling differently? Or how do I stop the loss of "RED"?
My guess its something to do the way GWT generates the javascript. When you manually set the cell on load its all good. When you select it, the javascript changes the object to use the selected CSS and when you un select it, the CSS changes to the default GWT CSS style for the cell.
Only way I can think of is to have a handler on select. When you select an item:
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
public void onSelectionChange(SelectionChangeEvent event) {
// get item last selected
// check if needs re styling
// restyle
// do things with the new selected object
}
});
Add another check through the cell list and mark the ones that got unmarked.
This way might be inefficient, but its one way of avoiding your problem that I can think of. hope it helps.
After trying various approaches the only want that works, without hacks, is to define the style at the point of rendering.
With my own ContactCell extending AbstractCell the render() function can pass in a styling value into the contactcell.ui.xml file.
#Override
public void render(Context context, Contact value, SafeHtmlBuilder sb) {
if (value == null) {
return;
}
String styling = value.getStyling();
uiRenderer.render(sb, styling);
}
and then in contactcell.ui.xml file
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>
<ui:with field='styling' type='java.lang.String'/>
<div class="{styling}"> ... </div>
GWT will mangle the style name so define your own CssResource class to access the class name thru so that the class name is mangled throughout the app.
I have made a hierarchy in which there is a main page, using add element i have attached a component mxml of type group. There is a single button on main page when clicked it should add children of type group in that group type mxml component along with two buttons. Now using one of buttons i am attaching another component mxml type group. the problem is even they overlap i can still excess the children groups of first group component mxml. how can i stop this mouse events to happen.
I think those kind of events usually bubble up to parent components.
You can try using the following code in your mouse click event listener to stop further propagation:
private function onMouseClicked(event: MouseEvent): void {
event.stopPropagation();
... do whatever you wanted when smth was clicked ...
}
By setting enabled, mouseChildren, mouseEnabled to false, you will disable the entire component and it's children. example below
private var myPreviousGroupComponent:Group = null;
function addNewGroup():void
{
if(myPreviousGroupComponent != null)
{
myPreviousGroupComponent.enabled = false;
myPreviousGroupComponent.mouseChildren = false;
myPreviousGroupComponent.mouseEnabled = false;
}
var newGroup:Group = new Group();
addElement(newGroup);
myPreviousGroupComponent = newGroup;
}
I use a ASP.NET Menu control with Orientation=Horizontal. It is kind of irritating that the popout menus appear on mouseover, which causes it to show by accident if you move the mouse over the menu when you want to click on something right below the menu. Then the menu popout hides the element you actually wanted to click on!
Is it possible to change the functionality so that the popout requires a mouse click instead of mouseover?
Well, I found a solution myself (kind of a hack...).
This solution requires use of AJAX to capture the menu item onclick postback event, so it can be picked up client side in javascript before doing the actual postback when you click the menu item.
First, I override these functions that is defined by the Menu control
to ignore the menu popout in the mouseover event:
var activeMenuItem = null;
function Menu_HoverStatic(item) {
// Register the active item to be able to access it from AJAX
// initialize postback event
activeMenuItem = item
// Apply the style formatting on mouseover (colors etc).
// This was also called in the original Menu_HoverStatic function.
Menu_HoverRoot(item);
}
function Menu_Unhover(item) {
activeMenuItem = null; // This is the only difference to the original
var node = (item.tagName.toLowerCase() == "td") ?
item:
item.cells[0];
var nodeTable = WebForm_GetElementByTagName(node, "table");
if (nodeTable.hoverClass) {
WebForm_RemoveClassName(nodeTable, nodeTable.hoverClass);
}
node = nodeTable.rows[0].cells[0].childNodes[0];
if (node.hoverHyperLinkClass) {
WebForm_RemoveClassName(node, node.hoverHyperLinkClass);
}
Menu_Collapse(node);
}
// Then I added a renamed copy of the original `Menu_HoverStatic` function:
function Menu_ClickStatic() {
// Pick up the active menu item that is set in the
// overridden Menu_HoverStatic function.
// In the original, the item was input parameter.
var item = activeMenuItem;
// The rest is identical to the original Menu_HoverStatic.
var node = Menu_HoverRoot(item);
var data = Menu_GetData(item);
if (!data) return;
__disappearAfter = data.disappearAfter;
Menu_Expand(node, data.horizontalOffset, data.verticalOffset);
}
Then I snap up the onclick postback event in AJAX that is triggered by the menu. This must be done to cancel the onclick postback and display the menu popout instead.
// Get the Page Request Manager that provides all the .NET
var prm = Sys.WebForms.PageRequestManager.getInstance();
// Register postback event for asyncronous AJAX postbacks
if (prm) prm.add_initializeRequest(InitializePostback);
function InitializePostback(sender, args) {
var element = args.get_postBackElement();
//Check if the postback element is the menu
if (element.id == 'myMenu') {
// Name of the menu element that triggered is the postback argument
var postbackArguments = document.getElementById('__EVENTARGUMENT');
if (postbackArguments)
// Check on the menu item name to pick up only the menu items that shall
// trigger the popout (not the items that does an actual command).
if (postbackArguments.value == 'MenuTopItem1'
|| postbackArguments.value == 'MenuTopItem2'
|| postbackArguments.value == 'MenuTopItem3') {
// Abort and cancel the postback
prm.abortPostBack();
args.set_cancel(true);
Menu_ClickStatic(); // Call my own copy of the original function
return;
}
}
}
Note:
I found out the details about these functions by using the script viewer in Firebug.
The soluton provided above doesn't work in everone's case. One can also try this out, it worked in my solution-
var jq = jQuery.noConflict();
jq(document).ready(function () {
jq(document).on('click', '#ctl_id_Here', function () {
Menu_HoverStatic(this);
Menu_HoverRoot(this);
});
jq(document).on('click', '#ctl_id_Here', function () {
Menu_HoverStatic(this);
Menu_HoverRoot(this);
});
});
3 Steps:
Stop the current hovering effects:
On page load (or on ready), write following line: $('#Menu1').find('ul .level2').css('display','none');
Once you do that, it'll stop the hovering effect of that menu. But once you do that, then you would only be able to open the submenu by making it display block, so for that I wrote following lines, onclick of an image inside the menu: $('#Menu1').find('ul .level2').css('display','block');
Open the menu on click of an element: I don't think need to explain it. Just make menu display block on click of the identified element.
Close the opened menu: 2 ways to do it: First; Use property Disapperafter as below:
Second: Write below code to close it onclick of anywhere else on the screen:
$('body').click(function(evnt) {
if($(evnt.target).parents('table#menu').length == 0)
{
$('#MenuInvitePatient').find('ul .level2').css('display','none');
return;
}
else
{
return;
}
});
I'm doing a menu that loads levels dynamicly, when you click on a item the next level is loaded asynchronously. For each menu item I have a user control. Every user control is declared in its parent, for example, the "secondlevelcontrol" has the reference to "thirdlevelcontrol".
With this level of nesting, I want to manage the asynchronous calls on every user control so, when the first level is loaded the javascript to load the second is loaded too. When the second level is loaded the javascript to load the third is loaded too.
To do asynchronous calls I'm implementing ICallbackEventHandler interface. As you can see in the examples, controls are added to the page as plain html. The method "ProcessOnLoadEvent" executes all lines of the "OnLoad" event of the user control.
An example of the implementation is this for the user control of fourth level:
public string GetCallbackResult()
{
return _callbackRendering;
}
public void RaiseCallbackEvent(string itemId)
{
var id = Int32.Parse(itemId);
var menu = new LateralMenu();
var currentChildren = menu.GetNodesById(id, 1);
var ctrl = this.Page.LoadControl(USER_CONTROL_FIVE_LEVEL_RELATIVE_PATH) as LeftSideFifthLevel;
ctrl.Items = currentChildren.Children;
ctrl.ProcessOnLoadEvent();
_callbackRendering = ctrl.GetHtml();
}
And this is the code for the fifth level user control:
public void ProcessOnLoadEvent()
{
EnsureChildControls();
if (null != RepeaterMenu)
{
SettingCallbackReference();
Visible = null != Items && 0 < Items.Count;
if (null != Items && 0 < Items.Count)
{
RepeaterMenu.DataSource = Items;
RepeaterMenu.DataBind();
}
}
}
public void RaiseCallbackEvent(string itemId)
{
var id = Int32.Parse(itemId);
var menu = new LateralMenu();
var currentChildren = menu.GetNodesById(id, 1);
var ctrl = this.Page.LoadControl(USER_CONTROL_SIX_LEVEL_RELATIVE_PATH) as LeftSideSixthLevel;
ctrl.Items = currentChildren.Children;
ctrl.ProcessOnLoadEvent();
_callbackRendering = ctrl.GetHtml();
}
public void SettingCallbackReference()
{
var cm = this.Page.ClientScript;
var cbRef = cm.GetCallbackEventReference(this, "itemId", "AnchorLevel5_OnClick_Callback", "ctx");
var cbScript = "function AnchorLevel5_OnClick(itemId, ctx){ new Menu().empty(ctx); " + cbRef + "; }";
cbScript += "function AnchorLevel5_OnClick_Callback(htmlText, ctx){ new Menu().render(htmlText, ctx); }";
cm.RegisterClientScriptBlock(this.GetType(), "CallServer", cbScript, true);
}
My problem is that levels beyond second level never work because the javascript associated with the user control ("SettingCallbackReference" method) has no html to put on the page.
Is there any way to create some user controls created dynamicly that implements ICallbackEventHandler interface that add new user controls to the page? Or, Am I doing something wrong and this is not the right way to implement this behaviour?
Thanks!!!
I suspect that you are probably going about this the wrong way. Take a look at the answer to this question: How to lazy load Infragistics UltraWebTree control?
This question was specifically about lazy-loading a tree view, but the same principles apply for lazy loading menu items. Follow these steps:
On first page load, render the top level menu
Include a function on the page that makes an ajax call to the server with the
parent id and retuns the next level items for that parent (getNodes in my example)
Bind this function to the click event of the top level menu items (that have sub items)
In the success handler of the ajax call, inject the returned menu items below
the parent and bind the same function to the click event of these items only.
On callback, be careful not to bind the function to the click event of ALL menu items, because then you will end up getting the function bound multiple times to the top level items and called multiple times. Just bind to the returned items.
Also, you need some way of determining that an item's sub items have already been loaded. That is what the following line in my example was for, but you might need something slightly different:
if (jQuery(nodesDiv).text() == 'Loading...') {
I used jQuery because it is the most concise, but you culd do this in pure js - I wouldn't recommend it.