React Native Text to Speech with Online Transcription

Is there any way you’d recommend to get live (streaming) transcribed audio using a model on par with OpenAI Whisper or AssemblyAI in React Native.

I made a NodeJS server that forwarded my messages and transcription from React Native to Deepgram. It fails 90% of the time but works sometimes. I know that the issue occurs before the response is received from Deepgram. Are the websocket packets getting to big for longer transcriptions? Am I sending Finalize at the wrong time?

speech.ts

import { Audio } from "expo-av";
import { useEffect, useRef, useState } from "react";

export default function useSpeech() {
    const [recording, setRecording] = useState<Audio.Recording | null>(null);
    const [messages, setMessages] = useState<string[]>([]);
    const [inProgressMessage, setInProgressMessage] = useState<string | null>(null);
    const wsRef = useRef<WebSocket | null>(null);
    const [isAudioSetup, setIsAudioSetup] = useState(false);
    const [isWSReady, setIsWSReady] = useState(false);

    // Create WebSocket connection to Deepgram
    const setupWS = () => {
        const newWs = new WebSocket(
            `wss://time-defend.fly.dev`,
        );
        wsRef.current = newWs;
        // Handle WebSocket events
        newWs.onopen = () => {
            console.log('WebSocket connected');
            if (newWs === wsRef.current)
                setIsWSReady(true);
            console.log(newWs, wsRef.current, "newWs === ws", newWs === wsRef.current)
        };
        newWs.onmessage = (event) => {
            console.log('Received message:', event.data);
            const data = JSON.parse(event.data);
            // handle transcription
        };
        newWs.onerror = (error) => {
            console.error('WebSocket error:', error);
        };
        newWs.onclose = (event) => {
            console.log('WebSocket closed:', event.reason);
            if (newWs === wsRef.current)
                setIsWSReady(false);
        };
        setIsWSReady(false);
    };

    useEffect(() => {
        setupWS();
        // Request permissions and set up audio
        const setupAudio = async () => {
            try {
                await Audio.requestPermissionsAsync();
                await Audio.setAudioModeAsync({
                    allowsRecordingIOS: true,
                    playsInSilentModeIOS: true,
                });
                setIsAudioSetup(true);
            } catch (err) {
                console.error('Failed to setup audio:', err);
            }
        };
        setupAudio();

        // Cleanup WebSocket when unmounting
        return () => {
            if (wsRef.current) {
                wsRef.current.close();
            }
        };
    }, []);

    // Start Recording + Open WebSocket
    const startRecording = async () => {
        try {
            // Create a new recording
            const { recording: newRecording } = await Audio.Recording.createAsync(
                Audio.RecordingOptionsPresets.HIGH_QUALITY,
                (status) => {
                    // This callback receives recording status updates
                    console.log('Recording status:', status);
                },
                100 // Update interval in milliseconds
            );
            setRecording(newRecording);

            if (!wsRef.current) {
                throw new Error('WebSocket not initialized');
            }
        } catch (err) {
            console.error('Failed to start recording:', err);
        }
    };

    // Stop Recording + send "Finalize"
    const stopRecording = async () => {
        try {
            setIsWSReady(false);
            if (!recording) return;

            await recording.stopAndUnloadAsync();
            recording._options?.web.bitsPerSecond
            const uri = recording.getURI();
            setRecording(null);

            // wss://api.deepgram.com/v1/listen?punctuate=true&channels=1&sample_rate=16000&encoding=linear16
            // get the recording and encode it the right way as a string
            // Get the audio file as a blob

            // Web: Use fetch and Blob
            const response = await fetch(uri!);
            const blob = await response.blob();
            const reader = new FileReader();

            reader.onloadend = () => {
                let base64String = reader.result!;

                // console.log(base64String)

                // wsRef.current!.send(Buffer.from(base64String.split(",")[1], "base64"));
                wsRef.current!.send(base64String as ArrayBuffer)
                wsRef.current!.send("Finalize");

                // Once done, let Deepgram know we're finished sending audio
                // if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
                //   wsRef.current.send('Finalize');
                // }
            };

            reader.readAsArrayBuffer(blob);

            console.log('Recording stopped, file saved at:', uri);
        } catch (err) {
            console.error('Failed to stop recording:', err);
        }
    };
    const isReady = isAudioSetup && wsRef.current?.readyState === WebSocket.OPEN && isWSReady;
    console.log("isReady", isReady, isAudioSetup, wsRef.current?.readyState === WebSocket.OPEN, isWSReady)
    const isRecording = recording !== null;
    return { isReady, isRecording, startRecording, stopRecording, inProgressMessage, messages };
}

