[Need help with some JavaScript] I'm using some script to display tags in the Back side of my cards along with the .replace() method to hide some of them. It works, but its container is still showing. How to fix it?

Hi, everybody!

I’ve been looking for posts and tutorials on how to fix it since yesterday but I didn’t find anything.

So, I hope some of you guys can help me getting this done. I’ll try to explain what I want objectively, but if you need more information, please ask me.

Here we go:

Let’s say I’ve got a card with the following tags …

image

…and I want to display some of them in the Back side but hide others. So I use the .replace() method to hide those I don’t want to display (in this exemple, it was ::is_a and DELTA::is_d).

This is what I got:

image

But this is what I want:

image

This is the script I’m using to display the tags:

<div id="tags-container"></div>

<script>
//Vars
var tagsPresent = false;
var tags;
var tagContent = "{{Tags}}";
// Place all specified tag colors here
var tagMap = [
  // "fallback" should be set to desired default color
  fallback = {
    name: "",
    color: ""
  },
];

//Calls
tags = searchTags();
checkTags(tags);

// Functions

//Find out if tags are there or not, and if so split at each word
function searchTags(){
  //Check if there are any tags
  if (tagContent == null || tagContent === ""){
    tagsPresent = false;
  } else {
    // Check if there is more than one tag
    if (tagContent.search(" ") >= 1){
      tagsPresent = true;
      tags = tagContent.split(" ");
    } else {
      tagsPresent = true;
      var tags = [tagContent];
    }
  }
  return tags;
}

// Loop through all tags in array and create a new div for each w/ respective color
function checkTags(tags){
  if (tagsPresent) {
    addTags(tags);
  } else {
    console.log("tags are not present");
  }
}

function addTags(tags){
  for (var i in tags) {
  var newDiv = document.createElement("div");
  newDiv.id = "tag";
  newDiv.innerHTML = tags[i];
  newDiv.style.display = "inline-block";

  // Choose background fill
  newDiv.style.backgroundColor = determineTagColor(tags[i]);

  //Choose outline
  newDiv.style.border = "1px solid" + determineTagColor(tags[i]);

  document.getElementById("tags-container").appendChild(newDiv);

  }
}

// Determine Tag Color by running through each tag
function determineTagColor(tag) {
  for (var i = 0; i < tagMap.length; i++){
    if (tagMap[i].name === tag){
      return tagMap[i].color;
    }
  }
  return tagMap[0].color;
}

</script>

This is the script I’m using to replace the tags and “_” with white space:

<script>
q = document.getElementById("tags-container");
q.innerHTML = q.innerHTML.replace(/\b(DELTA::is_d|::a)\b/g, ' ').replace(/\_/g, ' ');
</script>

This is the CSS for the tags:

<style>
#tag {
display: inline-block;
color: rgba(0,0,0, 0.65);
font-weight: 700;
background-color: #f0f0f0;
opacity: 1;
padding: .01em .3rem .1em .3rem;
border: solid .04rem;
border-radius: 0.1rem;
box-shadow: rgba(60, 64, 67, 0.03) 0px 1px 2px 2px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
font-size: .7rem;
}
</style>

Can you help me with that?

I simplified your code a bit. I recommend you do the following:

Add this element to your template:

<div id="tags" hidden>{{Tags}}</div>

This is best practice to get field/tag content, because it prevents issues with quotes.

Replace your script with the following


// Place all specified tag colors here
var tagMap = [
    {
        name: "test",
        color: "red",
    }
]

function addTags() {
    var container = document.getElementById("tags-container")
    var tags = document.getElementById("tags").innerText.split(" ")

    tags.forEach((tag) => {
        node = document.createElement("div")
        node.classList.add("tag")
        node.innerHTML = tag.replace("_", " ")
        if ((color = tagColor(tag)) != null) node.style.color = color
        container.appendChild(node)
    })
}

// Determine Tag Color by running through each tag
function tagColor(tag) {
    for (entry of tagMap) {
        // remove .toLowerCase() if you want it to be case-sensitive
        if (entry.name == tag.toLowerCase()) {
            return entry.color
        }
    }
}

