1

I am working on a simple example, if a user clicks on element then all the elements above it should have a class and all elements below it should not have any class applied to them.

Here is my code:

<script>
function test(object) {
    var pid = object.id;
    var id = parseInt(pid.split("")[1]);
    console.log(id);
    for (var i = 1; i <= id; i++) {
        var element = document.getElementById("p"+i);
        console.log(element);
        element.className = "active";
    }
    console.log(id+1);
    for(var i = id+1; i <= 4; i++) {
        var element = document.getElementById("p"+i);
        element.className.replace(new RegExp('(?:^|\\s)'+ 'active' + '(?:\\s|$)'), ' ');
        console.log(element);
    }
}   
</script>

<div id="divid">
    <p id="p1" onclick="test(this)">one</p>
    <p id="p2" onclick="test(this)">two</p>
    <p id="p3" onclick="test(this)">three</p>
    <p id="p4" onclick="test(this)">four</p>
</div>

So here if I click on three then the elements for one, two, three should have the class active and element four should not have any class. This is working fine.

Now if I click on one, I am expecting that two, three, four should have any css class but it is not working like that.

Can you please help me where is the issue. I want to use plain Javascript.

learner
  • 6,062
  • 14
  • 79
  • 139

4 Answers4

4

It might be wise to consider an alternative to using the onclick attribute due to separation of concerns. The following allows you to alter the HTML without having to consider JavaScript while you work.

https://jsfiddle.net/gseh0wxc/2/

var getList = (selector) => [].slice.call(document.querySelectorAll(selector));

var paragraphs = getList("#divid p[id ^= 'p']");
paragraphs.forEach((paragraph, index) => {
  paragraph.addEventListener('click', (e) => {
    for (let i = 0; i < index; i++) {
      paragraphs[i].classList.remove('active');
    }
    for (let i = index; i < paragraphs.length; i++) {
      paragraphs[i].classList.add('active');
    }
  });
})
zfrisch
  • 8,474
  • 1
  • 22
  • 34
  • This is really good, can you please explain what this code indicates? `var getList = (selector) => [].slice.call(document.querySelectorAll(selector));` – learner Jul 14 '17 at 20:19
  • 1
    It creates a function called getList that returns an array of elements that match whatever CSS selector you pass into it. The big thing is that it returns an Array of elements that you can actually manipulate. – zfrisch Jul 14 '17 at 20:24
  • interesting, I want to know more, can you please point me to some documentation of javascript that explains this feature, never saw this earlier. – learner Jul 14 '17 at 20:27
  • It's something you learn while you progress and it becomes incredibly useful. For more of an explanation of why it's used and useful take a look at this post: https://stackoverflow.com/questions/19099170/what-does-array-prototype-slice-call-wrapper-queryselectorall-do – zfrisch Jul 14 '17 at 20:28
  • This should be the accepted answer because it solves the problem and also improves the code quality, which is always good for SO. – Denialos Jul 14 '17 at 20:28
  • @zfrisch, I am not able to solve this using normal javascript code like using for loop, created another question for the same - https://stackoverflow.com/questions/45245952/issue-while-avoiding-foreach-loop – learner Jul 21 '17 at 20:09
1

Please try this code

function test(object) {
    var pid = object.id;
    var id = parseInt(pid.split("")[1]);
    console.log(id);
    for (var i = 1; i <= id; i++) {
        var element = document.getElementById("p"+i);
        element.classList.add("active");
    }
    console.log(id+1);
    for(var i = id+1; i <= 4; i++) {
        var element = document.getElementById("p"+i);
        element.classList.remove("active");
    }
}

Hope this helps.

smupyknight
  • 174
  • 10
  • I see like this `

    three

    ` is it possible to remove the class attribute itself so it looks like `

    three

    `
    – learner Jul 14 '17 at 19:55
  • 1
    Sure. You can use removeAttribute class. For example element.removeAttribute("class"); Then you'll get what you want. – smupyknight Jul 14 '17 at 19:57
  • Code only answers are less useful than those with explanations of exactly what code was added/removed. It would be even better if you'd add references where users could learn about the `classList` interface. – Heretic Monkey Jul 14 '17 at 20:27
1

try this simple approach instead, don't need to extract id number and all, and with a single simple loop.

function test(option) {
//this will select all p tags id starts with "p" inside div having id "divid" and return a array
var targetPTags = document.querySelectorAll("div#divid p[id^=p]")
var idx, flag=false;
    //we are iterating over that array and taking each dom element in el
    for(idx=0;idx<targetPTags.length;idx++) {
        var el = targetPTags[idx];
        if(flag) {
            //do operation you want for after elements in el
        } else if(option===el) {
            flag=true; // we are making flag true when its the element that clicked and doing no operation
            //do the operation you want for the element, may be the same as below operation in else
        } else {
            //do operation you want for before element in el
        }
    }
}
Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32
0

Kind of similar to "Chatterjee"'s solution, but here you go:

function test(object)
{
    var parentElem = null;
    var childElems = null;
    var currElemSet = false;
    var i=-1;

    try
    {
        parentElem = object.parentElement;

        if(parentElem!=null)
        {
            childElems=parentElem.getElementsByTagName(object.nodeName); // could refine to accommodate sibling nodes only
            if(childElems!=null)
            {
                for(i=0;i<childElems.length; i++)
                {
                    if(currElemSet) childElems[i].className = "";
                    else childElems[i].className = "active";

                    if(childElems[i]==object) currElemSet = true;
                }
            }

        }
    }
    catch(e)
    {
        alert("Error:  " + e.Message);
    }
    finally
    {

    }

}