AgGrid VUE without Node.js

im trying to bundle aggrid-vue locally and use it in some of my pages where i require tables. I am not running a node.js server – My application is a python back-end with fastapi serving the endpoints and pages.
I have the following package.json and vite configurations that i use to bundle and try bundle aggrid for use in my pages.

package.json:

{
  "name": "frontend",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "build": "vite build"
  },
  "dependencies": {
    "ag-grid-vue3": "^33.1.1"
  },
  "devDependencies": {
    "vite": "^6.2.2"
  }
}

vite.config.js

import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
  build: {
    outDir: 'dist',
    lib: {
      entry: resolve(__dirname, 'dependencies/vite-entries/aggrid.js'),
      name: 'AgGrid',
      fileName: 'aggrid-bundle',
      formats: ['umd']
    },
    rollupOptions: {
      // Instead of making Vue external, we'll handle it differently
      output: {
        // Provide globals for UMD build
        globals: {
          vue: 'Vue'
        }
      }
    }
  },
  resolve: {
    // Ensure Vue is resolved correctly
    alias: {
      'vue': 'Vue'
    }
  },
  define: {
    'process.env': {
      NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'production')
    }
  }
});

aggrid.js

import { AgGridVue } from 'ag-grid-vue3';
import { AllCommunityModule, ModuleRegistry } from 'ag-grid-community'; 
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';

ModuleRegistry.registerModules([AllCommunityModule]);
if (typeof window !== 'undefined') {
  window.AgGrid = {
    AgGridVue
  };
}

export { 
  AgGridVue
};

after doing this i run an npm run build
this generates two files for which i can now include in my page

    <link rel="stylesheet" href="/libs/aggrid-bundle.css">
    <script src="/libs/aggrid-bundle.umd.js" type="module"></script>

the folowing is my table.js component where im trying to use this grid

export const DTable = {
    name: 'DataTable',
    components: { 'ag-grid-vue': window.AgGridVue },
    props: {
        containerId: { type: String, default: null },
        panelId: { type: String, default: null },
        data: {
            type: Object,
            default: null
        },
        dataModelType: {
            type: String,
            default: 'datatable'
        }
    },
    
    setup(props) {
        const { ref, onMounted, onUnmounted, watch, inject } = Vue;
        // Row Data: The data to be displayed.
        // Simple test data
        const rowData = ref([
            { make: "Tesla", model: "Model Y", price: 64950 },
            { make: "Ford", model: "F-Series", price: 33850 },
            { make: "Toyota", model: "Corolla", price: 29600 }
        ]);

        const colDefs = ref([
            { field: "make" },
            { field: "model" },
            { field: "price" }
        ]);
        
        // Add debugging
        onMounted(() => {
            console.log("AgGridVue component:", window.AgGrid.AgGridVue);
            console.log("Test data:", rowData.value);
            processData();
        });

        
        const gridOptions = ref({
            defaultColDef: {
                sortable: true,
                filter: true,
                resizable: true
            }
        });
        
        return {
            rowData,
            colDefs,
        };
    },
    template: `
        <!-- The AG Grid component -->
        <div style="height: 500px; width: 100%;" class="ag-theme-alpine">
            <ag-grid-vue
                style="height: 100%; width: 100%;"
                :column-defs="colDefs"
                :row-data="rowData">
            </ag-grid-vue>
        </div>
    `
};

the problem im running into is that there are no errors and the logs from the onMounted looks good. but no table is actually rendered. When i loook at the DOM that is rendered, it looks like this

<ag-grid-vue 
  column-defs="[object Object],[object Object],[object Object]" 
  row-data="[object Object],[object Object],[object Object]" 
  style="height: 100%; width: 100%;">
</ag-grid-vue>

The bindings seem to show objects that are never really rendered properly.
If you are familiar with AgGrid – i could use your help here.