addTags()

Add this to your Styling section:

.tag {
  display: inline-block;
  color: rgba(0,0,0, 0.65);
  font-weight: 700;
  background-color: #f0f0f0;
  opacity: 1;
  padding: .01em .3rem .1em .3rem;
  border: solid .04rem;
  border-radius: 0.1rem;
  box-shadow: rgba(60, 64, 67, 0.03) 0px 1px 2px 2px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
  font-size: .7rem;
}

I made it case-insensitive because I thought that might be helpful. But you can of course remove that feature as seen in the comment within determineTagColor.

Edit: Actually, now that I think about it, you don’t even need the fallback, because you already define a default color in CSS.

I edited my code accordingly.

1 Like

Hi, @kleinerpirat

Thank you for your help. It was very useful as always!

I appreciate the way you simplified the code. This script of yours make the process of replacing tags easier.

I followed your recommendations but, whenever I replace an entire tag with white space, there’s still some black line showing (see the exemple below)

node.innerHTML = tag.replace("_", " ").replace("ALPHA::is a", " ").replace("BETA::is b", " ").replace("DELTA::is d", " ")

image

I tried to fix it by changing the CSS values, then I noticed (by increasing the padding) that the black line I want to hide is, in fact, the container for each tag I replaced with white space.
image

So, If I understood it correctly, what your script does is: get the content of {{Tags}}, slice it, put each tag between <div></div>, attribute the <div> a class named tag and return the tags. Meanwhile, the .replace() method destroys the content between <div></div> and put something else there (in my case, white space), right?

In this case, if I’m getting things correctly, are there a way of making the <div></div> hidden if there’s nothing (or white space) between it? (I did some research and found this, but I don’t know how to make it work in this code of yours).

The result should look like this:
image

That’s correct, with your replace function you’re only deleting the inner HTML of the nodes, but they still get created and appended to the container - just empty.

Surely there is a better way to hide tags than with string replacement. What exactly is the use case here?

It seems like you want to hardcode some tags into your script which should never be displayed on the backside. You could create a list similar to that tagMap for the colors, but in this case for the tags you don’t want to show up.

Then prevent the creation of the nodes like that:

function addTags() {
    var hiddenTags = ["ALPHA::is_a", "BETA::is_b"]
    var container = document.getElementById("tags-container")
    var tags = document.getElementById("tags").innerText.split(" ")

    tags.forEach((tag) => {
        if (!hiddenTags.includes(tag)) {
            node = document.createElement("div")
            node.classList.add("tag")
            node.innerHTML = tag.replace("_", " ")
            if ((color = tagColor(tag)) != null) node.style.color = color
            container.appendChild(node)
        }
    })
}

But I’m afraid I still don’t get why you’re doing this in the first place. Would you mind elaborating on the use case a bit? Do you want to hide the ::is_xxx part? Then I would look towards Regular expressions - JavaScript | MDN.

1 Like

Yes, you’re right.

This seems to be exactly what I want to do.

I just tried it and it worked as I needed. That’s great!

Sure.
I’ve been building a huge list of hierarchical tags these days (think about a syllabus or a table of contents, but for at least 10 courses or books) that I intend to use to identify the subject related to each card. So, I want to display the tag (or tags) of this list in the Back side of my cards.

However, I also have another uncorrelated set of tags (a way smaller quantity than the first one) that I never want to be displayed in the Back side.

So, to put it in a simple way, what I intend to do is, whenever I have a card with tags of the first kind (the ones in the huge list) I want them to be displayed, but if there’s a tag of the second kind in the card, I don’t want this particular tag (or tags) to be displayed.

Yes, I think I’ll hide the 1st level of the hierarchy and display just the sub tags, but it depends on how the final set of lists is organized.

I just tried to do it by both the .replace() method and by bringing it to the list of hiddenTags you created, but only the first approach worked, which I think is enough for me, as the <div></div> still have some text in between.

1 Like