Get list item

J

joe

I have a two level menu like below. When user clicks any item or sub item I'd
like to know which item is clicked. I could use id's and getElementById but is
there another way. This list can be long.

<ul onclick="testing()">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
<li><a href="#">Folder 1</a>
<ul>
<li><a href="#">Sub Item 1.1</a></li>
<li><a href="#">Sub Item 1.2</a></li>
</ul>
</li>
<li><a href="#">Item 3</a></li>
</ul>
 
T

Thomas 'PointedEars' Lahn

joe said:
I have a two level menu like below. When user clicks any item or sub item
I'd like to know which item is clicked. I could use id's and
getElementById but is there another way. This list can be long.

<ul onclick="testing()">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
<li><a href="#">Folder 1</a>
<ul>
<li><a href="#">Sub Item 1.1</a></li>
<li><a href="#">Sub Item 1.2</a></li>
</ul>
</li>
<li><a href="#">Item 3</a></li>
</ul>

Your approach is common, but wrong. Unfortunately, your address header
fields are also practically invalid, so you will probably never learn why.

<http://www.interhack.net/pubs/munging-harmful/>


PointedEars
 
D

Denis McMahon

I have a two level menu like below. When user clicks any item or sub
item I'd like to know which item is clicked.

document.activeElement might work, you'll need to assign element ids to
each anchor in the list.

The following is an example that I just tested in FF 4.0.1 on ubuntu
11.04:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html;
charset=utf-8">
<title>Test activeElement</title>
<script type="text/javascript">
function whoAmI() {
alert (document.activeElement.id + " was clicked");
}
</script>
</head>
<body id="mary">
<p onclick="whoAmI()" id="jim">
<a id="fred" name="fred" href="#pete">goto pete</a>
<a id="pete" name="pete" href="#fred">goto fred</a>
</p>
</body>
</html>

I make no claim for the support of document.activeElement in other
browsers, or older versions of firefox, or on other platforms.

Rgds

Denis McMahon
 
J

Jukka K. Korpela

I have a two level menu like below. When user clicks any item or sub item I'd
like to know which item is clicked. I could use id's and getElementById but is
there another way. This list can be long.

I wonder what you are trying to accomplish, but why don’t you simply
assign (using a loop) an onclick event handler to each link? That would
appear to be the natural way if you wish handle clicks on different
links differently.
 
G

Gregor Kofler

Am 2011-06-17 13:03, Jukka K. Korpela meinte:
I wonder what you are trying to accomplish, but why don’t you simply
assign (using a loop) an onclick event handler to each link? That would
appear to be the natural way if you wish handle clicks on different
links differently.

Natural? I suppose event bubbling is there to avoid such things. With
large enough menus you'd end up with dozens of (superfluous) listeners,
perhaps all of them leaking memory. Depending on the actual markup one
listener attached to the top-level ul element addressing event.target
(or window.event.srcElement respectively) together with a check of the
nodeName of the reported element will suffice to get the proper
reference to the anchor.

Gregor
 
J

joe

Gregor Kofler said:
Am 2011-06-17 13:03, Jukka K. Korpela meinte:

Natural? I suppose event bubbling is there to avoid such things. With
large enough menus you'd end up with dozens of (superfluous) listeners,
perhaps all of them leaking memory. Depending on the actual markup one
listener attached to the top-level ul element addressing event.target
(or window.event.srcElement respectively) together with a check of the
nodeName of the reported element will suffice to get the proper
reference to the anchor.

Gregor


What would be the prefeered way then?
 
G

Gregor Kofler

Am 2011-06-18 10:13, joe meinte:
What would be the prefeered way then?

I suppose "preference" is a personal thing or one determined by a given
situation. With your overly "lean" problem description (perhaps you
could avoid JS altogether), no one can point out an optimal solution.

In general I prefer event bubbling over numerous event listeners. Even
more so, when retrieving the event target is simple.

Gregor
 
J

joe

Gregor Kofler said:
I suppose "preference" is a personal thing or one determined by a given
situation. With your overly "lean" problem description (perhaps you
could avoid JS altogether), no one can point out an optimal solution.

In general I prefer event bubbling over numerous event listeners. Even
more so, when retrieving the event target is simple.

Gregor

What I am trying to accomplish is this:
given, say:
<ul onclick="testing()">
<li><a href="#1">clothing</a></li>
<li><a href="#2">meats</a></li>
<li><a href="#3">fruit</a>
<ul>
<li><a href="#4">apples</a></li>
<li><a href="#5">oranges</a></li>
</ul>
</li>
<li><a href="#6">vegetables</a></li>
</ul>