update id name on html table elements when delete middle rows

i have HTML elements like this

<table id="table1">
    <thead>
        <tr>
            <th>EVALUATION</th>
            <th></th>
        </tr>
    </thead>
    <tbody>

    </tbody>
</table>
<input id="button_delete" type="button" onclick="deleteRow()" value="DELETE">
<input id="button_add" type="button" onclick="addRow()" value="ADD"> 

This is the code for addRow function

function addRow(){
    var tblList = document.getElementById("table1");
    var tblBody = tblList.tBodies[0];

    const lastRow = document.querySelector('#table1 tr:last-child td:first-child+td input') || 0;
    const length = tblBody.rows.length;

    try {
        var row = tblBody.insertRow(length);
    } catch(e) {
        console.log(e);
        return false;
    }

    var newCell0 = row.insertCell(0);
    newCell0.innerHTML = `
    <table style="width: 100%;">
        <tr>
            <td>
                <input type="checkbox" id="eval_cb0_${length}" name="eval_cb0_${length}" value="checked" >
            </td>
            <td>
                <label for="eval_cb0_${length}">EVAL 1</label>
            </td>
        </tr>
        <tr>
            <td>
                <input type="checkbox" id="eval_cb1_${length}" name="eval_cb1_${length}" value="checked" >
            </td>
            <td>
                <label for="eval_cb1_${length}">EVAL 2</label>
            </td>
        </tr>
    </table>
    `;

    var newCell1 = row.insertCell(1);
    newCell1.innerHTML = `
        <input class="row-cb" type="checkbox" name="cb_clone[]">
    `;
}

This is the code for deleteRow function

function deleteRow() {
    const checkboxes = document.querySelectorAll(".row-cb");

    const userConfirm = confirm("Are u sure?");
    if (!userConfirm) return;
    
    checkboxes.forEach((checkbox) => {
        if(checkbox.checked){
            const row = checkbox.closest('tr');
            row.remove();
        }
    });
}

The function addRow will add row in the last child of a table, and deleteRow will delete checked row. The problem is, when I delete middle row, i.e. row 2 from 3 rows available, then the row 3 element’s id still not updated even though there is only 2 rows remaining. How to update the row 3’s id name? Thanks

Step through matrix issues when wanting to go back one step for web app HTML,CSS JS

I have been learning web dev and have some minor knowledge of Python, so I set myself what I thought was a simple task of a set through the web app.
The first issue I’m stuck with (and I have no doubt there will be more when everyone looks at what I have so far) is that I have created sections that ask the user a Yes/No question. The user will click the corresponding button. I have also created a previous step button in case the user accidentally selects the wrong answer. As well as a back-to-main menu button.

Moving through the matrix shows only one section, which is fine. But at some point, when you drill through and want to go back a step or back to the start, it shows the last step, which isn’t what I want. Clicking back to the start will show the previous two sections/steps.

I feel this could be something simple I am missing, but I think I’m missing it when I try to debug

Also, I am curious if it would be better to do the backend logic with Python or if what I am doing is good enough for now, and I’m trying to overcomplicate it

What I want if the user clicks “back”

what I get instead

