2

Let's say we have a unordered list with a class:

    <ul class="list-class">
        <li><a href="#">All</a></li>
        <li><a href="#">Breakfast</a></li>
        <li><a href="#">Lunch</a></li>
        <li><a href="#">Dinner</a></li>
        <li><a href="#">Snack</a></li>
   </ul>

Let's say now I wanted to create some function that does different things based on which item has been clicked on:

function whichElement() {
    alert("The -- Link has been clicked");
}

How can this be done without creating a separate function for each item and writing an inline onclick="" event? I'm open to using jQuery as well.

Arun
  • 626
  • 10
  • 29

8 Answers8

1

How about this if I understand correctly:

var items = document.querySelectorAll('.list-class li');

[].forEach.call(items, function(item){

  var text = item.textContent.trim().toLowerCase();

  item.addEventListener('click', function(){
    if (text == 'all') {
      //...
    }
    //...
  });
});
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Would be worth mentioning that some of these methods require a modern browser, or the methods require shimming. i.e. `querySelectorAll`, `forEach`, `textContent`, `trim` and `addEventListener`, current codes requires IE9+ but +1 for POJS solution. – Xotic750 Jun 25 '13 at 08:33
  • `[].forEach.call` will create an empty `Array` in the memory while `Array.prototype.foreach.call` doesn't. – The Alpha Jun 25 '13 at 18:57
1

You may try this

function addEvent(elem, event, fn)
{
    if (elem.addEventListener)
    {
        elem.addEventListener(event, fn, false);
    }
    else
    {
        elem.attachEvent("on" + event, function() {
            return(fn.call(elem, window.event));   
        });
    }
}

addEvent(window, 'load', function(e){
    var list = document.querySelector('.list-class');
    addEvent(list, 'click',  function(e){
         e = e || window.event;
         var el = e.target || e.srcElement;
         alert(el.innerHTML);
    });
});

DEMO.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • I'm not sure why you only went half way with your cross-browser POJS solution? You created a cross-browser `addEvent` but then you use ´querySelector´ which requires IE8+. Still, +1 for a POJS solution. – Xotic750 Jun 25 '13 at 08:37
  • Yes, I mentioned that it is IE8+ – Xotic750 Jun 25 '13 at 08:46
0

Add a click handler to the ul, something like:

$('.list-class').on(
  'click',
   function(e){
     e = e || event;
     var from = e.target || e.srcElement;
     if (/^a$/i.test(from.tagName)){
        alert('you clicked '+from.innerHTML);
     }
   });

See this jsFiddle

KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • Would it not have been better to use jquery's event delegation instead of testing for the tag and why not a simple `from.tagName === "a"` instead of regex `test`? – Xotic750 Jun 25 '13 at 09:41
  • Maybe, but what do you know - this *is* event delegation. JQuery will use the same mechanics internally. `test`: some browsers report 'A', others 'a' for the tagname, so test is a bit shorter compared to `from.tagName === "a" || from.tagName === "A"`. – KooiInc Jun 25 '13 at 17:21
  • Perhaps I didn't explain myself so well, yes you have a form of "direct delegation", see [jquery on event delegation](http://api.jquery.com/on/). jquery should also take care of the `e || event` and `target || srcElement` for you by ["normalisation"](http://api.jquery.com/category/events/event-object/) and hence are unnecessary. Then regarding [`tagName`](http://ejohn.org/blog/nodename-case-sensitivity/) by John Resig himself. Gives you final code in jquery as per this [jsfiddle](http://jsfiddle.net/Xotic750/buYp8/). This is what I was trying to convey. – Xotic750 Jun 25 '13 at 18:26
0

Do a Jquery Trick as

$("#list-class li").click(function() {
    alert($(this).prevAll().length+1);
});

Here is the FIDDLE

Usman
  • 3,200
  • 3
  • 28
  • 47
0

EDIT: event.target returns DOM element that initiated the event.

$('.list-class').click(function(e){  
   alert(e.target.nodeName);
});

Check this in JSFiddle

