Convert the text inside a span element into a key-value object in JavaScript

How can I extract and save the text from a span element as key value pairs within a div?

<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a">ADDITIONAL_WRK</span>

      <span class="sp3-tag sp3-intent-danger">
        <span class="sp3-text-overflow-ellipsis sp3-fill">DECIMAL</span>
      </span>
    </div>
  </div>
</div>

<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a"> AFFECTMRAPPLIC</span>

      <span class="sp3-tag sp3-intent-danger">
        <span class="sp3-text-overflow-ellipsis sp3-fill"> DECIMAL</span>
      </span>
    </div>
  </div>
</div>

<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a">APPROVED_ON</span>

      <span class="sp3-tag sp3-intent-danger">
        <span class="sp3-text-overflow-ellipsis sp3-fill">TIMESTAMP</span>
      </span>
    </div>
  </div>
</div>

<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a">COMPOSITE</span>
    </div>
  </div>
</div>

To individually access them, you can use the following:

// First span
var firstSpan= document.getElementsByClassName( 'data-diff-basic__class-name__4ngp30a' )
var firstSpanArray = [];
for ( var i = 0; i < firstSpan.length; ++i ) {
    firstSpanArray.push( firstSpan[i].innerText );
}

// Second span
var secondSpan= document.getElementsByClassName( 'sp3-text-overflow-ellipsis sp3-fill' )
var secondSpanArray = [];
for ( var i = 0; i < secondSpan.length; ++i ) {
    secondSpanArray.push( secondSpan[i].innerText);
}

Now, I want to combine firstSpanArray and secondSpanArray using their index into a key value JavaScript object. However, some spans may not have a corresponding second span, leading to an index mismatch.

Can anyone help me modify this query to achieve the following result:

spanCollection = {
  "ADDITIONAL_WRK":"DECIMAL",
  "AFFECTMRAPPLIC":"DECIMAL", 
  "APPROVED_ON":"TIMESTAMP",
  "COMPOSITE":""
}

Answer №1

To achieve this, you can select the second div in the first loop by checking with the parent element if it exists. If there is no parent (result 'null'), then set the value to an empty string.

Here's a working example:

var firstSpan = document.getElementsByClassName('data-diff-basic__class-name__4ngp30a');
var spanCollection = {};

for (var i = 0; i < firstSpan.length; ++i) {
  var value_span = firstSpan[i].parentNode.querySelector('.sp3-text-overflow-ellipsis.sp3-fill');
  var span_value = value_span ? value_span.innerText : '';
  var span_key = firstSpan[i].innerText;
  spanCollection[span_key] = span_value;
}

console.log(spanCollection);
[...]

Answer №2

There are multiple ways to accomplish the task at hand.

One method is to use a reduce based approach, where you iterate through an array of nodes obtained from a queried NodeList with each node belonging to the class

.data-diff-basic__class-name__4ngp30a
, these nodes contain the key-name information.

During each iteration step, you would...

  • Retrieve the key-name from the current node being processed.

    const key = keyNode.textContent.trim();
    
  • Fetch the corresponding value-containing node related to each key-containing node. If the value data exists, extract it. Otherwise, default to an empty string. To do this, you can use a combination of Element::querySelector and the optional chaining operator / ?.

    const value = keyNode.parentNode.querySelector('.sp3-fill')?.textContent.trim() || '';
    

Throughout the entire reduce process, you would aggregate key-value pairs into an initially empty object using Object.assign. The return value of the reducer function would be this object containing the aggregated key-value pairs...

const spanCollection = [
  ...document.querySelectorAll('.data-diff-basic__class-name__4ngp30a')
]
.reduce((result, keyNode) => {

  const key = keyNode
    .textContent.trim();
  const value = keyNode
    .parentNode.querySelector('.sp3-fill')?.textContent.trim() || '';

  return Object.assign(result, { [ key ]: value });

}, {});

console.log({ spanCollection });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a">ADDITIONAL_WRK</span>

      <span class="sp3-tag sp3-intent-danger">
        <span class="sp3-text-overflow-ellipsis sp3-fill">DECIMAL</span>
      </span>
    </div>
  </div>
</div>

... (additional HTML code follows) ...

</div>

Another approach could also utilize reduce, but in this case, the data to be reduced is an array of nodes where the text content of each node contains the complete key-value data as a single string after trimming, in the form...

'a_one_word_key     and a lot of value data'

Taking this example value, split using a regex like ...

'a_one_word_key     and a lot of value data'.split(/(\s+)/);

... which preserves the whitespace sequences during splitting, resulting in an array like...

['a_one_word_key', '     ', 'and', ' ', 'a', ' ', 'lot', ' ', 'of', ' ', 'value', ' ', 'data']

By utilizing array destructuring, one can access the necessary key-value data as follows...

const [key, _, ...valueData] = keyValueNode.textContent.trim().split(/(\s+)/);

The variable key will always exist, the underscore represents the optional first split whitespace sequence that is not needed. The valueData array, accessed using the rest property syntax, will default to an empty array regardless of the source data, ensuring defined key-value pairs.

In the object aggregation process similar to the first reduce example, you would now do...

Object.assign(result, { [ key ]: valueData.join('') });

The full example code for this second solution looks as follows...

const spanCollection = [
  ...document.querySelectorAll('.data-diff-basic__class-header__4ngp30a')
]
.reduce((result, keyValueNode) => {

  const [key, _, ...valueData] = keyValueNode.textContent.trim().split(/(\s+)/);

  return Object.assign(result, { [ key ]: valueData.join('') });

}, {});

