Using React Router V6, multiple components not showing

import { createBrowserRouter, RouterProvider } from “react-router-dom”
import Root from “./routes/Root”
import Main from “./components/Main”
import Rows from “./components/Rows”
import requests from “./Request”

const router = createBrowserRouter([
{
path: “/”,
element: ,
children: [
{
path: “/”,
element:
},
{
path: ‘/’,
element: (
<>

</>
)
}
]
}
])

const App = () => {
return (

)
}

export default App

Only the Main component is showing

background.js is not working in manifest v3. The same background.js worked fine in manifest v2

background.js is not working which works fine in v2

This is my manifest.json for v3 which is not letting me use background.js I am not getting any error message but the background.js file is not working

{
    "manifest_version": 3,
    "name": "DummyProject",
    "version": "0.0.1",
    "permissions": [
      "scripting",
      "tabs",
      "activeTab",
      "downloads"
    ],
    "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "128": "logo.png"
      }
    },
    "icons": {
      "128": "logo.png"
    },
    "background": {
      "service_worker": "background.js",
      "type": "module"
    }
  }
  

How many GET requests can i make to an external api

I’m creating a simple express server that fetches data from an external api (“https://www.veikkaus.fi/api/toto-info/v1/card/58971228/races”). The purpose is to create an app that fetches this info and updates it every 1-10 seconds.
Im very new to creating servers and using fetch and after a lot of research i still couldn’t find an answer to my question which is:
How often am i allowed to send this request aka. update the data to my app.

I have created the server and it correctly fetches the data. I’m scared a will cause some harm to the external API

How can I use javascript form validation alongside ZF1 form validation?

I have a web app built with Zend Framework 1.12. I’m pretty comfortable using ZF1 forms, including its form validation machinery. I now need to create a form with a variable number of fields: it has a table with a fixed number of fields at the top, and a table with one empty row at the bottom. As values fill up the empty row, a new empty row appears, etc.

AFAIK, Zend_Form only supports a fixed number of fields in a form. So I resort to javascript, and it is relatively straightforward to detect when focus leaves one of the input elements in the variable-length table, and if there are no empty rows, add a new empty row. And I can scan the input values in all the rows of the table and report errors. This is good.

But the problem comes when the form is submitted. If my javascript has detected errors in the variable table, I can prevent the form from being submitted, because I have a submit button like this:

<a href="javascript:OSH.CheckAndSubmit()">Submit</a>

And OSH.CheckAndSubmit() looks like this:

OSH.CheckAndSubmit = function() {
    if (OSH.divisionsOk()) {
        document.getElementById('addevent').requestSubmit();
    }
    else {
        return false;
    }
}

So errors detected by my javascript prevent the form from being submitted. If there are no errors detect by my javascript, then the form is submitted, where the ZF1 validators go to work on the fixed fields in the form, and if errors are detected, they insert error messages near the erroneous fields, with the erroneous values still in place. But unfortunately, the filled-in rows in the variable-length table disappear.

I guess I could try reading a pile of ZF1 source code to try figure out how the values of the input fields are preserved on the form after it is submitted and the error messages get added, but I’m wondering if anyone here either knows how ZF1 forms accomplish this, or just how to get it done in general.

I am using rails 7 importmap but error is generated javascript XXX function is not defined on custom js file

Recently I am learning to use rails7, but when I use importmap to refer to my js file,
I always get an error: [ testalert is not defined ], please help me

testjs.js is my js file

app/javascript/testjs.js

.....
  function testalert(){
    alert('call from testjs');
  }

app/views/welcome/index.html.erb

......
<input type='button' onclick="testalert();" value='test alert'>

importmap.rb

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "testjs", preload: true

application.js

import "@hotwired/turbo-rails"
import "controllers"
import "testjs"

app/assets/config/manifest.js

//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js

config/initializers/assets.rb

 ......
 Rails.application.config.assets.precompile += %w( testjs.js )

when i click the web page button [test alert] should pop up a alert windows ,but always get the error message
enter image description here

the html head
enter image description here

Does anyone know why and how to fix it , Thank you

System configuration
Rails version:
rails 7.0.5
Ruby version:
ruby 3.1.2

I have followed
https://stackoverflow.com/questions/70548841/how-to-add-custom-js-file-to-new-rails-7-project/72855705#72855705 but the error still occurs

node.js rsa encryption / decryption fail

node.js rsa encryption / decryption fail

what ive coded look at this

const crypto = require("crypto");
const fs = require("fs");

/*
const {
  generateKeyPair,
} = require('crypto');

generateKeyPair('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem',
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: '123',
  },
}, (err, publicKey, privateKey) => {
    console.log(err);
  console.log(publicKey);
  console.log(privateKey);
});

*/

//Encryption
function EncryptData(tmp_data){
    const encryptedData = crypto.publicEncrypt(
    {
        key: "-----BEGIN PUBLIC KEY-----" + "rn" + 
"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjXP+5cJDcySfRbSLQ0UF" + "rn" + 
"6coRn5Xv4VNoDJOC0fkiEt5xQGdPT7r50VWlm1WnU0bQvV55+ZkeRVF4FcNwhZaB" + "rn" + 
"LHO6jx2tS4ONErl6oxCwy4ATXXcQA7y2NmRMbMB7k+JogLRzKzIdG0QpftVFwM2e" + "rn" + 
"J+EyOCC8ugP8JiZtYlRolrNayo5c5id7sPDmRV07KUpNScg4EedqNvkzL55dd+4+" + "rn" + 
"/iBYaH9byk84+XFZY2teQgfBAsLXP9x0Z5+nK2tE2Pk2Q9jxh+fjvp08uf0FsNd1" + "rn" + 
"jICeS6BRNTHkzoSD6MSUCRVo2b+D/yZ3wS4hO+EiIYz1aIcAfCnIRxx1LpDBPHv6" + "rn" + 
"E6GNnqU9a1IvyBKka5Di/alFd16Id99jYQ92AEABlvDgvC4HJTnNFCxCaBGDVsJH" + "rn" + 
"QvLiMhE6W4ITP+JddzwmQb1SV0EPuUTW/jnGAzvNdwfARylIuVIX4Xbm4dKA48td" + "rn" + 
"r/MkMHi6E464jjQ7P+pslzfIA+fyAsFo6i3H6T6fB4TZ+kpQfiAW8qjUiprwY5BV" + "rn" + 
"5LKSyU84Bld5bfEQfp2KjUYe/AJf1/EAGKJXLS4oETt4JyuvcwiIBwObqsCGGB3l" + "rn" + 
"ooGK31viImr0osCtgh+OrJ5paNM6UH08nVzDeHqGYrcv7J/RCdi5Wr/QlMZlBj8O" + "rn" + 
"Oxg8ehU1TVR0AIrZg7yPol8CAwEAAQ==" + "rn" + 
"-----END PUBLIC KEY-----",
        padding: crypto.constants.RSA_PKCS1_PADDING,
        oaepHash: "sha256",
    },
    Buffer.from(tmp_data)
    );
    return encryptedData;
}

//Decryption
function DecryptData(tmp_enc_data){
    const decryptedData = crypto.privateDecrypt(
    {
        key: "-----BEGIN ENCRYPTED PRIVATE KEY-----" + "rn" + 
"MIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIRkPOUV4NJyACAggA" + "rn" + 
"MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCfoI8M4S2WN6od2fYyKyQZBIIJ" + "rn" + 
"UCt0XRSADkNHObn5aiMdkD1wBBEzceriJl4lCRs+oMVfUYodEj+nly5n2vhm/j+P" + "rn" + 
"u3ad5U2fZDPXMXK38U9gWNUfsoblmpyoIR3n9j+KkswvPQUQdTFwg78xC4hqGlAi" + "rn" + 
"0e4QBJqLa6uqUj2lbxhJGFwMoawZG5RoKUFqzEADkZNN3LmMm3ImYjDn+p+f6uzC" + "rn" + 
"rqZNWNp4CDFyTcqPeks3s7T8vEHiPXlLzjqlAxXklQsNPALAjTk4SuPgstq8C9o2" + "rn" + 
"kbyTnkRvmqpxR+KwoWyg98ebuysPUgK3iJvYQtsXU9P4AuLgNRtFVCh+nlPVayW+" + "rn" + 
"Qji0fArpudR15wDyearokaV01HCm7ygVJzBlbDuis3QI0lfZkF1kiiDaaRAMxSbl" + "rn" + 
"zYPuO0aVgKJaRHeLxmtYLCm6E8k/AbqFh5wLgTbim2Krj1WDis2b/1n+ZklUjnQc" + "rn" + 
"aT+M9TstHh9Sh/DNLiDJwGum4f4XLfDAnQYG09T2f0z07v3WdKkTi4MbDfOzNSoe" + "rn" + 
"Gu6B5HXMpGojaK4rdkDtYDfZAvNUT1XkwdAObfVNOKPr/CFmLLSlUfVEGqHcHgPg" + "rn" + 
"QaqtOSM3SClUd6NKU+q9hAtsGJG4+W6khRhouRIPqMa8PX3nz9gnmCNzXn/FQtXJ" + "rn" + 
"evQuNE/YWWJrHn06kCu60LZWtYl1e7W1erYwohAXWBOJ3reJ7lbjUl7Ydl6ZvPFp" + "rn" + 
"lCL4zICbzXA6vSc8bJApPUczSkJKo5NBgfZplMKoaLWI937pTvcMddxoTnLkX/4J" + "rn" + 
"xF00UXrMDNNqKIPT4iMvYGnI66i1VXS+/dKDWUQybxv1WHFBISLXpbpgdgTLVjpN" + "rn" + 
"F/zXDQ0cGtkWcRJF6t/6lKgzBrfeN4eWmCvJHk1H4Ud5p18iGl0khGB9jxRKJ9b8" + "rn" + 
"wEcsH8OPVXSYwBsh93FgjCCrnBB6vrlBIN364087jkBTYkw/aIqw81gVDSTaNIBV" + "rn" + 
"Hm0/oAdeMlaFFsfkk/jhU5OKEIrD8ydvy859xCuHnZmxcuX/rUylQoGo5F0CtJtF" + "rn" + 
"A5e3uJavF9t4N/Nxj839kyEywRv32fs1kQB/xNLLc3fv38fSA79rOjqvM7IHPlzt" + "rn" + 
"ERltwsEDTxjBUDXhEyuqaW8zrM+/Y7uk/z2jpeWJfThJpeKzjUIgz6gQVqHdXvak" + "rn" + 
"g2L6GLyyN3IXMNbkQbyl5q03VKKY7o7085I19nK4vJxjcSH8IQYFb1DdPxhKwcic" + "rn" + 
"jCf5v8h0ifjTDvTF0LjqObT8z6UJJpPT+hbOHMd3SfPWTam7RhnP6XvYwrKcD2oH" + "rn" + 
"e3IOtNiZppP+Bq1BUz0j9//sG6qfU7pegAetWpTG6432Kq729hj6zyby9m+HkV7h" + "rn" + 
"sh4EnqoJ4ZW+Ko+1C8U/NIp/zd/DrSDh6+mRSN0J3bTYHkW2++r/X1XLKcRaAHPu" + "rn" + 
"HjA0zipM4ptQb0npaCtsoUHoUKREjzsGv39OhHqc1/K3bu8rgmWSkdwi7YUQU/64" + "rn" + 
"3xtD+pn+1h2HKz0e15bBedDLH8lEkUe4zWfXeVOkhSFwD4ht5Q6hbqciCpOrAoLL" + "rn" + 
"75+Sneon8kgiy0eT1X07499f/DAtFJTVCO0YYAQ39T9wuHZyIEjH/gTe6UlGKqxU" + "rn" + 
"wM14lGN3om84a97RAaQ1a8e5kzW1csLUCNku3VbhCJ4/qkX10wDVubgOcopfQOWq" + "rn" + 
"DwrVRCbLm//kyuge1THmvS2ojqqOKRcyKhA6hwxD7prEbUoPfEw05I4e1tRAs+T/" + "rn" + 
"SXXOI0Nwj9VMWCRbNOVEWb5Gom3HTUIa1kPLfHOLtHkTnPDKnjlkofcJfekO8gUY" + "rn" + 
"YRY2pfA2iB+PfS5nImCuKpksty4yzpCYTFMF3lyi6ZQVu8w0oTdrLYbre0RCHXbj" + "rn" + 
"yEtZcpAfXoUOmQ1SAD9WOm9mudhjUZD4l4YyOL4RdSWnzwI38z4ZJkWzZKjq/9q8" + "rn" + 
"ZuGMkFrIAIKjraW23W6B3ksOGBqG/CZaPje8rJ9ogfCWNhZHQQRrXzb48QPJAQy0" + "rn" + 
"/REdygKDkJ1UbNDHa3qMuZTS0KGsgsnsNtlp3+q8Essd0dfvxwYZkM8lxMnatG1t" + "rn" + 
"73xxE0bhdf1Zx16/tJAGBOyzNfjTWVFfXhAKH9tuYYE0Lez0r+aVJIunkZt7WgDm" + "rn" + 
"xxPtcoBCwBmWaJQJN486GpVHL/NJzcM8yPSkUDTpE3SoCFUqjtl5wMPVwfUmD6Xu" + "rn" + 
"dNvZclqwiI+8LMIaiYVroDB/F3LwIE7iZsIQ6jnTgqyUTzRjyvlzsTK/I3CGEkXS" + "rn" + 
"QJ5oCR3uC6cDz4FU5yCA89nI+RGXnE8G4mVXf10zlrmfmRlkWOnQPiiyMeRsaVWm" + "rn" + 
"+0F1lo4XYG5sjzpMBgd5g6kxeVP2CvWU6KC8vu/5UmoccoJmrGqOM1apdUMSFczc" + "rn" + 
"QUxhlu6K+4MbhdB2v88vEFb41RocOJsIA1gS20F5K/iFZVwIryd4kRohDe5sjW8s" + "rn" + 
"AUu97pqu/ufQ0XlAeGjnADyo1j4qWgJEdaoPn7JqIkM3gQT2gBfqHRXUYu++ilWv" + "rn" + 
"A0xRNE3lNoVGw9lUXbJkldri5bc20eT3mRj3Oa6viPJQcNXypBImOI8GSYciko4w" + "rn" + 
"jTgsvunpd6bPSFd2CED+QKSQYGEJhyeheoSk4vsFPdLvcmKRf6b5vdntK2cRTuGt" + "rn" + 
"54p4tltQrAF6pD+fg8qa3fjFdDuuvy2gRakIeHjDbmZpBsSMa7tnyJA7uTqL930d" + "rn" + 
"OFySrsK2geEFdjUXC/fLyQxxJjo0/g4XB7jhoYQFFH0zjEICSIoy3nzLMiraVF6q" + "rn" + 
"sXmmhw42RQRXY3Uu4R8NpGF+8IR/BzS4RQWnaDirdt9yGWOA9A/WHCLfWTO1Sv0F" + "rn" + 
"r8P3490Va9dTB+fCPsHik07jAQ3bNZR4hJwkU+ixv171zw+KQag1QQoAVDzaQRlu" + "rn" + 
"IsXJ3Z3bZaasaNJbMCibT9GWKv8GrwQPX3Dx2pHb0+AqrgIVsf6dcHqs3pCFhHqK" + "rn" + 
"mJLHbgBOWlAVUmZiVwpsNuzDTuoVZxRRNwd6W+KtXiSuYCcJkst/qmcGBkKnJBb8" + "rn" + 
"t9UgLDS2vdnpG2hMA2sZT+z5QLfpNy6dnrZLUibAYa3q3m9lwuIo2nu7lN6enxNY" + "rn" + 
"sxwValowr1BeCKZ5W4ldxONUm+T60kfd9ijlSf0UwYgOcZ98oekBeiB6bvn+gQee" + "rn" + 
"7wTGpU8bfNqA0iNlN25rlW6SxxJiMR1mZJKT5eNZUpmm" + "rn" + 
"-----END ENCRYPTED PRIVATE KEY-----",
        padding: crypto.constants.RSA_PKCS1_PADDING,
        oaepHash: "sha256",
    },
    tmp_enc_data
    );
    return decryptedData;
}

var enc_data = EncryptData("Hello World");

var decrypted_txt = DecryptData(enc_data);

console.log(decrypted_txt.toString("utf-8"));

I expect it to give me the Output “Hello World”, using the above Source. Because i need the hardCode the values PrivateKey and PublicKey in my Software. I need this Function so badly and im getting this Error down below:

node:internal/crypto/cipher:80
return method(data, format, type, passphrase, buffer, padding, oaepHash,
^

Error: error:07880109:common libcrypto routines::interrupted or cancelled
←[90m at Object.privateDecrypt (node:internal/crypto/cipher:80:12)←[39m
at DecryptData ←[90m(C:UsersPCDesktopRaccoon Project Filestestsar←[39mtest.js:57:31←[90m)←[39m
at Object. ←[90m(C:UsersPCDesktopRaccoon Project Filestestsar←[39mtest.js:123:21←[90m)←[39m
←[90m at Module._compile (node:internal/modules/cjs/loader:1254:14)←[39m
←[90m at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)←[39m
←[90m at Module.load (node:internal/modules/cjs/loader:1117:32)←[39m
←[90m at Module._load (node:internal/modules/cjs/loader:958:12)←[39m
←[90m at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)←[39m
←[90m at node:internal/main/run_main_module:23:47←[39m {
opensslErrorStack: [
←[32m’error:04800068:PEM routines::bad password read’←[39m,
←[32m’error:07880109:common libcrypto routines::interrupted or cancelled’←[39m,
←[32m’error:1C80009F:Provider routines::unable to get passphrase’←[39m,
←[32m’error:07880109:common libcrypto routines::interrupted or cancelled’←[39m
],
library: ←[32m’common libcrypto routines’←[39m,
reason: ←[32m’interrupted or cancelled’←[39m,
code: ←[32m’ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED’←[39m
}

Node.js v18.16.0

Please help me out with this Bug i lost already 5 Hours.

how do I check validate of actors who have been in a movie with both actor X and actor Z (but not necessarily at the same time)

So I have an JavaScript coding assessment and need y’all opinions,
Provides a list of movies and the actors that starred in them.
so I have to use these end points to get the data,and I already did,but stuck on the validation POST request and couldnt know what should be the body objects exactly.

curl --request GET 
--url https://switch-yam-equator.azurewebsites.net/api/movies 
--header 'x-chmura-cors: <access_token>'

[
{ "movieId": 365478,
"title": "Man with the Screaming Brain",
"actors": [331341, 132257, 126364, 1646]

}, ...
]

Actors
Provides a list of actors and their IDs.

curl --request GET 
--url https://switch-yam-equator.azurewebsites.net/api/actors 
--header 'x-chmura-cors: <access_token>'

[
{ "actorId": 168,
"title": "Samuel L. Jackson"
}, ...
]

Validation
Accepts results in JSON format and returns an HTTP 200 response if the data are correct.

curl --request POST 
--url https://switch-yam-equator.azurewebsites.net/api/validation 
--header 'x-chmura-cors: <access_token>' 
--data '<results>'

[
{
"Name": "Alan Smithee",
"KRMovies": [
"The Matrix",
"The Matrix Revolutions"
]

“NCMovies”: [

so I got the matching actors and return their IDs and their names,but when attached the name and the title to the body it shows this
error

” error”: “Object reference not set to an instance of an object.”
so please any thoughts would be perfect for someone on my situation 😀
Thanks

JS – Check *all* selected files on dragenter, error if any do not meet requirement

I have a drag and drop image “uploader” (it does not upload, only converts to base64 and displays thumbnails). Currently if you drag one file into the dropzone, if it is not a .jpg/.jpeg it will show error (this is correct functionality), but if you drag multiple files into the dropzone, it does not show the error if at least 1 file is a jpg, even if the other file(s) do not meet jpg requirement, which is not what should happen (ex: you select .jpg and .zip, this will not trigger error, but it should). I need to show the error always unless all selected files are .jpg. Can anyone assist?

Here is the relevant dragenter code (same code for dragover)

container.addEventListener(
"dragenter",
(e) => {
e.preventDefault();
e.stopPropagation();
const img = Array.from(e.dataTransfer.items).find(e => e.type.match('image/jpeg'))
if (img){
   container.classList.add("active");
}else{
  error.innerHTML = "HTML removed from snippet for readability";
  error.classList.remove("hideit");}
},
false
);

https://jsfiddle.net/x2fyrcLb/2/

Updating active navbar link in React

I’m using React to make a simple navbar that will color the currently active link.

import styles from "./styles.module.css"

export function Navbar() {
    return (
    <nav className="nav">
        <ul>
          <CustomLink to ="/">Home</CustomLink>
          <CustomLink to ="/projects">Projects</CustomLink>
          <CustomLink to ="/about">About</CustomLink>
          <CustomLink to ="/contact">Contact</CustomLink>
        </ul>
      </nav>
      );
}

function CustomLink({ to, children, ...props }) {
    const resolvedPath = useResolvedPath(to);
    //needs path to fully match, reconsider if adding querying from URL in future
    const isActive = useMatch({path: resolvedPath.pathname, end: true});
    return (
        <li className={isActive ? "active" : ""}>
            <Link to={to} {...props}>
                {children}
            </Link>
        </li>
    )
}

CSS:

.active{
    background-color: #30BCED;
}

I also tried nav li.active so far everything but the .active works in the CSS and by looking at the webpage inspector I can see that the currently active link is being given the active class name

Javascript async await looping over fetch

I need some help with javascript loop over fetch api.
First I make a call to get projects by user and store then in projetosList.
Until here works fine.
But when I loop over projetosList to fetch schedules info in listarSchedules function, doesn’t works.

Javascript shouts out to me: SyntaxError: await is only valid in async functions, async generators and modules.

I’ve tried every combination of async-wait except the correct one 🙁

let urlProjetos = "https://gitlab.com/api/v4/projects?archived=false&private_token=glpat-xx";
let projetosList = [];

function getData(url) {
    return new Promise((resolve, reject)=>{
        fetch(url)
        .then((resp)=>resp.json())
        .then((data)=>{
            return resolve(data);
        })
    });
}

function imprimirProjetos(allUserData) {
    allUserData.forEach((requestPage)=>{
        requestPage.forEach((requestItem)=>{
            let id_nome = requestItem.id + "#" + requestItem.name; 
            projetosList.push(id_nome);
            console.log(id_nome);
        });
    }); 
}

function listarMeusProjetos() {
    let meuId = 123456;
    let urlMeusProjetos = "https://gitlab.com/api/v4/users/" + meuId  + "/projects?private_token=glpat-xx";
    let userRequests = [];

    userRequests.push(getData(urlMeusProjetos));

    Promise.all(userRequests).then((allUserData)=>{
        imprimirProjetos(allUserData);
    });
}

listarMeusProjetos();


// ULTIL HERE WORKS OK


function imprimirSchedule(allUserData) {
    console.log(allUserData);
}

// PROBLEM!!!!
async function listarSchedules() {
    let userRequest = null;
    let allUserData = [];
    let allPromessas = [];

    projetosList.forEach((item)=>{
        let projetoId   = item.split("#")[0];
        let projetoNome = item.split("#")[1];

        console.log("PROJETO ID: " + projetoId + " PROJETO NOME: " + projetoNome);
        let urlSchedule = "https://gitlab.com/api/v4/projects/" + projetoId  + "/pipeline_schedules?private_token=glpat-uSjCXDMEZPh5x6fChMxs";

        console.log("urlSchedule");
        console.log(urlSchedule);

        userRequest = (getData(urlSchedule))
        await userRequest.then((data)=>{
            let str = projetoId + "#" + data.description + "#" + data.owner.username;
            allUserData.push(str)
        })

    });

    imprimirSchedule(allUserData)


}

listarSchedules().then(()=>console.log("DONE"));

Thanks.

In React manage button value state for dynamically added buttons

The code below is a small, very simplified snippet from a React messaging app


const Chat = () => {

    const [myMessages, setMyMessages] = useState([]);
    const [message, setMessage] = useState("");
    const [myButtons, setMyButtons] = useState([{}]);

    const addNewMessage = () => {

        let buttonIndex = myMessages.length;
        setMyButtons(myButtons => [...myButtons, { value: "Copy message" }]);

        let newMessage =
            (<div>
                <div>{message}</div>
                <button className="copy-to-clipboard-button" onClick={() => { copyToClipboard(buttonIndex, message); }}>
                    {myButtons[buttonIndex].value}
                </button>
            </div>);

        setMyMessages(...myMessages, newMessage);

    };


    const copyToClipboard = (i, text) => {
        navigator.clipboard.writeText(text);
        let allButtons = myButtons.slice();
        allButtons[i] = "Copied!";
        setMyButtons(...allButtons);
    };


    const handleChange = (event) => {
        setMessage(event.target.value);
    };


    return (

        <div>
            <div style={{ maxHeight: "80vh", minHeight: "90vh", maxWidth: "96vw" }}>
                <div>{myMessages.map(message => <div>{message}</div>)}
                    <input
                        type="text"
                        id="message"
                        name="message"
                        onChange={handleChange}
                        value={message}
                    />

                    <button onClick={addNewMessage}>Go!</button>
                </div>
            </div>

        </div>

    )
};

export default Chat;

This code is for demonstration purposes only in order to spotlight the problem I’m trying to solve. Basically, when a new message is added, a copy to clipboard button is added with it. The value of each these dynamically added buttons is set to {myButtons[buttonIndex].value} with the intention that I’m tying the button’s value to a state variable that can be updated and rendered. This value is set correctly when the component is first added.

When a ‘copy-to-clipboard-button’ is clicked, the copyToClipboard method is called and the copy functionality works correctly. The next step is to change the button value to “Copied!”. Although the array is updated correctly, the value of the button is not updated. I suspect that the problem is that when the button is created, it sets the value as a static value and is not tied to that state variable going forward. My thinking is that there is a way to indicate that the button value should be tied to state ongoing, but I’m not able to find the right syntax. Perhaps there’s a better way to approach this altogether. Looking for some guidance. Thanks!

How can I keep the format of the text while replacing it?

I am working on building a google docs add-on that calls some specific api and replace the selected text with the response from the api .. However its removing the format of the original text (bold / colors / highlight / etc …). Is there any way to keep the formatting?

this is the method i am using to replace the selected text.

function replaceSelectedTextWithAPI(apiEndpoint) {  try {
  const selectedText = getSelectedText().join("");
  const replacement = callAPIWithSelected(apiEndpoint);
  
  var selection = DocumentApp.getActiveDocument().getSelection();
  if (selection) {
    const elements = selection.getSelectedElements();
    for (let i = 0; i < elements.length; ++i) {
      const element = elements[i].getElement();
      if (element.editAsText) {
        const startIndex = elements[i].getStartOffset();
        const endIndex = elements[i].getEndOffsetInclusive();
        const originalText = element.asText().getText().substring(startIndex, endIndex + 1);
        const escapedOriginalText = escapeRegExp(originalText);
        element.asText().replaceText(escapedOriginalText, replacement);
      }
    }
  }
} catch (error) {
    throw new Error('Error replacing selected text: ' + error.message);
  }
}

and this is the method for getting the selected text by the user:

function getSelectedText() {
  const selection = DocumentApp.getActiveDocument().getSelection();
  const text = [];
  if (selection) {
    const elements = selection.getSelectedElements();
    for (let i = 0; i < elements.length; ++i) {
      if (elements[i].isPartial()) {
        const element = elements[i].getElement().asText();
        const startIndex = elements[i].getStartOffset();
        const endIndex = elements[i].getEndOffsetInclusive();
        // Logger.log(startIndex)
        // Logger.log(endIndex)

        text.push(element.getText().substring(startIndex, endIndex + 1));
      } else {
        const element = elements[i].getElement();
        if (element.editAsText) {
          const elementText = element.asText().getText();
          if (elementText) {
            text.push(elementText);
          }
        }
      }
    }
  }
  if (!text.length) throw new Error('Please select some text.');

  //Logger.log('Selected Text: ' + text); // Output the selected text to the console

  return text;
}

I don’t know the error, is it form getSelcetedText() method, but this method is from Google themself .. Or it is from the replaceSelectedTextWithAPI() method?

Array.prototype.map.call Why does it keep returning 0?

I am trying to use Array.prototype.map.call to pull a list of text entries from an unordered list. I am generating the list from dropdown selections (each selection adds a new <li> to the list. When I submit the form, I want it to identify all the items in the list and add them with commas separating.

Currently, when I submit the form, all I return are a bunch of 0s (separated by commas).

(Building this in Google Apps Script to create a custom form in a Spreadsheet)

Here’s what I’m using:

var teacherNameValues = teacherName.length === 0 ? "" : Array.prototype.map.call(teacherName,function(n) { return n.value }).join(", ");

My empty unordered list is id “currentTeachers”

The rest of what I am using is below. All the other fields listed are functioning correctly–ONLY the teacherName is recording 0s instead of text.



      var arrayOfDistrictsBuildings;  

      function afterButtonSubmit() {
        var meetingDate = document.getElementById("enterDate");
        var cbdCoach = document.getElementById("selectCoach");
        var districtName = document.getElementById("selectDistrict");
        var buildingName = document.getElementById("selectBuilding");
        var teacherName = document.getElementsByTagName("li");
        var meetingProductivity = document.getElementById("selectProductivity");
        var generalNotes = document.getElementById("generalNotes");

        var teacherNameValues = teacherName.length === 0 ? "" : Array.prototype.map.call(teacherName,function(n) { return n.value }).join(", ");

        var rowData = {
                      meetingDate: meetingDate.value, 
                      cbdCoach: cbdCoach.value, 
                      districtName: districtName.value, 
                      buildingName: buildingName.value,
                      teacherName: teacherNameValues, 
                      meetingProductivity: meetingProductivity.value, 
                      generalNotes: generalNotes.value
                      };
        google.script.run.withSuccessHandler(afterFormSubmit).addNewRow(rowData);
      }

      function afterFormSubmit(e) {
        var districtName = document.getElementById("selectDistrict");
        districtName.value = "";
        var buildingName = document.getElementById("selectBuilding");
        buildingName.value = "";
        var teacherName = document.getElementById("selectTeacher");
        teacherName.value = "";        
        var generalNotes = document.getElementById("selectProductivity");
        selectProductivity.value = "";
        var generalNotes = document.getElementById("generalNotes");
        generalNotes.value = "";
      }

      function afterSidebarLoads(){
        google.script.run.withSuccessHandler(afterCbdCoachReturned).getCbdCoachOptions();
        google.script.run.withSuccessHandler(afterDistrictReturned).getDistrictOptions();
      }

      function addUniqueItemsToLists(el,districtLoop,index){
        var currentlyAdded = [];
        el.innerHTML = '<option>select here</option>';
        districtLoop.forEach(function(r){
          if(currentlyAdded.indexOf(r[index]) === -1){
          var districtOption = document.createElement("option");
          districtOption.textContent = r[index];
          el.appendChild(districtOption);
          currentlyAdded.push(r[index]);
          };
        });
      }
//get Coach from list
     function afterCbdCoachReturned(coachLoop){
        var cbdCoach = document.getElementById("selectCoach");
        
        coachLoop.forEach(function(r){
          var coachOption = document.createElement("option");
          coachOption.textContent = r[0];
          cbdCoach.appendChild(coachOption);
        });

      }

//get school district from list and filter based on number of instances
      function afterDistrictReturned(districtLoop){
        arrayOfDistrictsBuildings = districtLoop.filter(function(r){ return true; });
        var districtName = document.getElementById("selectDistrict");
        addUniqueItemsToLists(districtName,arrayOfDistrictsBuildings,0);
        document.getElementById("loading").remove();
      }

      function afterDistrictSelected(){
        var buildingName = document.getElementById("selectBuilding");
        var teacherName = document.getElementById("selectTeacher");  
        var districtName = document.getElementById("selectDistrict").value;
        var filteredDistricts = arrayOfDistrictsBuildings.filter(function(r){ return r[0] === districtName; });
        addUniqueItemsToLists(buildingName,filteredDistricts,1);
        addUniqueItemsToLists(teacherName,filteredDistricts,2);

      }

      var myNodelist = document.getElementsByTagName("LI");
      var i;
      for (i = 0; i < myNodelist.length; i++) {
        var span = document.createElement("SPAN");
        var txt = document.createTextNode("(remove)");
        span.className = "close";
        span.appendChild(txt);
        myNodelist[i].appendChild(span);
      }

      var close = document.getElementsByClassName("close");
      var i;
      for (i = 0; i < close.length; i++) {
        close[i].onclick = function() {
          var div = this.parentElement;
          div.style.display = "none";
        }
      }

      function newElement() {
        var li = document.createElement("li");
        var inputValue = document.getElementById("selectTeacher").value;
        var t = document.createTextNode(inputValue);
        li.appendChild(t);

        document.getElementById("currentTeachers").appendChild(li);
        document.getElementById("selectTeacher").value = "";

        var span = document.createElement("SPAN");
        var txt = document.createTextNode("(remove)");
        span.className = "close";
        span.appendChild(txt);
        li.appendChild(span);

        for (i = 0; i < close.length; i++) {
          close[i].onclick = function() {
            var div = this.parentElement;
            div.style.display = "none";
          }
        }
      }

      document.getElementById("mainButton").addEventListener("click",afterButtonSubmit);
      document.getElementById("selectDistrict").addEventListener("change",afterDistrictSelected);
      document.addEventListener("DOMContentLoaded",afterSidebarLoads);


Why my state is empty when I try to access it from a function?

I have this room component for video chat, it has two states, players to hold all elements, it is an array of nodes, each is a div, created when a user joins the room (this happens inside useEffect) and videoInDisplayFrame to hold the current element in display frame, when the user clicks on a specific player we set this one to videoInDisplayFrame.

import { useState, useEffect, useRef } from "react";
import styles from "./Room.module.css";

export default function Room() {
  const [players, setPlayers] = useState([]);
  const [videoInDisplayFrame, setVideoInDisplayFrame] = useState(null);

  const displayFrame_ref = useRef();
  const streams__container_ref = useRef();

  let expandVideoFrame = (e) => {
    console.log("expandVideoFrame is running... players:",players,"videoInDisplayFrame:",videoInDisplayFrame);

    displayFrame_ref.current.style.display = "block";

    //if videoInDisplayFrame is not null
    if (videoInDisplayFrame) {
      // add videoInDisplayFrame to players
      setPlayers((prev) => [...prev, videoInDisplayFrame]);
    }
    // find from players the one with the same id as e.currentTarget
    const newVideoInDisplayFrame = players.find((element) => 
      element.props.id === e.currentTarget.id;
    );
    // then if it exists, add it to videoInDisplayFrame
    if (newVideoInDisplayFrame) {
      setVideoInDisplayFrame(newVideoInDisplayFrame);
    }
  };

  let hideDisplayFrame = () => {
    console.log("hideDisplayFrame is running... players:",players,"videoInDisplayFrame:",videoInDisplayFrame);

    displayFrame_ref.current.style.display = null;

    // add videoInDisplayFrame to players
    setPlayers([...players, videoInDisplayFrame]);

    // set videoInDisplayFrame to null
    setVideoInDisplayFrame(null);
    
  };

  useEffect(() => {
    console.log("useEffect is running...");
    // after component first mount
    let uid = String(Math.floor(Math.random() * 10000));
    // create JSX element
    let player = (
      <div
        // ref={videoFrames_refs[videoFrames_refs.length]}
        className={styles.video__container}
        id={`user-container-${uid}`}
        onClick={expandVideoFrame}
      >
        <div className={styles.video_player} id={`user-${uid}`}></div>
      </div>
    );
    // add it to players
    setPlayers((prev) => [...prev, player]);
  }, []);

  return (
    <>
      {console.log("This is a new render... players: ",players,"and videoInDisplayFrame: ",videoInDisplayFrame)}
      <section
        className={styles.stream__container}
      >
        <div
          ref={displayFrame_ref}
          id="stream__box"
          className={styles.stream__box}
          onClick={hideDisplayFrame}
        >
          {videoInDisplayFrame}
        </div>

        <div
          ref={streams__container_ref}
          className={styles.streams__container}
        >
          {/* display players inside JSX */}
          {players.map((element, index) => (
            <div key={index}>{element}</div>
          ))}
        </div>
      </section>
    </>
  );
}

when I mount the components for the first time and then click on the only player I have to display it, I can see that my players state is an empty array, I expected it to contain the element so I can remove it and set it inside videoInDisplayFrame because useEffect should update it so the component rerenders and the state is updated before I click, I even added this button

<button
  onClick={() => {
   console.log("current state... players: ",players,"videoInDisplayFrame:",videoInDisplayFrame);
  }}
 >
current state
</button>

to be able to see the state at any moment and the output was confusing :
enter image description here

as you can see, even when I clicked on the button to see the state before expandVideoFrame and after it and it is not empty event when I click to run hideDisplayFrame after this, players is not empty so why it is when expandVideoFrame runs?.

Note:

inside expandVideoFrame I tried this just for test:

setPlayers(prev => {
  console.log("prev: ", prev)
  return [];
})

and prev was not empty, it contains the node element, but I expect players to have the same value as well, what am I missing? thank you for your time.

Count Odd Numbers in an Interval Range

When I click test it works, when I click submit it doesn’t. I’m a complete beginner so any help is appreciated

var countOdds = function(low, high) {
  let data = []
  for (let i = low; i <= high; i++) {
    if (i % 2 !== 0) {
      data.push(i)
    }
  }

  return data.length
};