How to have rows and columns header of table stay on top when it is scrolled

Further from this :
thread

I want to have the left columns width and position dynamycally. Because it keeps changes when I adjust the header text.

I modified the html, full code is here

this script to identify left position of columns dynamycally:

 document.addEventListener("DOMContentLoaded", function() {
      const table = document.querySelector("table");
      const headers = table.querySelectorAll("th");
      const rows = table.querySelectorAll("tr");

      let leftOffset = 0;

      for (let i = 0; i < 3; i++) {
        const columnWidth = headers[i].offsetWidth; // Get actual width of each column

        // Apply sticky positioning to the first three columns
        headers[i].style.position = "sticky";
        headers[i].style.left = `${leftOffset}px`;
        headers[i].style.zIndex = "10"; // Ensure row headers stay above regular cells
        //headers[i].style.background = "#fff"; // Prevent overlapping transparency

        rows.forEach(row => {
          const cell = row.cells[i];
          if (cell) {
            cell.style.position = "sticky";
            cell.style.left = `${leftOffset}px`;
            cell.style.zIndex = "5";
            cell.style.background = "#fff"; // Prevent content from showing through
          }
        });

        leftOffset += columnWidth;
      }

      // Make the first row (column headers) sticky
      const firstRow = table.querySelector("tr");
      if (firstRow) {
        firstRow.querySelectorAll("th").forEach(header => {
          header.style.position = "sticky";
          header.style.top = "0px"; // Stick to the top
          header.style.zIndex = "15"; // Keep it above other headers but below intersections
          //header.style.background = "#fff"; // Prevent overlap issues
        });
      }

      // Fix the intersection where the first row AND first three columns meet
      for (let i = 0; i < 3; i++) {
        const cell = firstRow.cells[i];
        if (cell) {
          cell.style.zIndex = "20"; // Highest priority for top-left corner cells
          cell.style.background = "#fff"; // Prevent layering issues
        }
      }
    });

Not all the header rows and cols are sticked:

Code result

I think it’s z-index is not right, but I do not get that.

The problem is :
the second row header (or the second ), when the table is scrolled horizontally to the right, it overlaps (on the top of element) the columns on the left side, it supposed to be under the columns element.

this elements

<th colspan="2" class="weekend">Sat</th>
        <th colspan="2" class="weekend">Sun</th>
        <th colspan="2" class="">Mon</th>
        <th colspan="2" class="">Tue</th>
        <th colspan="2" class="">Wed</th>
        <th colspan="2" class="">Thu</th>
        <th colspan="2" class="">Fri</th>
        <th colspan="2" class="weekend">Sat</th>
        <th colspan="2" class="weekend">Sun</th>
        <th colspan="2" class="">Mon</th>
        <th colspan="2" class="">Tue</th>
        <th colspan="2" class="">Wed</th>
        <th colspan="2" class="">Thu</th>
        <th colspan="2" class="">Fri</th>
        <th colspan="2" class="weekend">Sat</th>
        <th colspan="2" class="weekend">Sun</th>
        <th colspan="2" class="">Mon</th>
        <th colspan="2" class="">Tue</th>
        <th colspan="2" class="">Wed</th>
        <th colspan="2" class="">Thu</th>
        <th colspan="2" class="">Fri</th>
        <th colspan="2" class="weekend">Sat</th>
        <th colspan="2" class="weekend">Sun</th>
        <th colspan="2" class="">Mon</th>
        <th colspan="2" class="">Tue</th>
        <th colspan="2" class="">Wed</th>
        <th colspan="2" class="">Thu</th>
        <th colspan="2" class="">Fri</th>
        <th colspan="2" class="weekend">Sat</th>
        <th colspan="2" class="weekend">Sun</th>
        <th colspan="2" class="">Mon</th>

overlaps this:

<th></th>
<th></th>
<th></th>

and the rows in the tbody when it scrolls vertically, it overlaps those <th></th> too.

Draggable div is sticked to the right side of screen until max-width is reached while dragging

I’m making Chrome extension. I’m trying to make popup to be draggable and to be able to move it around screen. I’m able to move it but it’s stuck to the right side of screen until it reaches max-width. What am I doing wrong?

Here’s simplified code.

const popup = document.getElementById("popup");
const dragBtn = document.getElementById("drag-btn");

let offsetX, offsetY, isDragging = false;

