Divide the elements of the array separated by white space into individual components within the array

Scenario

I am in the process of creating a basic webpage that will allow me to showcase and filter bookmarks. Each bookmark can be associated with multiple tags, and tags may be duplicated across different bookmarks. The tags for each bookmark are stored in a data attribute within the wrapper element for that bookmark (as shown below). My ultimate objective is to dynamically generate a menu containing all the tags present on the page and toggle their visibility based on user selections. I am keen on keeping this project simple and self-contained, so I prefer solutions using pure JavaScript over external libraries.

Issue

Currently, my main challenge lies in generating a comprehensive array of tags. While I have successfully filtered out undefined elements (when a bookmark has no tags) and removed duplicate tags, I am struggling when it comes to handling bookmarks with multiple tags. Since a data attribute can only be used once per element, all tags for a single bookmark need to be stored as a list within the data attribute.

My goal is to split multiple tags from a singular data attribute entry into separate elements within the array for every bookmark with more than one tag.

For reference, consider the "data-tags" attribute in the <article> element:

<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="Tag-One Tag-Two">
    <section class="item">Bookmark Description</section>
    <section class="tags">
        <a href="#" class="tag">Tag-One</a>
        <a href="#" class="tag">Tag-Two</a>
    </section>
</article>

The first part of my script is functional:

const notes = document.querySelectorAll('.note');
let tags = [];
// extract tags
notes.forEach(note => tags.push(note.dataset.tags));
//Resulting array format: tags[] = ("Tag-One Tag-Two")
//remove duplicates
tags = tags.filter((value,index,array) => array.indexOf(value) == index);
//remove undefined values
tags = tags.filter(tag => tag !== undefined);

However, the following section poses challenges. Despite attempting various looping techniques, the utilization of splice() does not yield the expected results - often leading to premature trimming of the array:

for (let index = 0; index < tags.length; index++) {
   var value = tags[index];
   if (value.indexOf(' ') > 0 ){
     var newTags = value.split(' ');
     newTags.forEach(newTag => tags.push(newTag));
     tags.splice(index,1);
   }
 }

Any assistance offered would be greatly valued. Feel free to critique the initial code as well!

Answer №1

Retrieve all elements containing data-tags by using the attribute selector [data-tags]. Transform them into an array with Array.from() and map them to extract tags. Flatten the array of arrays by separating the tags string, then eliminate any empty tags. Utilize a Set to remove duplicates, and convert it back to an array either with Array.from() or array spread.

const notes = document.querySelectorAll('[data-tags]');

const tags = Array.from(
  new Set(
    Array.from(notes, note => note.dataset.tags.split(/\s+/g))
      .flat()
      .filter(Boolean)
  )
)

console.log(tags)
<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="Tag-One Tag-Two">
</article>

<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="Tag-Two">
</article>

<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="">
</article>

<article class="note"
    data-date="2021-08-04T03:40">
</article>

To correct your code, only add tags if they exist, split the tags, and use array spread to append multiple items to the array instead of creating sub-arrays:

const notes = document.querySelectorAll('.note');
let tags = [];
// get tags
notes.forEach(note => 
  note.dataset.tags && tags.push(...note.dataset.tags.split(/\s/g))
);
//Will look like this: tags[] = ("Tag-One Tag-Two")
//remove dupes
tags = tags.filter((value,index,array) => array.indexOf(value) == index);

//no need to filter empties

console.log(tags);
<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="Tag-One Tag-Two">
</article>

<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="Tag-Two">
</article>

<article class="note"
    data-date="2021-08-04T03:40"
    data-tags="">
</article>

<article class="note"
    data-date="2021-08-04T03:40">
</article>

Answer №2

To retrieve all the tags, you can extract them, split by spaces, filter out falsey values, and then utilize a Set to obtain unique tags.

const notes = document.querySelectorAll('.note');
const tags = [...new Set(
  [...notes]
    .flatMap(note => note.dataset.tags.split(/\s+/g))
    .filter(Boolean)
 )];
console.log(tags);
<article class="note" data-date="2021-08-04T03:40" data-tags="Tag-One Tag-Two">
  <section class="item">Bookmark Description</section>
  <section class="tags">
    <a href="#" class="tag">Tag-One</a>
    <a href="#" class="tag">Tag-Two</a>
  </section>
</article>
<article class="note" data-date="2021-08-04T03:40" data-tags="Tag-three Tag-Two">
  <section class="item">Bookmark Description</section>
  <section class="tags">
    <a href="#" class="tag">Tag-One</a>
    <a href="#" class="tag">Tag-Two</a>
  </section>
</article>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The command "npm run build:css " is not functioning properly, but when I execute the script independently, it works fine

Recently, while working on a program using npm script on my Mac system, I encountered some issues. Despite having installed node-sass globally, running "npm run build:css" did not work as expected. The content of my package.json file can be viewed here. Th ...

How to incorporate both image and text links within an HTML div container using JavaScript