HTML
Made sure each section has a unique ID and includes the “Back” and “Start Over” buttons.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fire Tank Troubleshooting Guide</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>FFTTG System Won't Run</h1>
    </header>
    <main>
        <section id="step1">
            <h2>Step 1: System Won’t Turn On</h2>
            <p>Hydraulic Pump Won’t Run</p>
            <p>Are any LED’s illuminated on the Isolair Display Box?</p>
            <button onclick="nextStep('step2Yes')">YES</button>
            <button onclick="nextStep('step2No')">NO</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step2Yes" style="display:none;">
            <h2>Step 2: Toggle the Jettison Switch</h2>
            <p>Toggle the Jettison Switch a few times and make
                sure it is in the normal operating position -UP.
                Does the system turn on?</p>
            <button onclick="nextStep('step3.0Yes')">YES</button>
            <button onclick="nextStep('step3.1No')">NO</button>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step2No" style="display:none;">
            <h2>Step 2: Circuit Breakers</h2>
            <p>Have any of the Circuit Breakers on the Isolair
                Display box popped?</p>
            <button onclick="nextStep('step3.2Yes')">YES</button>
            <button onclick="nextStep('step3.3No')">NO</button>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step3.0Yes" style="display:none;">
            <h2>Step 3.1: Jettison Switch</h2>
            <p>Jettison Switch was in ‘off’
                position or was faulty and
                beginning to fail. If this was
                the case, change Jettison
                switch ASAP</p>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step3.1No" style="display:none;">
            <h2>Step 3.1: Change Cyclic Controller</h2>
            <p>Change Cyclic Controller. Does system turn on?</p>
            <button onclick="nextStep('step4.1Yes')">YES</button>
            <button onclick="nextStep('step4.2No')">NO</button>   
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step3.2Yes" style="display:none;">
            <h2>Step 3.2: Circuit Breakers</h2>
            <p>Reset and try again</p>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step3.3No" style="display:none;">
            <h2>Step 3.2: Ground Power?</h2>
            <p>Are you operating off ground power? (engines not running?)</p>
            <button onclick="nextStep('step214Yes')">214 Ground Power</button>
            <button onclick="nextStep('stepBUSNo')">204 & OR No</button>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step214Yes" style="display:none;">
            <h2>Step 214: Ground Power</h2>
            <p>Ensure ‘NON-ESSENTIAL BUS’ is in the Manual position. Does System now turn on?</p>
            <button onclick="nextStep('stepBUSYes')">Yes</button>
            <button onclick="nextStep('stepBUSNo')">No</button>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="stepBUSYes" style="display:none;">
            <h2>Step BUS: Manual Position</h2>
            <p>214’s must always have ‘Manual’ selected when checking from ground power</p>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="stepBUSNo" style="display:none;">
            <h2>Step NON-ESSENTIAL BUS / 204 / Ground power : Circuit Breakers Check</h2>
            <p>Check ALL relevant aircraft Circuit Breakers. Continue with part 2.2 Circuit Breakers Check</p>
            <button onclick="nextStep('stepCircuitBreakerCheck')">Circuit Breaker Check</button> <!-- Add Circuit Breaker check after building matrix-->
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step4.1Yes" style="display:none;">
            <h2>Change Cyclic Controller</h2>
            <p>Faulty Cyclic Controller. Use Wiring Diagram 6.1 to determine which switch (either Jettison or Door Switch) was faulty and replace ASAP</p>
            <button onclick="nextStep('FaultyCyclicController')">Cyclic Wiring Diagram</button> <!-- Add Cyclic Wiring Diagram after building matrix-->
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
        <section id="step4.2No" style="display:none;">
            <h2>Step 4.2: Change Pressure Switch</h2>
            <p>Change Pressure Switch. Does the system now turn on?</p>
            <button onclick="nextStep('step5.1Yes')">YES</button>
            <button onclick="nextStep('step5.2No')">NO</button>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver()">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button> 
        </section>
        <section id="step5.1Yes" style="display:none;">
            <h2>Step 5.1: Pressure Switch Change</h2>
            <p>Pressure Switch was faulty. Discard.</p>
            <button onclick="prevStep()">Back</button>
            <button onclick="startOver('step1')">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>   
        </section>
        <section id="step5.2No" style="display:none;">
            <h2>Step 5.1: Wiring Or Relays</h2>
            <p>Most likely a problem with wiring or relays. Begin a more thorough check, continue with para. 2.4.1- Tank Power Supply Check.</p>
            <button onclick="nextStep('TankPowerSupplyCheck')">Tank Power Supply Check</button> <!-- Add Tank Power Supply Check after building matrix-->
            <button onclick="prevStep()">Back</button>
            <p font="bold">If Checks fail to locate the Problem, begin troubleshooting <span style="color: red; text-transform: uppercase;">again</span></p>
            <button onclick="startOver('step1')">Start Over</button>
            <button onclick="mainMenu()">Main Menu</button>
        </section>
    </main>type here

JavaScript
Updated the JavaScript to handle the navigation history and ensure that only the current step is visible.
tried to ensure the prevStep and startOver functions are properly hiding the current step before showing the previous step or the first step.

let historyStack = [];