dragBtn.addEventListener("mousedown", (e) => {
    isDragging = true;
    offsetX = e.clientX - popup.offsetLeft;
    offsetY = e.clientY - popup.offsetTop;
});

document.addEventListener("mousemove", (e) => {
    if (isDragging) {
        popup.style.left = `${e.clientX - offsetX}px`;
        popup.style.top = `${e.clientY - offsetY}px`;
    }
});

document.addEventListener("mouseup", (e) => {
    isDragging = false;
});
#popup {
    position: fixed;
    top: 20px;
    right: 20px;
    min-width: 350px;
    max-width: 500px;
    background: var(--dark-bg, #222);
    color: var(--dark-text, #fff);
    border: 1px solid #333;
    box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
    padding: 15px;
    border-radius: 8px;
    z-index: 10000;
}

#popup-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
}

#popup-title {
    font-size: 14px;
    font-weight: bold;
}

button {
    border: none;
    cursor: pointer;
    border-radius: 4px;
    font-size: 16px;
    width: 26px;
    height: 26px;
    text-align: center;
    padding: 0;
}

#drag-btn {
    background: #326042;
    color: white;
    cursor: grab;
}

#theme-btn {
    background: #ef713b;
    color: white;
}

#close-btn {
    background: #ff5252;
    color: white;
}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Song Lyrics Finder</title>
    <link rel="stylesheet" href="src/style.css">
</head>
<body>
    <div id="popup">
        <div id="popup-header">
            <p id="popup-title">Song Lyrics Finder (from Genius.com)</p>
            <div style="display: flex; align-items: center; gap: 5px;">
                <button id="drag-btn">✥</button>
                <button id="theme-btn">&#9681;</button>
                <button id="close-btn">&#11199;</button>
            </div>
        </div>
    </div>
</body>
</html>

How can I generate visualizations in JavaScript using data and packages from R? [closed]

I have a tumor dataset in R that is a Seurat object. I am working on a project to develop a new visualization tool for single cell RNA-seq data. I want to develop the visualization using JavaScript, but I am unsure how to go about doing so. I want to keep access to the R object and packages to be able to compute new data as needed by the user instead of trying to precompute everything beforehand. In other words I want to have a JavaScript front end and R back end. From what I have seen so far, it seems like the Shiny or Plumber packages may be the best. Would either of these work, or what would be the best way to go about this?

jsGrid Loading Data using Option “pageLoading”

Could someone help me figure out how to get jsGrid to load my data (shown within the “Data:” section). I’m using the “pageLoading” option but it would appear the controller is not wanting to recognize my data.

Do I need to pull out the “data” from the response? If so, how would I do that?

jsGrid Data Format:


{
  data: [ { ..first item ...}, { ..second item..}, ...],
  itemsCount: n 
}

Data:


[{"ROW_NUMBER":1,"data":"[{"data":[{"STUDENTPIDM":1,"STUDENTID":111,"STUDENTNAME":"Presley, Elvis","AIDYEAR":"2425","CATEGORY":"Deceased","CATEGORIES":null,"COMMENTS":"Wish he was still here"},{"STUDENTPIDM":2,"STUDENTID":222,"STUDENTNAME":"Monroe, Marilyn","AIDYEAR":"2324","CATEGORY":"Deceased","CATEGORIES":null,"COMMENTS":"Really miss her."},{"STUDENTPIDM":3,"STUDENTID":333,"STUDENTNAME":"Dean, James","AIDYEAR":"2425","CATEGORY":"Deceased","CATEGORIES":null,"COMMENTS":"Cool Actor"}],"itemcount":"3"}]"}]

Controller Code:


controller: {
          loadData: function (filter) {
                      return fetch("/internal/dataPackage.XXXX")
                               .then(response => response.json()) 
                               .catch((error) => {
                                  toastr["error"]("Something went wrong.", "Error");
                               });

Error:

Uncaught (in promise) TypeError: this.data is undefined

Set the value of an input which is provided from another form

I have a workflow where values are passed from one form to another. I need to have one of these values in the newly created form multiplied by 40 and inserted into another field. I can only figure out how to do this when the value is typed in but not passed in from a parent form.

The code below works, but again I have to actually type in a value over the one that is already passed in

const pallet = 40;

$(document).ready(function() {
  $("#FreeNumberField_17").change(function() { 
    $('input[name="FreeNumberField_07"]').val((
      +(pallet * $('input[name="FreeNumberField_17"]').val()).toFixed(3)
    ));
  });
});

TypeORM compare datetime field to date (ignoring time)

TypeORM with a SQLite DB

I am using querybuilder and I would like to bring back data that matches a date I am sending in this format “2024-12-11”. The field is a datetime field and the date looks like this when in the db “2024-12-11 00:00:00.000”.

If I compare what is there with new Date(“2024-12-11”) it works fine but I would rather just be comparing the date than datetime.

This is what my code looks like:

.andWhere("logs.log_date = :log_date", {log_date: new Date("2024-12-11")})

Thanks

TypeScript misunderstanding. How to fix problem?

Have a code (typescriptPlayground)

problem is in spread operator.
in case of secondObjectFull i have an error. It is ok. firstObject cannot spread to secondFullMapped

But in case of thirdObjectFull i can spread firstObject to thirdFullMapped.
I think that because of definition of thirdFullMapped

type thirdMapped = MappedTypeFunc<Omit<third, keyof base>, any>
type thirdFullMapped = baseMapped & thirdMapped;

in this case thirdMapped is empty. I think a problem is becase of this. If thirdMapped is not empty – all work as expected.

How to fix this situation?

Thanks

Serve a binary file in functions GCP

Is it possible to serve a file from google cloud platform

response.contentType("application/octet-stream");
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Length", file?.blob.size ?? 0;
response.send(file?.blob);

Do functions have some limits ?

Thanks for any help

JWT using password as secret key?

The json web token seems to be a good way to protect server apis from unauthorised access, but a jwt requires a secret key. And usually the one who does a request to a server is a browser. And a browser cannot store a secret key, because it would be visible in the HTML.

So the only option that remains is to use the password entered by the user, store it in a variable, and use it as a secret key for subsequent requests.
Problem is that on server secret keys have to match, so then I have to either:

  • store the pw in clear text. Not good for obvious reasons.
  • store the pw as hash, and hash it on client before passing it as secret key to create the token. No so good either, because now anyone knows the hashing method

Or am I missing something? Is there a better way to do this?

Dynamic custom component radio buttons do not have unique name when duplicated

I have the following form with a set of radio buttons in each section I can only select one of the buttons at any given time.

It appears that they do not have unique names.

enter image description here

The form is dynamically generated using the following code:

  get anatomicalComplaints(): FormArray {
    return this.childForm.get('dcrr_pc')?.get('pc_anat_loc_compl') as FormArray
  }

  addAnatomicalComplaints() {
    this.anatomicalComplaints.push(this.createNewAnatomicalComplaint())
  }

  removeAnatomicalComplaints(index: number) {
    this.anatomicalComplaints.removeAt(index)
  }

  createNewAnatomicalComplaint() {
    return new FormGroup({
      spinal: new FormControl(''),
      vas: new FormControl(''),
      laterality: new FormControl(''),
      radicular_component: new FormControl(''),
      pc_cas_hist_doc_compl: new FormControl('')
    })
  }

Each input in the form is a custom component that I have built to make development easier. The code follows here:

import { CommonModule } from '@angular/common';
import { Component, forwardRef, Host, Input, OnDestroy, OnInit, Optional, ViewEncapsulation } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormsModule, AbstractControl, FormGroupDirective, ControlContainer, FormGroup, FormArray } from '@angular/forms';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-form-input',
  standalone: true,
  imports: [
    CommonModule
  ],
  templateUrl: './form-input.component.html',
  styleUrl: './form-input.component.scss',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => FormInputComponent),
      multi: true
    },
    
  ],
  viewProviders: [
    {provide: ControlContainer, useExisting: FormGroupDirective}
  ]
})
export class FormInputComponent implements OnInit, ControlValueAccessor, OnDestroy {
  
  @Input() placeholder: string = ''
  @Input() type: string = 'text'
  @Input() label: string = ''
  @Input() required: boolean = false
  @Input() minLength: number = 0
  @Input() labelClassList: string = ''
  @Input() classList: string= ''
  @Input() size: string = 'sm'
  @Input() options: string[] = [];
  @Input() selectOptions: any;
  @Input() controlName : string | null = null
  @Input() indexAt : number = 0
  @Input() formType : string = 'horizontal'
  @Input() inputGroup : boolean = false

  protected onTouched: any = () => {}

  private onChange: any = () => {}
  private destroy$ = new Subject<void>()

  control !: AbstractControl