When user clicks "clothing" in my Javasrcipt I can display "clothing" in some
div.
When user clicks "oranges" I can display "clothing->oranges" etc.
Clicking should also take user to appropriate page, defined on corresponding
href. In above example I use #1, #2 just for brevity.

The list can be large with dozens of items and many sublevels. The examples has
just three item and two levels.
 
G

Gregor Kofler

Am 2011-06-18 10:48, joe meinte:
What I am trying to accomplish is this:
given, say:
<ul onclick="testing()">
<li><a href="#1">clothing</a></li>
<li><a href="#2">meats</a></li>
<li><a href="#3">fruit</a>
<ul>
<li><a href="#4">apples</a></li>
<li><a href="#5">oranges</a></li>
</ul>
</li>
<li><a href="#6">vegetables</a></li>
</ul>



When user clicks "clothing" in my Javasrcipt I can display "clothing" in some
div.
When user clicks "oranges" I can display "clothing->oranges" etc.

A "central" event listener, which retrieves the event target and
traverses the tree up to the root ul element, picking all anchors (or
rather their firstChild) along the way seems easy enough.
Clicking should also take user to appropriate page, defined on corresponding
href. In above example I use #1, #2 just for brevity.

"Going to another site" would lead to a page reload immediately once
your listener has returned, and no one will ever see your nicely
JS-built breadcrumbs navigation.
The list can be large with dozens of items and many sublevels. The examples has
just three item and two levels.

Performance won't be an issue. But with the above idea of loading a new
page, your whole approach is futile.

Gregor
 
E

Elegie

On 18/06/2011 10:48, joe wrote :

Hello,
When user clicks "clothing" in my Javasrcipt I can display "clothing" in some
div.
When user clicks "oranges" I can display "clothing->oranges" etc.
Clicking should also take user to appropriate page, defined on corresponding
href. In above example I use #1, #2 just for brevity.

As Gregor has pointed out, if you navigate away from the page, then what
you display on this page will necessarily disappear, as the new page
renders - or do you use frames?

Or would you be using A elements for something else than a navigation?
If this is the case, then you need to correct your design.

Or do you really navigate to another page, and still want to print the
navigation history? Then this becomes a state-keeping issue.

You have to be more specific about what you want to achieve. The
following script addresses the issue you have exposed in your first
post, i.e. "When user clicks any item or sub item I'd
like to know which item is clicked.".

---
<ul id="menu">
<li><a href="#1">clothing</a></li>
<li><a href="#2">meats</a></li>
<li>
<a href="#3">fruit</a>
<ul>
<li><a href="#4">apples</a></li>
<li><a href="#5">oranges</a></li>
</ul>
</li>
<li><a href="#6">vegetables</a></li>
</ul>

<div id="messages" style="font-family: Courier New"></div>

<script type="text/javascript">
var navigation=[];
document.getElementById("menu").onclick=(function(evt){
var e=evt||window.event;
var t=e.target||e.srcElement;
t=getParent(t, "a");
if(t) {
navigation.push(new Link(t));
printNavigation();

if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue=false;
}
}
});

function Link(a){
this.href=a.href;
this.text=getText(a);
}

Link.prototype.toString=(function(){
return this.text + "{" + this.href + "}";
})

function printNavigation() {
document.getElementById("messages").innerHTML=navigation.join("<br>");
}

function getParent(child, parentTypeName){
if (child==null) return null;
if (child.nodeName.toLowerCase()==parentTypeName) return child;
return getParent(child.parentNode, parentTypeName);
}

function getText(node) {
if(node.nodeType==3) {
return node.nodeValue;
} else if(node.nodeType==1) {
var children=node.childNodes;
var text="";
for(var ii=0; ii<children.length; ii++) {
text+=getText(children[ii]);
}
return text;
}
}
</script>
 
J

joe

Elegie said:
On 18/06/2011 10:48, joe wrote :

Hello,
When user clicks "clothing" in my Javasrcipt I can display "clothing" in some
div.
When user clicks "oranges" I can display "clothing->oranges" etc.
Clicking should also take user to appropriate page, defined on corresponding
href. In above example I use #1, #2 just for brevity.

As Gregor has pointed out, if you navigate away from the page, then what
you display on this page will necessarily disappear, as the new page
renders - or do you use frames?