function nextStep(stepId) {
    const currentStep = document.querySelector('section:not([style*="display: none"])');
    if (currentStep) {
        historyStack.push(currentStep.id);
        currentStep.style.display = 'none';
    }
    document.getElementById(stepId).style.display = 'block';
}

function prevStep() {
    const currentStep = document.querySelector('section:not([style*="display: none"])');
    if (currentStep) {
        currentStep.style.display = 'none';
    }
    const prevStepId = historyStack.pop();
    if (prevStepId) {
        document.getElementById(prevStepId).style.display = 'block';
    }
}

function startOver(stepId) {
    const currentStep = document.querySelector('section:not([style*="display: none"])');
    if (currentStep) {
        currentStep.style.display = 'none';
    }
    historyStack = [];
    document.getElementById(stepId).style.display = 'block';
}

function mainMenu() {
    window.location.href = '/FFTTG/FFTG-Home.html';
}

CSS. I haven’t played around and debugged this too much as i don’t think this could be the issue

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f4f4f4;
}

header {
    background-color: #333;
    color: #fff;
    padding: 1em 0;
    text-align: center;
}


main {
    padding: 1em;
}

section {
    margin-bottom: 1em;
}

button {
    margin: 0.5em;
    padding: 0.5em 1em;
    background-color: #007bff;
    color: #fff;
    border: none;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

footer {
    background-color: #333;
    color: #fff;
    text-align: center;
    padding: 1em 0;
    position: fixed;
    width: 100%;
    bottom: 0;
}

.card {
    border: 1px solid #ccc;
    padding: 1em;
    margin: 1em 0;
    background-color: #fff;
}

.card img {
    max-width: 100px;
    margin-right: 10px;
    vertical-align: middle;
}

#Control-box-front {
    transition: all 0.3s ease;
}