  value: any;

  constructor(public parentForm: FormGroupDirective) {

  }

  ngOnInit() {

  }

  setRadioId = (index: number) => `${this.controlName}${index}`


  writeValue(value: any): void {
    this.value = value
  }

  registerOnChange(fn: any): void {
      this.onChange = fn
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn    
  }

  onInputChange(event: any): void {
    this.value = event.target.value
    this.onChange(this.value)
  }

  ngOnDestroy(): void {
    this.destroy$.next()
    this.destroy$.complete()
  }
}
@if(!inputGroup) {
    <div [class]="classList">
        @if(label != '' && formType == 'default') {
            <label>{{label}}</label>
        }
        @if(type == 'text' || type == 'date') {
            <input 
                [type]="type"
                [placeholder]="placeholder"
                [value]="value"
                (input)="onInputChange($event)"
                (blur)="onTouched()"
                class="form-control"
                [class.form-control-sm]="size == 'sm'"
            />
        }
        @if(type == 'radio') {
            @for(option of options; track option; let idx = $index) {
                <div class="form-check form-check-inline">
                    <input class="form-check-input" [type]="type" [name]="controlName" [id]="setRadioId(idx)" [value]="option">
                    <label class="form-check-label" [for]="setRadioId(idx)">
                        {{option}}
                    </label>
                </div>
            }
        }

        @if(type == 'checkbox') {
            @for(option of options; track option; let idx = $index) {
                <div class="form-check">
                    <input [type]="type" class="form-check-input" [name]="controlName">
                    <label class="form-check-label">
                    {{option}}
                    </label>
                </div>
            }
        }

        @if(type == 'select') {
            <select class="form-control" [class.form-control-sm]="size == 'sm'" (input)="onInputChange($event)"
            (blur)="onTouched()">
                <option value="">--Payer--</option>
                <option *ngFor="let o of selectOptions" [value]="o">{{o}}</option>
            </select>
        }

        @if(type == 'textarea') {
            <textarea class="form-control" [class.form-control-sm]="size == 'sm'" rows="5" width="100%"></textarea>
        }
    </div>
}

@if(inputGroup) {
    <div [class]="classList">
        <div class="input-group">
            <span class="input-group-text border-0 bg-transparent">{{label}}</span>
                @if(type == 'text' || type == 'date') {
                    <input 
                        [type]="type"
                        [placeholder]="placeholder"
                        [value]="value"
                        (input)="onInputChange($event)"
                        (blur)="onTouched()"
                        class="form-control"
                        [class.form-control-sm]="size == 'sm'"
                    />
                }
                @if(type == 'select') {
                    <select class="form-control" [class.form-control-sm]="size == 'sm'" (input)="onInputChange($event)"
                    (blur)="onTouched()">
                        <option value="">--Payer--</option>
                        <option *ngFor="let o of selectOptions" [value]="o">{{o}}</option>
                    </select>
                }
        </div>
    </div>
}

I have tried passing in the unique indexes, setting the formControlName inside the custom component, and setting unique ids. None of these solutions have worked.

How to customize LinearProgress color in Material UI

I have set a theme for my codebase using createTheme like so:

import { createTheme } from '@mui/material/styles';

export default function getTheme() {
  return {
    theme: createTheme({
      palette: {
        ...,
        progress: {
          0: '#000000',
          126: '#222222',
          251: '#444444',
          376: '#666666',
          501: '#888888',
          626: '#aaaaaa',
          751: '#cccccc',
          876: '#eeeeee',
          1000: '#ffffff',
        },
        ...,
      }
    });
  }
}

It works just fine for the Typography component:

import { Typography } from '@mui/material';

export default function HelloWorld() {
  return (
    <Typography color="progress.126">
      Hello World
    </Typography>
  );
}

However, it raises a TypeError: Cannot read properties of undefined (reading 'main') when I use it with LinearProgress:

import { LinearProgress } from '@mui/material';

export default function ProgressBar() {
  return (
    <LinearProgress
      variant="determinate"
      value={50}
      color="progress.501"
      sx={{
        height: 8,
        width: 120,
      }}
    />
  );
}

How can I apply these colors to the LinearProgress like I would with other Material UI components?

All Flexbox Containers Expanding Unintentionally When Toggling One Container