I am trying to create a clickable image and text within a div named "films" that both link to the same webpage. However, I am experiencing an issue where only the text link works and the image link is disabled. If I remove the text link, then the image l ...

`Is it possible to retrieve Wikipedia information directly from a Wikipedia link?`

Is there a way to create a feature where users can input a Wikipedia page link and retrieve all the text from that page? I am working on adding a functionality to my website where users can paste a link to a Wikipedia page they want to analyze into an inp ...

Tips for showcasing a "loading" animation as a lazy-loaded route component loads

Utilizing webpack's code splitting feature, I have divided my application into multiple chunks to prevent the entire bundle from being downloaded at once when a user visits my website. Some routes require large chunks that may take some time to downl ...

AJAX requires manual updating by clicking on a button

I've created a chat system where two individuals can communicate with each other. An AJAX function has been implemented to update the message container every 2 seconds. However, I have noticed that the AJAX call doesn't run immediately after a u ...

Load the content of the dialog and transfer variables

After struggling for days, I am still unable to find a solution to my current dilemma. In my database, there are approximately 1300 items each with its own unique "id", a corresponding "name", and a property called "enabled". My goal is to display links t ...

Tips for adding a border to a 3D pie chart in Highcharts

I created a 3D pie chart using the Highchart plugin and wanted to add borders to each portion. I tried adding the following code: borderWidth: 4, borderColor: "red" within the plotOptions: pie: section. However, I noticed that the portions were getting b ...

Rotating an SVG shape a full 360 degrees results in no visible change

Currently, I am utilizing d3.js for a project and encountering an issue with rotating an SVG element 360 degrees to achieve a full spin back to its original position. If I rotate the element 3/4 of the way using the following code snippet, it works effect ...

Modify the Div background color by accessing the HEX value saved in a JSON file

(I made a change to my code and removed the br tag from info2) Currently, I have successfully implemented a feature using jQuery that reads color names and hex values from a JSON file, populates them in a drop-down select menu (which is working fine). Now ...

Using jQuery .animate() leading to erratic input movements

I am currently utilizing jQuery's .animate() feature to create a smooth animation effect on the width of a <div> element when a child <input> is in focus. Nevertheless, I'm encountering an issue where the input field jumps up and down ...

Retrieving information from a separate JavaScript file

I'm currently developing a Discord Bot and my code is all contained within one file. My goal now is to break this code up into multiple files for better organization. For instance, I plan to have: index.js which will handle all the requires (e.g. var ...

Incorporate an image into a div element with the power of jQuery

As the user scrolls down the page, a sticky menu or floater bar appears. With the help of jQuery, I am able to apply the floater-bar class to the #menu-wrapper. My objective is to also insert an image inside an anchor tag at the same time the floater-bar ...

Engage with Vue.js and traditional JavaScript (plain) in your projects

Exploring the integration of Vue with regular JavaScript has presented a challenge. While some solutions online propose moving all functions to a Vue component, this approach proves impractical for complex or large functions. The task now is finding a way ...

"Adding content to the DOM using AJAX, the data is showing up as plain text rather than formatted

As part of my project, I am working on incorporating data retrieved through an AJAX request into the DOM to be able to manipulate it further. However, I encountered an issue where the data displayed as a string instead of HTML when appended to the DOM. Bel ...

Issues arise when Angular Meteor fails to load the UI-Router properly

Currently, I am exploring the integration of ui-router for routing within a meteor-angular application. My reference point is the meteor Whatsapp tutorial which can be found here Below is the relevant code snippet related to ui-router implementation: log ...

AngularJS checkbox validation requires a minimum of two checkboxes to be selected

When using AngularJS, I am looking to create a validation rule where a minimum of 2 checkboxes must be checked for the input to be considered valid. Here is what I have attempted: <div ng-repeat="item in items"> <label><input type="chec ...

Retrieve a collection containing all the variables that have been defined

I am attempting to gather all PHP defined variables and store them in an array. Previously, I tried: $myArr = get_defined_vars(); var_dump($myArr); The result was: array(4) { ["_GET"]=> array(0) { } ["_POST"]=> array(0) { } ["_COOKIE"]=> array ...

What steps should I take to fix the error "Unused left side of comma operator with no side effects.ts(2695)" in my React project?

import React from "react"; import { useRecoilState } from "recoil"; import { Industry, industryState } from "../atoms/industriesAtoms"; const manageIndustryData = () => { const [industryStateValue, setIndustryStateValue] ...

Maintain your position on the current page when refreshing Angular 4

My Anuglar 4 application features multiple routes, with two main ones being Logging and List of items. Specifically, the routes are http://localhost:4200/#/ and http://localhost:4200/#/items. However, I've noticed that when I reload the page while on ...

Arranging numerous items based on date in JavaScript without prior knowledge

I'm facing an issue where I need to showcase JSON data containing events but want them sorted by time. The challenge is that the number of objects in the JSON can vary as users can keep adding more. Below is my code snippet demonstrating how the displ ...