0

I'm trying to get the focus method (touch, mouse or keyboard) on links setting a data-attribute.

$(function() {
    var i,
        r = document.getElementsByTagName("a")[0];

    if ("ontouchstart" in window) {
        document.addEventListener("touchstart", function(event) {
            i = "touch";
        }, true);
    }
    else {
        document.addEventListener("mousedown", function(event) {
            i = "mouse";
        }, true);
    }
    document.addEventListener("keydown", function(event) {
        i = "keyboard";
    }, true);
})

The problem is that I only get results writing the last part in jQuery:

    $("a").focus(function() {
        $(this).attr("data-focus-method", i)
    })
    $("a").blur(function() {
        $(this).removeAttr("data-focus-method")
    })

And I want to write the whole code in plain JavaScript. I've tried the way below:

    r.addEventListener("focus", function() {
        r.setAttribute("data-focus-method", i);
    });
    r.addEventListener("blur", function() {
        r.removeAttribute("data-focus-method");
    });

But it doesn't work. Can somebody help me please?

7
  • 2
    Is the code here the same as your actual code? This line appears suspect r = document.getElementsByTagName("a")[0] when you mention "on links" - ie your text implies multiple/all links but your code indicates first link (which is a bit strange in itself). If you actually have something like for (var idx in document.getElementsByTagName("a")) { var r = document.getElementsByTagName("a")[idx] then that's your problem - r will have changed by the time it hits the event listener, hence the use of this. Commented Jan 21, 2020 at 14:32
  • @freedomn-m the problem is that when I remove the [0] I get the "r.addEventListener is not a function" error message. Commented Jan 21, 2020 at 14:44
  • Your code works just fine. Commented Jan 21, 2020 at 14:45
  • @ArthurOtaviano That's because getElementsByTagName() returns a nodeList which you need to iterate through and call addEventListener on each individual element Commented Jan 21, 2020 at 14:47
  • It's not about removing the [0] - it's more that does your real code use [i] (or similar)? Commented Jan 21, 2020 at 14:56

3 Answers 3

1

I suggest to use querySelectorAll method and use forEach to iterate the nodelist

document.querySelectorAll("a").forEach((link) => {
  link.addEventListener("focus", function() {
    this.setAttribute("data-focus-method", i);
  });
  link.addEventListener("blur", function() {
    this.removeAttribute("data-focus-method");
  });
});
Sign up to request clarification or add additional context in comments.

2 Comments

Does using setAttribute work to set data attributes? I've always used el.dataset to do that.
@YaakovAinspan Yes, it does
0

I'm not sure why you're trying to override the i on method whenever a key is pressed on the keyboard. However, I'm assuming that's the desired effect since you don't mention it in your question.

That said, here's something to get you closer to your goal of a vanilla JS version of the code.

The answer uses the spread operator to convert the nodeList you get from getElementsByTagName to an array and then forEach() to loop through the array items. For each item, we add two event listeners. one for focus, and one for blur.

When focused, we add the attribute. When blurred we remove the attribute. I opted for set attribute and remove attribute, but you can also use dataset if you want.

To determine what i (the method) is, I used let and a ternary operator.

I'm still not sure why you want to override the method when a key is pressed on the keyboard so I left that. I can improve that if you let me know what the desired effect is.

let i = ("ontouchstart" in window) ? "touch" : "mouse";

document.addEventListener("keydown", () => {
  i = "keyboard"
})

const links = [...document.getElementsByTagName("a")];

links.forEach(link => {
  link.addEventListener("focus", () => {
    link.setAttribute('data-focus-method', i);
  });
  link.addEventListener("blur", () => {
    link.removeAttribute('data-focus-method');
  })
})
<a href="#">My link 1</a>
<a href="#">My link 2</a>
<a href="#">My link 3</a>

Comments

0

I got the solution adding:

    var w;
    for (w = 0; w < r.length; w++) {
        r[w].addEventListener("focus", function() {
            this.setAttribute("data-focus-method", i);
        });

        r[w].addEventListener("blur", function() {
            this.removeAttribute("data-focus-method");
        });
    }

By the way, thanks for everyone who helped me!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.