I’m working on a layout using Flexbox, where I have multiple containers, each containing collapsible content. When I toggle the expansion/visibility of one collapsible container, all the containers expand in height, which is not the desired behavior. The content of the other boxes doesn’t become visible, but their heights increase, matching the one that was toggled.

Expected behavior:
When toggling the visibility of .snippet-text-information by clicking the .snippet-button ”+” button, only the .snippet-box containing the toggled element should adjust its height accordingly. Other .snippet-box containers should remain at their original height.

Actual behavior:
When I toggle the expansion of one .snippet-text-information element, all .snippet-box containers expand in height, even though only the content of one box is becoming visible. The height of each .snippet-box matches the expanded content of the toggled box.

Code:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Minimal Reproducible Example</title>
    <style>
        /* CSS styles will go here */
    </style>
</head>
<body>

<div class="snippet-box-container">
    <div class="snippet-box">
        <div class="snippet-button-box">
            <button class="snippet-button" data-target="#box1">+</button>
        </div>
        <div class="snippet-text-box">
            <div class="snippet-text-title">Lorem Ipsum</div>
            <div class="snippet-text-content">Lorem ipsum dolor sit amet</div>
            <div class="snippet-text-information" id="box1">
                <div class="list-title">Lorem ipsum dolor sit amet:</div>
                <ol>
                    <li>Item 1</li>
                    <li>Item 2</li>
                </ol>
            </div>
        </div>
    </div>

    <div class="snippet-box">
        <div class="snippet-button-box">
            <button class="snippet-button" data-target="#box2">+</button>
        </div>
        <div class="snippet-text-box">
            <div class="snippet-text-title">Lorem Ipsum</div>
            <div class="snippet-text-content">Lorem ipsum dolor sit amet</div>
            <div class="snippet-text-information" id="box2">
                <div class="list-title">Lorem ipsum dolor sit amet:</div>
                <ol>
                    <li>Item 1</li>
                    <li>Item 2</li>
                </ol>
            </div>
        </div>
    </div>
</div>

<script>
    function toggleExtension() {
        const buttons = document.querySelectorAll('.snippet-button');
        buttons.forEach(button => {
            button.addEventListener('click', () => {
                const target = document.querySelector(button.getAttribute('data-target'));
                target.classList.toggle('active');
            });
        });
    }

    window.onload = toggleExtension;
</script>

</body>
</html>

CSS:

.snippet-box-container {
    display: flex;
    justify-content: center;
    gap: 25px;
    width: 100%;
    padding: 0px 15px;
}

.snippet-box {
    display: flex;
    flex-direction: column;
    min-height: 180px;
    flex-basis: 290px;
    background-color: white;
    box-shadow: 0px 0px 20px rgba(128, 128, 128, 0.1);
    border-radius: 15px;
    box-sizing: border-box;
}

.snippet-button-box {
    display: flex;
    justify-content: flex-end;
}

.snippet-button {
    height: 35px;
    width: 35px;
    background-color: rgb(232, 230, 230);
    border-radius: 50%;
    margin: 20px;
    border: none;
}

.snippet-text-box {
    padding: 25px;
    gap: 5px;
}

.snippet-text-title {
    font-size: 22px;
    font-weight: 800;
}

.snippet-text-content {
    color: rgb(184, 184, 184);
}

.snippet-text-information {
    display: none;
}

.snippet-text-information.active {
    display: block;
}

Codepen: https://codepen.io/The-Now/pen/MYWoVQL

I’ve tried changing display: none to visibility_hidden and tried adding different height properties to the .snippet-text-information, but it didn’t work.

I suspect this might be related to how Flexbox handles element heights, but I’m unsure of the exact cause.

Any insights on why this is happening or suggestions on how to fix it with minimal structural changes?

Thanks in advance!

React.js Offline POS Stuck While Saving

I am developing an offline POS system in React.js, but I am facing an issue where the POS gets stuck while saving transactions.

What I Have Done:
Used IndexedDB/localStorage for offline data storage.
Implemented a service worker to sync data when online.
Tried using async/await to handle transactions.
Issue:
When saving a new transaction, the system hangs and doesn’t complete the process.
No error logs appear, but the UI freezes until a refresh.
It works fine when online, but offline transactions are not saving properly.
Has anyone faced a similar issue? Any suggestions on handling offline transactions properly in React.js?

Tech Stack: React.js, IndexedDB, Service Workers, Local Storage

parse json for this new line character as well spaces [closed]