Praveen
  • 55,303
  • 33
  • 133
  • 164
  • With this, I could of course click on an `li` element and not specifically the contained `a` element and it would fire the alert. – Xotic750 Jun 25 '13 at 09:38
0

You can do it in POJS like so, this should be cross-browser compatible and doesn't use any 3rd party libraries. Other advantage is that there is only one event listener per element of the named class, uses event propagation.

Javacsript

/*jslint maxerr: 50, indent: 4, browser: true */
/*global alert */

(function () {
    "use strict";

    function addEvent(elem, event, fn) {
        if (typeof elem === "string") {
            elem = document.getElementById(elem);
        }

        function listenHandler(e) {
            var ret = fn.apply(null, arguments);

            if (ret === false) {
                e.stopPropagation();
                e.preventDefault();
            }

            return ret;
        }

        function attachHandler() {
            window.event.target = window.event.srcElement;

            var ret = fn.call(elem, window.event);

            if (ret === false) {
                window.event.returnValue = false;
                window.event.cancelBubble = true;
            }

            return ret;
        }

        if (elem.addEventListener) {
            elem.addEventListener(event, listenHandler, false);
        } else {
            elem.attachEvent("on" + event, attachHandler);
        }
    }

    function whichElement(e) {
        var target = e.target;

        if (target.tagName === "A" && target.parentElement.tagName === "LI" && target.parentElement.parentElement.className === "list-class") {
            alert("The " + target.firstChild.nodeValue + " Link has been clicked");
        }
    }

    addEvent(document.body, "click", whichElement);
}());

On jsfiddle

If you were using some newer/custom HTML tags or XML then you may need to consider tagName case sensitivity, and write the following to be certain.

if (target.tagName.toUpperCase() === "A" && target.parentElement.tagName.toUpperCase() === "LI" && target.parentElement.parentElement.className === "list-class") {

In jquery terms the above could be written as

Javascript

$(document).on('click', '.list-class>li>a', function (e) {
    alert("The " + e.target.firstChild.nodeValue + " Link has been clicked");
});

On jsfiddle

In jquery they call this event delegation.

Xotic750
  • 22,914
  • 8
  • 57
  • 79
  • Understood, of course if you keep your own library of functions then jquery becomes pretty redundant, and you demystify the hidden magic. :) – Xotic750 Jun 25 '13 at 09:24
  • 1
    Oh yeah I'm not one of those people that doesn't understand that jQuery is just a JS library. It just makes some stuff really easy to write! Good answer though btw! Nice to see some POJS – El Ronnoco Jun 25 '13 at 09:30
  • Probably not. My pet hate (one of) – El Ronnoco Jun 26 '13 at 10:30
0
<ul class="list-class">
        <li><a href="#" id="hrefID1">All</a></li>
        <li><a href="#" id="hrefID2">Breakfast</a></li>
        <li><a href="#" id="hrefID3">Lunch</a></li>        
   </ul>
 <script>
$(".list-class li").find('a').each(function(){
    $(this).click(function(){
        switch($(this).attr('id'))
        {
            case "hrefID1";
                    //do what ever 
                    break;
            case "hrefID2";
                    //do what ever 
                    break;
            case "hrefID3";
                    //do what ever 
                    break;
        }
    });
});
</script>
Manish Parmar
  • 859
  • 1
  • 11
  • 19
0

Not to jump on the bandwagon as this is similar to others (but not quite)...

$('.list-class>li').on('click',
   function(){
      alert('clicked ' + $('a',this)[0].innerHTML); //eg "clicked Lunch" etc
   }
);

http://jsfiddle.net/znySy/

This simply alerts the text of the link clicked, but equally within the function you could switch on the text eg...

function(){
    switch ($('a',this)[0].innerHTML) {
        case 'Lunch'     : // do something for Lunch
        case 'Breakfast' : // do something for Breakfast
        default          : // do something for not Lunch or Breakfast
    }
}
El Ronnoco
  • 11,753
  • 5
  • 38
  • 65