#Control-box-front:hover {
    content: url('public/images/Control-box-front-green.png');
}
/* From Uiverse.io by chase2k25 */ 
.card {
    width: 400px;
    height: 400px;
    border-radius: 8px;
    background: linear-gradient(145deg, #333, #000);
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding: 0.4em;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
    overflow: hidden;
  }
  
  .card p {
    flex: 1;
    overflow: hidden;
    cursor: pointer;
    border-radius: 8px;
    transition: flex 0.5s;
    background: linear-gradient(145deg, #212121, #000);
    display: flex;
    justify-content: center;
    align-items: flex-start; /* Align items at the top */
  }
  
  .card p:hover {
    flex: 4;
  }
  
  .card p span {
    padding: 0.2em;
    text-align: center;
    transform: rotate(-0deg);
    transition: transform 0.5s;
    text-transform: uppercase;
    color: white;
    font-weight: bold; /* Removed quotes */
    letter-spacing: 0.1em;
    position: relative;
    z-index: 1;
  }
  
  .card p:hover span {
    transform: rotate(0);
  }
  
  .card p::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(255, 255, 255, 0.1);
    z-index: 0;
    transition: opacity 0.5s;
    pointer-events: none;
    opacity: 0;
  }
  
  .card p:hover::before {
    opacity: 1;
  }
  .card p img {
    max-width: 350px;
    margin-right: 10px;
  }

How to properly handle mutually exclusive checkbox selection with reactive forms

I need some assistance with handling checkbox selection using angular. I have 4 checkboxes, ALL, FirstName, LastName, MiddleName. When the page loads ALL should be the only one selected. If I click any of the other boxes ALL should be deselected. Likewise if I click ALL again the other checkboxes should be deselected. Currently ALL is selected when the page loads. I then can click the other boxes. However I can’t click ALL unless I manually uncheck the other boxes. Any assistance you can provide will be greatly appreciated.

I am using component projection to include the child form type filter in the parent.html.

— parent html

<form [formGroup]="reportListFG">
<app-form-type-filter 
                  [formGroup] ="reportListFG.get('filterGroup')"
                  (formTypeFilterChanged)="onFormTypeSelectionChange($event)"
                  (clear)="clearReceipt($event)" 
                  #formFilter></app-form-type-filter>

—parent ts

this.reportListFG = this.fb.group(
    {
      Address: [[]],
      PhoneNumber: [[]],
      filterGroup: this.fb.group({
      ALL: [true],
      FirstName: [false],
      LastName: [false],
      MiddleName: [false],
      }),
      
    
  )
  // Listen to form changes and handle the logic for "All" and other checkboxes
this.reportListFG.get('filterGroup').valueChanges.subscribe(values => {
  this.handleCheckboxSelection(values);
});

}

  handleCheckboxSelection(values: any) {
  const allSelected = values.ALL; 

  console.log('Inside handleCheckbox');

  // If "All" is selected and another box is checked, uncheck "All"
  if (allSelected && (values.FirstName || values.LastName || values.MiddleName)) {
    this.reportListFG.get('filterGroup')?.patchValue(
      {
        ALL: false
      },
      { emitEvent: false } // Prevent infinite loop
    );
  }

  // If "All" is selected, ensure other checkboxes remain unchecked
  else if (allSelected) {
    console.log(allSelected, '********');
    this.reportListFG.get('filterGroup')?.patchValue(
      {
        FirstName: false,
        LastName: false,
        MiddleName: false
      },
      { emitEvent: false } // Prevent infinite loop
    );
  }
}

Skip to next step on timeout

I’m leveraging Puppeteer to open a website from a list of URLs, grab a few pieces of data, then write to CSV.

While there are a few elements that could be collected from a given URL, not all URLs will have all elements.

When my code is unable to find one of the stated elements (xpath) it times out and stops the code altogether. Instead of doing this, I would like it to either enter null or 0 to indicate that no data was actually gathered from the URL for that element.

I tried adjusted the duration until timeout but it doesn’t move to the next step, it just exists the script altogether (as it does with the default timeout).

As there will be instances where the xpath can’t be found, I don’t want to disable timeout as it will just loop forever at that point.

Here’s my code as it currently stands:

const puppeteer = require('puppeteer');
const fs = require('fs');
const csv = require('csv-parser');
const createCsvWriter = require('csv-writer').createObjectCsvWriter;

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  
  const urls = [];
    fs.createReadStream('urls.csv')
        .pipe(csv())
        .on('data', (row) => {
            urls.push(row.url); // Assuming the CSV has a column named 'url'
        })
        .on('end', async () => {
                       
            for (const url of urls) {
                await page.goto(url, { waitUntil: 'networkidle2' });
                const url_visited = url

                //* PRICE 1

                    let xpath_ELEMENT_1 = 'XPATH';
                    const el1 = await page.waitForSelector('xpath/' + xpath_ELEMENT_1);
                    const ELEMENT_1 = await page.evaluate(el => el.textContent.trim(), el1);

                //* PRICE 2

                    let xpath_ELEMENT_2 = 'XPATH';
                    const el1 = await page.waitForSelector('xpath/' + xpath_ELEMENT_2);
                    const ELEMENT_2 = await page.evaluate(el => el.textContent.trim(), el2);


// create csv file
const csvWriter = createCsvWriter({
    path: 'output.csv',
    header: [
        {id: 'url', title: 'URL'},
        {id: 'price1', title: 'Price1'},
        {id: 'price2', title: 'Price2'}
    ]
});

// create record using collected data
const records = [
    {url: url_visited, price1: ELEMENT_1, price: ELEMENT_2}
]

// write record to csv
await csvWriter.writeRecords(records);
}

await browser.close();
});
})();```

validated email using jquery [closed]

I have a problem verifying email address with script below, its not working even if i enter correct email format, it doesn’t move to next hidden div

<script>
        $('#fobtn').click(function(){
        var email = $('#email').val();
        var regex = /^([a-zA-Z0-9_.-+])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/;
        if( !$(this).val() ) {
          $("#error").html("email needed cant leave this blank");
          return false;
    } 
    
    
        if(!regex.test(email)) {
           $("#error").html("valid email needed");
           return false;
        }
      
    
    else{
  $('#hidden1').hide();
  $('#hidden2').show();
  }
  
});
</script>

To store user’s input from HTML pages during navigation from one page to another in Google Web Application

I try to made a google web application with multipage where user has to tick or untick on checkboxes based on applicable. I need to save those checkboxes status on HTML page using local storage during page navigation. If he navigate between pages then can see his selection. But unable to store and retrieve the data. As i am learning apps script so please guide me. Also if i return back to my first page then also can load my filled checkbox.

//HTML First Page

label>Cricket</label>
<input id="cb1" type="checkbox">
label>Football/label>
<input id="cb2" type="checkbox">

//Java Script to store using local storage

let cricketCheckbox = document.getElementById("cb1").checked;
let footballCheckbox = document.getElementById("cb2").checked;
localStorage.setItem("checkbox1","cricketCheckbox");
localStorage.setItem("checkbox2","footballCheckbox");

//HTML SecondPage

label>Singing</label>
<input id="cb3" type="checkbox">
label>Dancing/label>
<input id="cb4" type="checkbox">

//Java Script to retrive using local storage

let cricketStatus = localStorage.getItem("checkbox1");
let footballStatus = localStorage.getItem("checkbox2");
let singingStatus = document.getElementById("cb3").checked
let dancingStatus = document.getElementById("cb4").checked

Loop in Jquery DataTable and change css only in specific rows

I need to loop inside my Datatable, and I want to change background-color attribute only in some rows at specific index, so I need to have control over the index of the table.

My idea is to extract a single tr on a specific position, so
I was trying to write this code, I don’t have any error in console, I see it prints the correct number of index for each row, but nothing happen on the table, the css is not applied.

var myTable = $('#food').DataTable();
$('#button').on('click', function () {
    $('#food > tbody > tr').each(function(index, tr) { 
       console.log(index);
       $("#food tr:nth-child("+index+")").addClass('change-color');
     });
});


 .change-color{
      background-color: #FFFFAC;
  }

Using TUIEditor in WTForms

I need to use a rich text editor on a web application. I’ve chosen Toast UI editor: https://nhn.github.io/tui.editor/latest/.

The application is developed in python using cherrypy. My forms are managed using WTForms.

I can’t understand how to create a custom widget in WTForms based on the TUI Editor. More generally speaking, the problem is to use WTForms on 3rd party “complex” web widgets.

Can you help me?

Thanks a lot!

Vitest + Playwrigth + LitElement, browser not working

TL;DR

I want to run my unit tests using Vitest but when using the fixture from @open-wc, it doesn’t.

The problem

I have a project using Lit Element with a lot of unit tests and I’m using Playwright as a runner for everything now (using @web/test-runner-playwright).

This is what a test typically looks like:

import { expect, fixture, html } from '@open-wc/testing';

describe('MyComponent', async () => {
  it('should exist', async () => {
    const myComponent = /** @type {MyComponent} */ (
      await fixture(html`
        <my-component></my-component>
      `)
    );

    expect(myComponent).to.exist;
  }
})

To get started with the setup, I used npx vitest init browser.
It created vitest.config.js & an example.
I added set environment to jsdom and that’s about it for my config:

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'jsdom',
    browser: {
      enabled: true,
      provider: 'playwright',
      instances: [{ browser: 'chromium' }],
    },
  },
});

I went ahead and changed my import to use Vitest in my tests instead:

-import { expect } from '@open-wc/testing';
+import { describe, it, expect } from 'vitest';

But now it go interesting, for unit test not using the browser, not problem is works as expected:
enter image description here

But on the others, I get an error:
enter image description here

I was expecting the import { fixture } from '@open-wc/testing'; to be enough to mount the dom element needed for the test. This what is used for the vue & react example on the Vitest documentation.

It feels like I’m missing something obvious here.

What I tried:

  • Adding loaders to follow the React config for example but it didn’t change anything.
import { litStyleLoader, litTemplateLoader } from '@mordech/vite-lit-loader';

export default defineConfig({
  plugins: [litStyleLoader(), litTemplateLoader()],
// ...
  • Changed the environment to happy-dom, same.

Modal image gallery displaying incorrect image while loading

I’m making a portfolio website that contains multiple modal image galleries – but a consistent issue I’m having is that when first viewing a large modal image it will display the previously clicked image while waiting for the current one to load.
I’ve tried fiddling with the JavaScript to make it so upon closing a modal it resets the data URL completely so it is unable to display the previous image, but have had no luck.

Here is the code:

var imageDivs = document.querySelectorAll(".artwork");

imageDivs.forEach(function(div) 
{ 
  div.addEventListener("click", function(e) 
  { 
    const overlay = document.getElementById("full-res-overlay");
    const fullResImage = document.getElementById("full-res-image");
    const captionText = document.getElementById("caption");
    fullResImage.src = this.dataset.url;
    overlay.style.display = "block";
    captionText.innerHTML = this.dataset.text;
  });
});

document.querySelector("#full-res-overlay").addEventListener("click", function(e) {
  this.style.display = "none";
});

   
 .gallery-container {
        width: 98%;
        max-width: 98%;
        padding: 0;
        background-color: transparent;
        border-radius: 10px;
        text-align: center;
      }
      
  .artwork-container {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 20px;
      }
  .artwork {
        cursor: url('/KISSCURSEGREEN.png'), pointer;
        width: 18vw;
        height: 25vw;
        max-width: 100%;
        position: relative;
        
      }
  
  .artwork:hover {
        opacity: 0.8;
        transform: scale(95%);
        transition: opacity 0.3s ease;
        transition: transform 0.3s ease;
      }
  
 .artwork img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
       
      
   
      .full-res-overlay {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.9);
        z-index: 10; 
        text-align: center;
}
.full-res-image {
        max-width: 80%;
        max-height: 80%;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }
      
      .caption {
  
  font-size: 2vw;
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
  text-align: center;
  color: #ccc;
  height: 150px;
  
}
 <div class="gallery-container expanded" >
              <div class="artwork-container">
 
 <div
            class="artwork" style="width: 23vw; height: 22vw;"
            data-url="https://sinniister.neocities.org/ARTWORK/2023VW/2023VW5.JPG" data-text="DEATHBIRD | 19.06"
          >
            <img
              src="https://sinniister.neocities.org/ARTWORK/2023VW/2023VW5S.JPG"
             />
          </div>
          
          <div
            class="artwork" style="width: 26vw; height: 22vw;"
            data-url="https://sinniister.neocities.org/ARTWORK/2024VW/2024VW3.JPG" data-text="SCP-173 | 29.05"
          >
            <img
              src="https://sinniister.neocities.org/ARTWORK/2024VW/2024VW3S.JPG"
             />
          </div>
          </div>
          </div>
          
           <div
      class="full-res-overlay"
      id="full-res-overlay"
      onclick="closeFullRes()"
    >
      <img
        src=""
        alt="Full Resolution Artwork"
        class="full-res-image"
        id="full-res-image"
      />
      
      <div id="caption" style="color: white;"
      ></div>
      
    </div>
          

Using Singleton Logger class in Nestjs

I have a web application on Nest.js where I make use of pino to log exceptions .

Service1.ts

import {Logger} from 'nestjs-pino';

export class Service1{
constructor(private readonly logger : Logger) {}

async Do()
{

...
 this.logger.log("Log1");
}
}

Service2.ts

import {Logger} from 'nestjs-pino';

export class Service2{
constructor(private readonly logger : Logger) {}

async DoOtherWork()
{

...
 this.logger.log("Log1");
}
}

Since the Service files will be called from multiple UI operations so my understanding is multiple Logger classes will be created .
So , is it a good idea to have Logger as a Singleton class ?

How can I make changes to the Nest.js application to have Logger as a singleton class with thread safety?

How to Access the Shadow DOM of a Custom Element in Vue Vitest

I’m working on a Vue component that contains a custom element with a shadow DOM. I want to test the content inside the shadow root of this custom element using Vue Test Utils. However, when I use wrapper.find("custom-element").html(), it only returns the outer HTML of the wrapper element, not the content inside the shadow DOM.

What I’ve Tried:
I’ve tried using

wrapper.find(“custom-element”).shadowRoot

and

wrapper.find(“custom-element”).element.shadowRoot

, but I’m still unable to access the HTML inside the shadow DOM.

Expected Behavior:
I want to be able to access and test the content inside the shadow DOM of the custom element.

What I Need Help With:
How can I correctly access the shadow DOM of a custom element in Vue Test Utils and retrieve its HTML content for testing purposes? Are there any additional steps or considerations I need to keep in mind when working with shadow DOMs in unit tests?

Any help would be greatly appreciated! Thank you in advance!