{
“best.jugaadtravel.com”: {
“PEM”: “—–BEGIN PRIVATE KEY—–nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgnm0xOarXPTlGneYeJUR64b2fi+e1yekFr1H6FE/O+tNyoYxeK60DVgkRdSCnDNOWZ2ynULDJ65N0Cnoyasofgqco4NqwJg81675CwCzuFKR5usnkhJ7bY6LGpMoWG0tTvU+iUWQHbWUkPInTPRDmehgY7ss1MRQFQv2TzRZC2oIcMrtozG0lmcEbGmxgFaPnXYACX051XAjrwbTny9H87+si2OVbCMo8+h45gTAZDfD+FKQQEST5F57X5Hvow6SErlgweuLeb/h5m/GsnSUL4vjQUmpYs+mqaYAmAqt80O6OXXmmaGL1rCQy63feIpQsksMT7/cUZzSM3lO6+nkTtbOjBfAgMBAAECggEANJvvtAHpfVqmWfkQdd/GKi8DXgryxV5Z81HEpx4j5kEjnTVw3p97qe4SRk+RBGZlH4x8wEjjvx+USpvx9fGoI+Q5QjRWIT+0nCG/yInFUxZmyn2dV2ZBCicWd+4d6yPBhoopfUcfdndUe4v/DEySeuP3QrKMIAEyLxqhnDUa81adHSn7y4r3o5NBN4NeLp+YcWWqqcq5VgIAeWv8245amphgA4at+QJFYr9CZC+hqfRjPXontmUdEvpgXT0YuRZUt6UeiV07ITjFXbQ+Yq0HG+Wq33+7sH73YiY7b2aNLTChUP8hn5mqv/YH3uDFRwV6h53cBzclXccSZjtvlWj4rzheaQQKBgQDXqUwGmY0t9SGCAjRdnQomSE/pT1FS1mFcmm5DE+xwYMy6+DrO+9eFmjHjE9DeXrgyrVLdfJCfSDfCYJ7TqnfcmOhRwtwbJZGYNY6YqwTs7eBezHWdvYvuUl6AIlZyijXAJynsI7X90pyCK+vo/InX0lWPFzgy8fZaSKDjKLw9ogsDwKBgQC+qXt1RpA0XvHEbDPSnEoZleKWm3G71Ul+nv5Y5xOOLEN7zrub0+z9TkFeIj2cH2ZD6wW9XTVKZ9y6Qs05v0x0Zco7brM5V6BRBnMLUncIPBhOFuv1armpWPZ4A+HABwMjHhNekejlUQT+hNV2AwBcTSFNAglqwdbMfmnjeJ7w16msQKBgQCq9skQSlZDYprHp9u/Ouo4ZaIDJsZol3YvYw/nOHJTNPAPNzSDnZATl+OIcsMYJdq8Qe75KrCztNqPO21tusX1BgICQPYeXXsRjjfCmSDNyixvkBXZlnYx/hZwWchSUQK/a8yuKLkzmOz9vLfuIZJIDM3ll609GApvn3c1wQzj+xPQKBgF3wnX1W++Jn1FaWzsizYuGG2ybduyzDCu71pY/j+myYPn+nsiPq3N9JSUe6EyTzC433JnBLS88i/N6/F7hu/t0m6RVPXDRL5q5F/iQb823pPghrnsKCXQulO3qSXw4f5lnNHbnoApgEmVBGbHRlSDUFs9zVcBYvGCbEjr0OVzFO8NhAoGBAIZM9e5k00uwg2S/Yaa+ntUtqXOfePoMnZ3p0uyMNuNtZqaUMkfxkZI/OZnfRoAYr8TOEclNOqloGXj5Ntu7knfS3Vov/eDLvRBOeYQb3iULl8feeAyLkcVYrEYlgjz5RwU0rzMIo5PUPZq5IHMD3Gn1CovX1ngX1KNzSsa/Fb14kkUn—–END PRIVATE KEY—–“,
“PUB”: “—–BEGIN PUBLIC KEY—–nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoJ5tMTmq1z05RnmHiVEenuG9n4vntcnpBa9R+hRPzvrTcqGMXiutA1YJEXUgpwzTlmdsp1CwyeuTdAqMmrKH4nKnKODasCYPNeu+QsAs7hSkebrJ5ISe22OixqTKFhtLU71PolFkB21lJDyEz0Q5nonYGO7LNTEUBUL9k80WQtqCHDK7aMxtJZnBGxpsYBWj512AAl9OdVwI68G08vR/O/rnItjlWwjKPPoeOYEwGQ3w/hSkEBEk+Ree1+R76MOkhK5YMHri3m/4eZvxrElC+L40nFJqWLPpqmmAJgKrfNDujl15pmhi9awkMut33iKULJLDE+/3FGc0jN5TuvpE7WzownXwIDAQABn—–END PUBLIC KEY—–“,
}
}
this is raw response in postman cant parse this json