Or would you be using A elements for something else than a navigation?
If this is the case, then you need to correct your design.

Or do you really navigate to another page, and still want to print the
navigation history? Then this becomes a state-keeping issue.

You have to be more specific about what you want to achieve. The
following script addresses the issue you have exposed in your first
post, i.e. "When user clicks any item or sub item I'd
like to know which item is clicked.".

---
<ul id="menu">
<li><a href="#1">clothing</a></li>
<li><a href="#2">meats</a></li>
<li>
<a href="#3">fruit</a>
<ul>
<li><a href="#4">apples</a></li>
<li><a href="#5">oranges</a></li>
</ul>
</li>
<li><a href="#6">vegetables</a></li>
</ul>

<div id="messages" style="font-family: Courier New"></div>

<script type="text/javascript">
var navigation=[];
document.getElementById("menu").onclick=(function(evt){
var e=evt||window.event;
var t=e.target||e.srcElement;
t=getParent(t, "a");
if(t) {
navigation.push(new Link(t));
printNavigation();

if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue=false;
}
}
});

function Link(a){
this.href=a.href;
this.text=getText(a);
}

Link.prototype.toString=(function(){
return this.text + "{" + this.href + "}";
})

function printNavigation() {
document.getElementById("messages").innerHTML=navigation.join("<br>");
}

function getParent(child, parentTypeName){
if (child==null) return null;
if (child.nodeName.toLowerCase()==parentTypeName) return child;
return getParent(child.parentNode, parentTypeName);
}

function getText(node) {
if(node.nodeType==3) {
return node.nodeValue;
} else if(node.nodeType==1) {
var children=node.childNodes;
var text="";
for(var ii=0; ii<children.length; ii++) {
text+=getText(children[ii]);
}
return text;
}
}
</script>
 
J

joe

Gregor Kofler said:
"Going to another site" would lead to a page reload immediately once
your listener has returned, and no one will ever see your nicely
JS-built breadcrumbs navigation.

Performance won't be an issue. But with the above idea of loading a new
page, your whole approach is futile.

Gregor

To clarify:
The page has a number of iFrames which are loaded. The main frame with the menu
stays the same.
 
J

joe

Here is full test page. Nothing seems to happend when I click an item

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//FI"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<head>
<script type="text/javascript">

var navigation=[];
document.getElementById("menu").onclick=(function(evt){
var e=evt||window.event;
var t=e.target||e.srcElement;
t=getParent(t, "a");
if(t) {
navigation.push(new Link(t));
printNavigation();

if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue=false;
}
}
});

function Link(a){
this.href=a.href;
this.text=getText(a);
}

Link.prototype.toString=(function(){
return this.text + "{" + this.href + "}";
})

function printNavigation() {
document.getElementById("messages").innerHTML=navigation.join("<br>");
}

function getParent(child, parentTypeName){
if (child==null) return null;
if (child.nodeName.toLowerCase()==parentTypeName) return child;
return getParent(child.parentNode, parentTypeName);
}

function getText(node) {
if(node.nodeType==3) {
return node.nodeValue;
} else if(node.nodeType==1) {
var children=node.childNodes;
var text="";
for(var ii=0; ii<children.length; ii++) {
text+=getText(children[ii]);
}
return text;
}
}
</script>
</head>

<BODY>
<ul id="menu">
<li><a href="#1">clothing</a></li>
<li><a href="#2">meats</a></li>
<li>
<a href="#3">fruit</a>
<ul>
<li><a href="#4">apples</a></li>
<li><a href="#5">oranges</a></li>
</ul>
</li>
<li><a href="#6">vegetables</a></li>
</ul>
<div id="messages" style="font-family: Courier New"></div>
</body>
</html>
 
E

Elegie

On 18/06/2011 14:32, joe wrote :

Hi,
Here is full test page. Nothing seems to happend when I click an item

You have relocated the SCRIPT tag into the HEAD, so when
document.getElementById is called, it fails as the element it refers to
has not been defined yet. Try and run the script by copy-pasting it
directly from my post, without altering it at all.

Also, I understand that you want to build some kind of navigation
manager, so I would like to suggest a refactored version of the script,
below. It comes with two files, which must be located in the same
directory (unless you adjust the path of the "src" attribute of the
SCRIPT tag in the HTML file):
- a javascript file, which contains an implementation for a
NavigationManager,
- a HTML file, which initializes the NavigationManager with the menu and
board components.


--- NavigationManager.js ---