console.log({ spanCollection });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<div class="data-diff-span__composite-list-item__18c5zip data-diff-core__highlight-area__19c0zip">
  <div class="data-diff-basic__class-row__4ngp30a">
    <div class="data-diff-basic__class-header__4ngp30a">
      <span class="data-diff-basic__class-name__4ngp30a">ADDITIONAL_WRK</span>

      <span class="sp3-tag sp3-intent-danger">
        <span class="sp3-text-overflow-ellipsis sp3-fill">DECIMAL</span>
      </span>
    </div>
  </div>
</div>

... (more HTML code here) ...

</div>

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

Node.js for Streaming Videos

I am currently working on streaming video using node.js and I recently came across this helpful article. The setup works perfectly when streaming from a local source, but now I need to stream the video from a web source. However, my specific requirement i ...

The formatter/render function in Angular Directive fails to refresh

Recently, I created a straightforward directive that converts minutes into a range slider while also displaying hours and minutes alongside. However, I encountered an issue where although moving the range slider updates the scope triggering Watch and Pars ...

Having trouble retrieving the $scope value in HTML, even though it was assigned within the success function of $http.post

Having trouble accessing the values of $scope properties after a successful $http post in index.html file. Here is the code snippet for reference, any help in resolving this issue would be greatly appreciated as I am new to AngularJs var app = angular.m ...

Unable to display MongoDB collection in React application

I've been working on showcasing my projects using React and Meteor. I have two collections, Resolutions and Projects. The issue I'm facing is that while I can successfully display the Resolution collection on the frontend, I'm struggling to ...

Mongoose search operation coming up with a blank array

Whenever I utilize $search in mongoose, it returns an empty array. Data Model const mongoose = require('mongoose'); const studentSchema = new mongoose.Schema({ name: { type: String }, }); studentSchema.index({ name: 'text' }); con ...

How to use jQuery to set a background image using CSS

I've been working on setting backgrounds dynamically with a jQuery script, but it seems like the .css function is not working as expected. Here's the code snippet: $(document).ready(function () { $(".VociMenuSportG").each(function () { ...

Dealing with event delegation on elements that are not nested

Working with Bootstrap group radio buttons where I need to implement event delegation. <div class="btn-group" role="group" aria-label="Basic radio toggle button group"> <input type="radio" class="btn- ...

Searching in the Kendo Dropdown List using text and value

$(document).ready(function() { $("#selection").kendoDropDownList({ filter: "startswith", dataTextField: "SelectionName", dataValueField: "SelectionID", dataSour ...

Retrieve a specified child object within its parent object using a string identifier

I have a situation where I need to create a JavaScript function that can extract a child object from a parent object based on a specific string identifier. Here is an example of what I'm looking for: function findChild(parent, name) { return par ...

Ways to transfer information from the Component to the parent in AngularJS 1.x

I am facing an issue with my component that consists of two tabs containing input fields. I need to retrieve the values from these input fields when the SAVE button is clicked and save them to the server. The problem lies in the fact that the SAVE function ...

Can Javascript (PWA) be used to detect fake GPS or mock GPS in applications?

Looking for a solution to prevent users from using Fake Location tools in my PWA application that gathers absence location data. Is there a method or package in JavaScript to detect the presence of Fake GPS installed on the device? ...

I'm looking to create a unit test for my AngularJS application

I am currently working on a weather application that utilizes the to retrieve weather data. The JavaScript code I have written for this app is shown below: angular.module('ourAppApp') .controller('MainCtrl', function($scope,apiFac) { ...

Learn how to cycle through three different texts that appear in the same spot using smooth transitions

I am working with three different rows that contain the Typography component. My goal is to display the first row, followed by the second, then the third, and back to the first one in a continuous loop. All three rows should be shown in the same location, ...

Limit the implementation of Angular Material's MomentDateAdapter to strictly within the confines of individual

Within my app, I have several components that utilize the mat-datepicker. However, there is one component where I specifically want to use the MomentDateAdapter. The issue arises when I provide it in this one component as it ends up affecting all the other ...

Tips for swapping out a new line character in JavaScript

Hello! I'm currently facing a challenge with some code. I have a function designed to replace specific HTML character values, such as tabs or new lines. However, it's not functioning as expected. var replaceHTMLCharacters = function(text){ tex ...

Selection Change Event for Dropdown Menu

Just starting to learn JavaScript and currently working with 3 select elements on a JSP page: <select id="railwayServiceList" name="railwayService_id" onchange="changeCompaniesCombo()"></select> <select id="companyList" name="company_i ...

Reaching out to the Edge: Enhancing the jQuery Slider Experience

Alright, I'm really excited about using this amazing slider. What I love most is the "free mode" feature that creates this stunning sliding effect. The size and number of slides are absolutely perfect for me. But there's just one small adjustment ...

Add design to the footer during a specific event using Javascript

Here is the CSS code I am working with: .footer { font-family: "lato", sans-serif; padding: 20px; line-height: 1.2; text-align: right; background: #eee; color: #0D47A1; font-size: 13px; height: 80px; position: fixed; right: 0px; botto ...

Ionic utilized the $http service and was unexpectedly triggered two times

$scope.login = function(email,password){ $http({ method: 'POST', url: 'http://example.com/login', headers: { 'owner': $rootScope.secret }, data: {email:email, password:password } }).then(function successCallback(response) { co ...

Using Selenium in Java to interact with popup elements

Attempting to retrieve and interact with pop-up/alert elements using selenium in Java has been a bit challenging for me. Below is the code snippet I have been working on: import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import ...