JavaScript adding event listeners to path elements of svg not working here

I have a page with an SVG containing multiple paths (this is for a world map), and wanted to make a script to add an event listener to each path, so you can click on an individual country and make things happen, though I am having trouble and not sure why.

I created a very simple script:

const countries = Array.from(document.getElementsByClassName('country'));
countries.forEach(c => {
  console.log(c);
  c.addEventListener('click', function() {
    console.log('you clicked:', c.getAttribute('title'));
  })
})

The script does loop through the elements array and each element is output to the console, mousing over the element in the console highlights the area on the page… but it appears no event listener is created, or bound to the path.

I did check the script is working by creating a set of paragraphs on the page:

<p class="country" title="p1">one</p>
<p class="country" title="p2">two</p>
<p class="country" title="p3">three</p>

These are now picked up by the same script and have event listeners that log the expected results on click… but nothing happens when the paths are clicked on. It seems like chrome just doesn’t want to add event listeners to path elements, but I know it should be possible.

for reverence the svg is inline defined like this:

    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 1008 651">
      <path class="country" id="AE" title="United Arab Emirates"
        d="M619.874,393.722L620.373,393.573L620.477,394.411L622.671,393.93L624.99,394.009L626.684,394.1L628.604,392.028L630.695,390.054L632.467,388.146L633.001,389.202L633.382,391.639L631.949,391.651L631.72,393.648L632.216,394.073L630.947,394.674L630.939,395.919L630.122,397.175L630.049,398.394L629.484,399.032L621.056,397.508L619.981,394.428z" />
      <path class="country" id="AF" title="Afghanistan"
        d="M646.879,356.901L649.738,358.201L651.853,357.745L652.438,356.188L654.651,355.669L656.231,354.617L656.791,351.832L659.154,351.154L659.594,349.902L660.917,350.843L661.762,350.952L663.323,350.975L665.438,351.716L666.295,352.143L668.324,351.017L669.27,351.694L670.174,350.085L671.85,350.159L672.281,349.641L672.578,348.213L673.785,346.975L675.303,347.785L674.998,348.869L675.846,349.038L675.585,351.994L676.694,353.137L677.672,352.404L678.916,352.057L680.663,350.486L682.594,350.745L685.486,350.751L685.985,351.758L684.353,352.15L682.928,352.795L679.71,353.2L676.699,353.931L675.063,355.439L675.725,356.899L676.046,358.603L674.649,360.033L674.766,361.335L673.995,362.549L671.328,362.444L672.43,364.663L670.646,365.507L669.455,367.511L669.609,369.491L668.514,370.415L667.477,370.109L665.334,370.537L665.027,371.451L662.939,371.446L661.377,373.289L661.278,376.039L657.635,377.374L655.682,377.092L655.114,377.794L653.438,377.386L650.634,377.865L645.936,376.228L648.479,373.298L648.249,371.202L646.125,370.65L645.905,368.565L644.987,365.921L646.187,364.094L644.966,363.599L645.736,361.148z" />
      <path class="country" id="AL" title="Albania"
        d="M532.985,334.657L532.629,335.93L533.027,337.524L534.19,338.425L534.134,339.393L533.223,339.925L533.054,341.115L531.75,342.88L531.274,342.626L531.218,341.826L529.665,340.601L529.421,338.851L529.658,336.323L530.041,335.164L529.568,334.573L529.38,333.377L530.596,331.512L530.774,332.227L531.528,331.891L532.125,332.907L532.796,333.293z" />
//  etc..

I have also tried hardcoding an event listener to a specific path id but that also does not do anything on click, i.e:

const oz = document.getElementById("AU");
console.log(oz);
oz.addEventListener("click", () => {
  console.log('clicked on oz');
});

While trying to find a solution I have seen examples of the same approach working, e.g.
https://svg-tutorial.com/svg/interaction

And I can’t realistically see where I am doing anything different that would cause a problem