var NavigationManager=(function(){
var navigationHistory=[];

function NavigationEntry(a){
this.href=a.href;
this.text=getText(a);
}

NavigationEntry.prototype.toString=(function(){
return this.text + "{" + this.href + "}";
});

function makeClickListener (board){
return (function (evt) {
var e=evt||window.event;
var t=e.target||e.srcElement;
t=getParent(t, "a");
if(t) {
navigationHistory.push(new NavigationEntry(t));
board.innerHTML=navigationHistory.join("<br>");
}
});
}

function addListener(target, evt, listener) {
if (target[evt]) {
target[evt] = (function(oldListener) {
return (function() {
oldListener.apply(this, arguments);
return listener.apply(this, arguments);
});
})(target[evt]);
} else {
target[evt] = listener;
}
}

function getParent(child, parentTypeName){
if (child==null) return null;
if (child.nodeName.toLowerCase()==parentTypeName) return child;
return getParent(child.parentNode, parentTypeName);
}

function getText(node) {
if(node.nodeType==3) {
return node.nodeValue;
} else if(node.nodeType==1) {
var children=node.childNodes;
var text="";
for(var ii=0; ii<children.length; ii++) {
text += getText(children[ii]);
}
return text;
}
}

return {
init:(function(container, board){
if (container && board) {
addListener(container, "onclick" ,makeClickListener(board));
}
})
};
})();


--- NavigationManager.html
<!DOCTYPE html>
<html>
<head>
<title>Navigation Manager Example</title>
<meta charset="UTF-8" />
<script type="text/javascript" src="NavigationManager.js"></script>
</head>
<body>
<ul id="menu">
<li><a href="#" target="main">clothing</a></li>
<li><a href="#" target="main">meats</a></li>
<li>
<a href="#" target="main">fruit</a>
<ul>
<li><a href="#" target="main">apples</a></li>
<li><a href="#" target="main">oranges</a></li>
</ul>
</li>
<li><a href="#" target="main">vegetables</a></li>
</ul>
<div id="messages" style="font-family: Courier New"></div>
<iframe name="main" width="500" height="300"></iframe>
<script type="text/javascript">
NavigationManager.init(
document.getElementById("menu"),
document.getElementById("messages")
);
</script>
</body>
</html>


HTH,
Elegie.
 
J

Jukka K. Korpela

Am 2011-06-17 13:03, Jukka K. Korpela meinte:

Natural?

Yes. If the purpose is to make different links react differently (though
perhaps by some pattern) to click events, why wouldn't you give each
link its own onclick handler (though perhaps different only by a
parameter value)?
I suppose event bubbling is there to avoid such things.

Why should they be avoided?
With
large enough menus you'd end up with dozens of (superfluous) listeners,
perhaps all of them leaking memory.

How much would that really matter? What kind of a modern computer would
choke on such a setup?
Depending on the actual markup one
listener attached to the top-level ul element addressing event.target
(or window.event.srcElement respectively) together with a check of the
nodeName of the reported element will suffice to get the proper
reference to the anchor.

There are different ways of course. The one I suggested appears to be
the most natural one and implementable rather simply.
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]>,
The following is an example that I just tested in FF 4.0.1 on ubuntu
11.04:
...
I make no claim for the support of document.activeElement in other
browsers, or older versions of firefox, or on other platforms.

FYI - Present in Win XP sp3 in
MS IE 8
Firefox 3.6.17
Opera 11.11
Safari 5.0.5
Chrome 12.0
as shown by <http://www.merlyn.demon.co.uk/js-props.htm#F>.

Optionally select the second of 7 checkboxes, and press the Enter
button. Double-click on it and press the Enter button to see the
properties of the Enter button. If instead you click in the white line
now containing "document.activeElement" you can see the properties of
that element. (That tried only in Firefox.)
 
G

Gregor Kofler

Am 2011-06-18 20:18, Jukka K. Korpela meinte:
2011-06-17 16:58, Gregor Kofler wrote:

How much would that really matter? What kind of a modern computer would
choke on such a setup?

Not the computer, but browsers and ultimately the OS. Particularly
Internet Explorers are infamous for their leaking with event listeners
under quite common setups.
There are different ways of course. The one I suggested appears to be
the most natural one and implementable rather simply.

With your approach you need some sort of loop for attaching the
listeners. With a top-level listener you need a loop in the listener -
as far as complexitiy goes, there's not much difference between those
approaches.

Gregor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,708
Latest member
SherleneF1

Latest Threads

Top