When the modal/dialog tag is open the selected id is wrong

I’m creating a simple CRUD, it’s already create, read and delete but does not update properly yet.

When the modal/dialog tag gets opened, for some reason the id of the collect is wrong, it always get the id of the first collect in the list.

for example, if there is id 1, 2 and 3 in the list and I click to edit the id 3, the modal/dialong tag gets opened, but the id is 1 and instead of updating the item list I’m clicking it always update the first item of the list.

this is part of the code where the collects are displayed and has the EditModal component.

import axios from "axios";
import {useState, useEffect} from "react";
import EditModal from "./EditModal.jsx";

function DisplayCollects() {

    const [data, setData] = useState([]);
    const [input, setInput] = useState({
        company: "",
        date: "",
        product: "",
    })

    useEffect(() => {
        async function fetchData() {
            try {
              const result = await axios("http://localhost:3000/");
              setData(result.data);
            }
            catch (err) {
              console.error(err);
            }
            
          }

          fetchData();
    }, [])

    function handleInput(event) {
        const {name, value} = event.target;
        if (name == "company") {
            setInput({...input, company: value});
        }
        if (name == "date") {
            setInput({...input, date: value});
        }
        if (name == "product") {
            setInput({...input, product: value});
        }
    }

    async function addCollect() {
        try {
            await axios.post("http://localhost:3000/add", input);
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function doneCollect(itemId) {
        try {
            await axios.post("http://localhost:3000/done", {itemId});
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function deleteCollect(itemId) {
        try {
            await axios.post("http://localhost:3000/delete", {itemId});
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function editCollect(input) {
        try {
            await axios.post("http://localhost:3000/edit", input);
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    return (
        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Empresa</th>
                    <th>Data</th>
                    <th>Material</th>
                </tr>
            </thead>
            <tbody>
            {data.map((item, index) =>
                <tr key={index} className="mainRow">
                    <td>{item.id}</td>
                    <td>{item.company}</td>
                    <td>{item.date}</td>
                    <td>{item.product}</td>
                    <td><img onClick={() => doneCollect(item.id)} src="/assets/images/done.png" alt="done button"/></td>
                    <td><EditModal id="form" editCollect={editCollect} itemId={item.id}/></td>
                    <td><img onClick={() => deleteCollect(item.id)} src="/assets/images/delete.png" alt="delete button"/></td>
                </tr>
            )} 
            </tbody>
            <tbody>
                <tr>
                    <td></td>
                    <td><input onChange={handleInput} value={input.company} type="text" name="company" placeholder="Empresa"/></td>
                    <td><input onChange={handleInput} value={input.date} type="text" name="date" placeholder="Data"/></td>
                    <td><input onChange={handleInput} value={input.product} type="text" name="product" placeholder="Material"/></td>
                    <td><img src="/assets/images/add.png" alt="add button" onClick={addCollect}/></td>
                </tr>
            </tbody>
        </table>
    )
}

export default DisplayCollects;

this is the EditModal component:

import { useState } from "react";

function EditModal({editCollect, itemId}) {

    console.log(itemId);
    const [input, setInput] = useState({
        input: itemId,
        company: "",
        date: "",
        product: "",
    });

    function handleInput(event) {
        const {name, value} = event.target;
        if (name == "company") {
            setInput({...input, company: value});
        }
        if (name == "date") {
            setInput({...input, date: value});
        }
        if (name == "product") {
            setInput({...input, product: value});
        }
    }

    function openDialog() {
        const dialog = document.getElementById("form");
        dialog.showModal();
    }

    return (
        <>
            <dialog id="form">
                <table>
                    <thead>
                        <tr>
                            <th>Empresa</th>
                            <th>Data</th>
                            <th>Material</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td><input onChange={handleInput} value={input.company} type="text" name="company" placeholder="Empresa"/></td>
                            <td><input onChange={handleInput} value={input.date} type="text" name="date" placeholder="Data"/></td>
                            <td><input onChange={handleInput} value={input.product} type="text" name="product" placeholder="Material"/></td>
                            <td><img onClick={() => editCollect(input)} src="/assets/images/done.png" alt="done button"/></td>
                        </tr>
                    </tbody>
                </table>
            </dialog>
            <img onClick={openDialog} src="/assets/images/edit.png" alt="edit button"/>
        </>
    )
}

export default EditModal;

and this is the backend:

app.post("/edit", async (req, res) => {
    console.log(req.body);
    try {
        await db.query("UPDATE coletas SET company = $1, date = $2, product = $3 WHERE id = $4", [req.body.company, req.body.date, req.body.product, req.body.input]);
        res.send("ok");
    }
    catch (err) {
        console.error(err);
    }
})

an image to better illustrate, the first 3 consoles are the id of each item in the list, I clicked to edit the last item, but when I’m typing it logs the id of first item and send the id of first item to the backend if I click the done button.

enter image description here

updates react-leaflet clusters and markers

please explain why when updating markers on the map, all clusters disappear for a moment, and then reappear. How do I make marker updates happen seamlessly for the user?

this is code parent component MapForm:

import { observer } from "mobx-react-lite";
import {
  MapContainer,
  Marker,
  Popup,
  TileLayer,
  Polyline,
  LayersControl,
  LayerGroup,
  Circle,
  FeatureGroup,
  Rectangle,
  useMap,
} from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L, { rectangle } from "leaflet";
import Form from "react-bootstrap/Form";
import "bootstrap/dist/css/bootstrap.min.css";
import styles from "./MapForm.module.css";
import DynamicMarkersLayer from "./DynamicMarkersLayer";

// Импортируем изображения маркеров
import markerIcon from "leaflet/dist/images/marker-icon.png";
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
import markerShadow from "leaflet/dist/images/marker-shadow.png";
import { useContext, useEffect } from "react";
import { Context } from "../../main";
// Фикс для маркеров
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: markerIcon2x,
  iconUrl: markerIcon,
  shadowUrl: markerShadow,
});

// Создаем отдельный компонент для обработки событий карты
const MapEventHandler = observer(() => {
  const { store } = useContext(Context);
  const map = useMap();

  useEffect(() => {
    const debounceTimer = { current: null };

    const handleMoveEnd = () => {
      clearTimeout(debounceTimer.current);
      debounceTimer.current = setTimeout(() => {
        const bounds = map.getBounds();
        if (!store.prevBounds || !bounds.equals(store.prevBounds)) {
          store.sendBounds(bounds);
          store.prevBounds = bounds;
        }
      }, 300);
    };


    map.on("zoomend", handleMoveEnd);
    map.on("moveend", handleMoveEnd);

    handleMoveEnd(); // Первоначальная загрузка

    return () => {
      map.off("moveend", handleMoveEnd);
      map.off("zoomend", handleMoveEnd);
    };
  }, []);

  return null;
});

function MapForm() {
  const center = [55.75281851900141, 37.61597512353604];

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
      <div className={styles.selectContainer}>
        <Form.Select aria-label="Выберите даты" className={styles.optionSelect}>
          <option>Выберите дату</option>
          <option value="1">Сегодня</option>
          <option value="2">Вчера</option>
        </Form.Select>
      </div>

      <div style={{ flex: 1, position: "relative" }}>
        <MapContainer
          center={center}
          zoom={10}
          style={{ height: "100%", width: "100%" }}
        >
          <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />

          {/* Добавляем обработчик событий карты */}
          <MapEventHandler />

          <LayersControl position="topleft">
            <LayersControl.Overlay name="Wi-Fi_AP" checked>
              <DynamicMarkersLayer />
            </LayersControl.Overlay>

            <LayersControl.Overlay name="Трек" checked>
              <Marker position={center}>
                <Popup>A pretty CSS3 popup. <br /> Easily customizable.</Popup>
              </Marker>
            </LayersControl.Overlay>

            <LayersControl.Overlay checked name="Layer group with circles">
              <LayerGroup>
                <Circle
                  center={center} //Ваня пиздюн Б6
                  pathOptions={{ fillColor: "blue" }}
                  radius={200}
                />
                <Circle
                  center={center}
                  pathOptions={{ fillColor: "red" }}
                  radius={100}
                  stroke={false}
                />
                <Circle
                  center={[51.51, -0.08]}
                  pathOptions={{ color: "green", fillColor: "green" }}
                  radius={100}
                />
              </LayerGroup>
            </LayersControl.Overlay>
          </LayersControl>
        </MapContainer>
      </div>
    </div>
  );
}

export default observer(MapForm);

this is code DynamicMarkersLayer:

import { LayersControl, Marker, Popup, useMap } from "react-leaflet";
import { useContext, useEffect, useMemo, useRef } from "react";
import { observer } from "mobx-react-lite";

import { Context } from "../../main";
import MarkerClusterGroup from "react-leaflet-markercluster";
import "react-leaflet-markercluster/styles";


function DynamicMarkersLayer() {
  const { store } = useContext(Context);
  const m =[...store.markers]

  const markerHash = m.length > 0 ? m.reduce((acc, marker) => acc+marker.id) - Date.now() : 'empty';
  
  return (
    
    <MarkerClusterGroup
    key={`cluster - ${markerHash}`}
      chunkedLoading
      chunkInterval={100}
      spiderfyOnMaxZoom={true}
      showCoverageOnHover={false}
      maxClusterRadius={60}
      spiderLegPolylineOptions={{
        weight: 1,
        color: '#222',
        opacity: 0.5
      }}
      spiderfyDistanceMultiplier={1.5}
      animate={true}
      animateAddingMarkers={true}
      disableClusteringAtZoom={18}
      removeOutsideVisibleBounds={false}
    >
      {m.map((marker) => {
        // console.log(`${marker.id - marker.version || 0}`)
        return(
        <Marker
          key={`${marker.id - marker.version}`}
          // key='0'
          position={[marker.lat, marker.lng]}
        >
          {/* <Popup>
            <div>
              <h4>{marker.name}</h4>
              <p>Координаты: {marker.lat}, {marker.lng}</p>
            </div>
          </Popup> */}
        </Marker>
      )})}
    </MarkerClusterGroup>
  );
}

export default observer(DynamicMarkersLayer)

Now, when changing bounds, a response with a set of coordinates is correctly received from the server, but the old layer disappears for a moment on the map before it is displayed, which is inconvenient with frequent updating of the dataset.

How can I calculate someone’s zodiac sign from their birth date using plain JavaScript? [closed]

I’ve searched around, and most examples I found are either in Python, PHP, or rely on full birth date/time (including the year or even hour of birth).
What I’m looking for is something much simpler:

I want to calculate someone’s Western zodiac sign based only on the day and month of birth, using plain JavaScript (no external libraries or APIs).

Example input: April 15 → output: Aries.

Is there a clean and reliable way to do this in JS, without relying on libraries?

No response to Fetch request in chrome extension background script

enter image description here

I’m trying to write a chrome extension to grab some stored data and POST it to a remote db table. I’m trying to testing the post functionality using https://www.postb.in/. I am using a devtools panel that I’ve added. I’ve stepped through the code and it seems to be working up until about line 37 in background.js. What am I doing wrong?

Panel.js contains:

const toDbBtn = document.getElementById("toDbBtn");

toDbBtn.addEventListener("click", async () => {
  const dbName = document.getElementById("textBox").value;

  try {
    const result = await chrome.storage.local.get(["yourKey"]);

    if (result.yourKey) {
      const savedArray = JSON.parse(result.yourKey);
      console.log(result.yourKey);
      console.log("Saved Array:", savedArray);
      console.log("DB Name:", dbName);
      console.log("Type of result.yourKey:", typeof result.yourKey);
      console.log("Type of savedArray:", typeof savedArray);
      console.log("Is savedArray an array?", Array.isArray(savedArray));

      // Send message to background script
      const response = await chrome.runtime.sendMessage({
        action: "sendToDB",
        data: { dbName: dbName, savedArray: result.yourKey },
      });

      if (response.error) {
        console.error("Error:", response.error);
      } else {
        console.log("Success:", response.result);
      }
    } else {
      console.log("No data found in storage to send.");
    }
  } catch (error) {
    console.error("Error during storage or message sending:", error);
  }
});

background.js:

chrome.runtime.onConnect.addListener(port => {});

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
  if (request.action === "sendToDB") {
    const { dbName, savedArray } = request.data;

    if (typeof dbName !== 'string' || typeof savedArray !== 'string') {
      sendResponse({ error: 'Invalid data types' });
      return false;
    }

    let parsedArray;
    try {
      parsedArray = JSON.parse(savedArray);
    } catch (e) {
      sendResponse({ error: 'Invalid JSON string for savedArray' });
      return false;
    }

    const data = {
      dbName: dbName,
      savedArray: parsedArray,
    };

    const postable = JSON.stringify(data);
    console.log("postable", postable);

    try {
      const response = await fetch("https://www.postb.in/1743970496740-3388752799946", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: postable,
      });

      const result = await response.json();
      console.log("Response from server:", result);
      sendResponse({ result: result });
    } catch (error) {
      sendResponse({ error: error.message });
    }

    return true; // Required for asynchronous response
  }
  return false; // Required if the message is not for this listener
});

manifest.json:

{
  "manifest_version": 3,
  "name": "myDevTools",
  "version": "1.0",
  "description": "Description of your extension",
  "devtools_page": "devtools.html",

  "host_permissions": [
    "*://*.cnn.com/",
    "https://www.postb.in/*"
  ],
  "permissions": [
    "storage",
    "activeTab",
    "scripting",
    "webNavigation",
    "tabs",
    "unlimitedStorage",
    "cookies",
    "alarms",
    "notifications",
    "contextMenus",
    "offscreen",
    "identity",
    "identity.email",
    "nativeMessaging",
    "browsingData"
  ],
  "background": {
    "service_worker": "background.js"
  }
}

Why is a fetch of missing resource’s URI take me straight to the catch block?

I’m using the Fetch API for the first time, running some code within a (recent version of) Thunderbird:

let uri = whatever();
window.fetch(uri)
  .then((response) => {
    console.log(`got response with status ${response.status}`);
    if (!response.ok) {
      throw new Error(`thrown response status: ${response.status}`);
    }
    return response.text();
  })
  .then((xhtml) => doStuff(xhtml))
  .catch((err) => console.error(`fetching failed: ${err}`));

When I run this with a URI at which a relevant resource exists, it works (i.e. doStuff() does its stuff). But when I run this with a URI with a valid server, but with a path to a missing page – I don’t really get what I expected… the error console shows me:

fetching failed: TypeError: NetworkError when attempting to fetch resource.

So, I’m hitting the catch block, but not with the error I threw in the then block.

My question: Why is that the case? And – what can I do to be able to distinguish the situation of the resource being missing from other errors (like: Can’t connect to server, timeout, etc.)?

Note: If any additional information is necessary, please ask in a comment.

How to bundle node:crypto createDecipheriv for use in the browser?

I’m trying to bundle the makeTLSClient function from here https://github.com/vkrot-cell/tls to make sure the claims are true and correct and to eventually use as described here https://github.com/explainers-by-googlers/verifyTLSServerCertificateForIWA?tab=readme-ov-file#example-with-direct-sockets-and-tls, mainly for the server that is implemented in the browser as described here https://github.com/digitalbazaar/forge?tab=readme-ov-file#transports-1.

This is what bun build spits out

bun build --target=browser lib/make-tls-client.js --outfile=bun-browser-bundle.js 
4 | import { createDecipheriv } from 'crypto';
             ^
error: Browser polyfill for module "node:crypto" doesn't have a matching export named "createDecipheriv"
    at /home/user/bin/wt/tls/lib/crypto/aes-cbc.js:4:10

4 | import { createDecipheriv } from 'crypto';
             ^
note: Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to "node" or "bun" in the transpiler options.
   at /home/user/bin/wt/tls/lib/crypto/aes-cbc.js:4:10

tsc does compile the source to JavaScript. I don’t think tsc ever handles the fact that the target is the browser where node:crypto is not defined.

I’ve ran in to this before, where I found out it’s impossble to polyfill node:crypto because internal node code is used that can’t be exported, something like the use of primordials in Node.js source code.

I think I might be able to use the forge browser code. However, I’m still wondering how the author managed to compile the source code in https://github.com/vkrot-cell/tls to a script that can be used in the browser?

Is deno compile really panicking just because of @ symbol?

I’ve compiled tsc nightly to a standalone executable previously.

All of a sudden deno is panicking, apparently due to the @next in npm:typescript@next/tsc.

Is deno compile really panicking just because of that @ symbol in npm:typescript@next/tsc?

RUST_BACKTRACE=full deno compile -A --node-modules-dir=auto --allow-scripts npm:typescript@next/tsc
============================================================
Deno has panicked. This is a bug in Deno. Please report this
at https://github.com/denoland/deno/issues/new.
If you can reliably reproduce this panic, include the
reproduction steps and re-run with the RUST_BACKTRACE=1 env
var set and include the backtrace in your report.

Platform: linux x86_64
Version: 2.2.8+6f406c1
Args: ["deno", "compile", "-A", "--node-modules-dir=auto", "--allow-scripts", "npm:typescript@next/tsc"]

View stack trace at:
https://panic.deno.com/v2.2.8+6f406c1/x86_64-unknown-linux-gnu/i9j8tEu8i16Fgztm7Fgytm7Fgn7m7Fgg-rwEmiuprFmpgpnEo03krEs_v2uE4hy2_Dsgt2_Dkx4opEqzzopEsi1opEq_jwrEkiw4tE61z4kEklo8tEmvi8hEgll8uEg94Jgo5JggwltCA

thread 'main' panicked at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/deno_semver-0.7.1/src/lib.rs:313:32:
programming error: cannot use matches with a tag: next
stack backtrace:
   0:     0x5605ba046a39 - <unknown>
   1:     0x5605b8b227a3 - <unknown>
   2:     0x5605ba045a92 - <unknown>
   3:     0x5605ba046893 - <unknown>
   4:     0x5605ba046036 - <unknown>
   5:     0x5605b89e1b1c - <unknown>
   6:     0x5605ba0457ac - <unknown>
   7:     0x5605ba08abc8 - <unknown>
   8:     0x5605ba08ab29 - <unknown>
   9:     0x5605ba08c68c - <unknown>
  10:     0x5605b8b20c1f - <unknown>
  11:     0x5605b9896c85 - <unknown>
  12:     0x5605b8698beb - <unknown>
  13:     0x5605b8884318 - <unknown>
  14:     0x5605b8a4b25c - <unknown>
  15:     0x5605b82cc172 - <unknown>
  16:     0x5605b82caf81 - <unknown>
  17:     0x5605b8794ef4 - <unknown>
  18:     0x5605b879380b - <unknown>
  19:     0x5605b8793ad0 - <unknown>
  20:     0x5605b88b2309 - <unknown>
  21:     0x5605b89d31d6 - <unknown>
  22:     0x5605b85537de - <unknown>
  23:     0x5605b89e38ea - <unknown>
  24:     0x5605b83e14f9 - <unknown>
  25:     0x5605b8a61ed5 - <unknown>
  26:     0x7ff3eb7bb24a - <unknown>
  27:     0x7ff3eb7bb305 - __libc_start_main
  28:     0x5605b6987029 - <unknown>
  29:                0x0 - <unknown>

SyntaxError: Unexpected token masonry [closed]

Helo
In my file functions.js, i have code:

$(document).ready(function(){ 
    $("#menu-responsive div.menu").hide(); 
    $('#menu-responsive').click(function(){
    $("#menu-responsive div.menu").slideToggle();
    }); 
});
<script>
var $container = $('.memberlist-grid');
// initialize
$container.masonry({
  itemSelector: 'li'
});
</script>

Validate chrome is error:

Uncaught SyntaxError: Unexpected token '<' (at functions.js:7:1)

What should be a good code? Please help me 🙂

SyntaxError: Unexpected token js [closed]

Helo
In my file functions.js, i have code:

$(document).ready(function(){ 
    $("#menu-responsive div.menu").hide(); 
    $('#menu-responsive').click(function(){
    $("#menu-responsive div.menu").slideToggle();
    }); 
});
<script>
var $container = $('.memberlist-grid');
// initialize
$container.masonry({
  itemSelector: 'li'
});
</script>

Validate chrome is error:

Uncaught SyntaxError: Unexpected token '<' (at functions.js:7:1)

What should be a good code? Please help me 🙂

Using dom component or image instead as label of bar chart on react chartjs v4 [duplicate]

I have bar chart like this,

const data = {
    labels:['book','desk'],
    datasets: [
      {
        label: 'My Data',
        data: [10,20],
        backgroundColor: 'rgba(255, 99, 132, 0.5)',
      },
    ],
 }

 <div style={{width:"800px"}}><Bar options={bar_options} data={data} /></div>

It shows the bar charts which has label book and desk

However I want to change the label to image, so I use options like this but in vain.

const bar_options = {
  responsive: true,
  indexAxis: 'y',
  plugins: {
    labels:{
      render: 'image',
      images: [{
        src:"book.jpg",
        height:25,
        width:25
      },{
        src:"desk.jpg",
        height:25,
        width:25
      }
     ]
    },
  },
};

How can I use book.jpg and desk.jpg instead of book and desk

Or if possible I want to render not only image using dom component such as

<div><p>book</p><img src="book.jpg></div>

Use image instead of label of bar chart chart.js [duplicate]

I have bar chart like this,

const data = {
        labels:['book','desk']
        datasets: [
          {
            label: 'My Data',
            data: [10,20],
            backgroundColor: 'rgba(255, 99, 132, 0.5)',
          },
        ],
      };
 }

 <div style={{width:"800px"}}><Bar options={bar_options} data={data} /></div>

It shows the bar charts which has label book and desk

However I want to change the label to image, so I use options like this but in vain.

const bar_options = {
  responsive: true,
  indexAxis: 'y',
  plugins: {
    labels:{
      render: 'image',
      images: [{
        src:"book.jpg",
        height:25,
        width:25
      },{
        src:"desk.jpg",
        height:25,
        width:25
      }
     ]
    },
  },
};

How can I use book.jpg and desk.jpg instead of book and desk

Or if possible I want to render not only image using dom component such as

<div><p>book</p><img src="book.jpg></div>

llamado a api sin respuesta en vs code [closed]

ola, estoy teniendo un problema al llamar a la API https://restcountries.com/v3.1/all. Cuando accedo a esta URL directamente desde mi navegador Google Chrome, recibo una respuesta JSON/ARRAY con la información de todos los países.

Sin embargo, cuando intento hacer la misma llamada desde mi entorno de desarrollo en VS Code, utilizando git bash, la solicitud no funciona o recibo un error.

Este es el código que estoy utilizando: lo dejo en un imagen

El error exacto que estoy recibiendo en mi consola de VS Code es

{
“error”: “abortar”
}

Custom DateTime Filter For AG-Grid (in Dash)

I’m presently trying to use Dash AG-Grid for a use-case in my org. One of those is to have filters through DateTime format (“YYYY-MM-DD HH:mm”). Since, the pre-configured agDateColumnFilter doesn’t allow inputs through the aforementioned format, I’m now working on a custom script for the same. A snippet of it goes like this (I’m obscuring certain aspects of it to maintain confidentiality):

ABC.py:

# Dynamically generate columnDefs
columnDefs = []
for column in table_column_info:
    col_name = column["col_name"]
    data_type = column["data_type"]

    # Add the column definition
    column_def = {
        "field": col_name,
        "cellRenderer": "SpinnerCellRenderer",
        "sortable": True,
        "resizable": True,
        "headerClass": "abcd",
        "cellStyle": {"whiteSpace": "normal", "wordWrap": "break-word"},
        "floatingFilter": True,
    }

    # Determine the filter type based on the data type

    if "datetime" in data_type.lower():
        column_def["filter"] = "DateTimeFilter"
   
    elif data_type.lower() in ["string", "object"]:
        column_def["filter"] = "agTextColumnFilter"
    elif "int" or "float" or "double" in data_type.lower():
        column_def["filter"] = "agNumberColumnFilter"

    # if filter_type:
    #     column_def["filter"] = filter_type

    columnDefs.append(column_def)

# Render the AgGrid component
return dag.AgGrid(
    id="table-grid-view",
    columnDefs=columnDefs,
    defaultColDef={
        "flex": 1,
        "minWidth": 150,
        "sortable": True,
        "resizable": True,
    },
    rowModelType="infinite",  # Use infinite row model
    dashGridOptions={
        "rowBuffer": 0,
        "maxBlocksInCache": 2,
        "cacheBlockSize": 100,
        "cacheOverflowSize": 2,
        "maxConcurrentDatasourceRequests": 2,
        "infiniteInitialRowCount": 1,
        "pagination": True,
        "rowHeight": 30,
    },
)

dashAgGridComponentFunctions.js: (in assets folder)

var dagcomponentfuncs = window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {};
const [useImperativeHandle, useState, useEffect, forwardRef] = [
    React.useImperativeHandle,
    React.useState,
    React.useEffect,
    React.forwardRef,
];

dagcomponentfuncs.DateTimeFilter = forwardRef((props, ref) => {
    const [filterType, setFilterType] = useState("equals"); // Default filter type
    const [dateFrom, setDateFrom] = useState(""); // Start date
    const [dateTo, setDateTo] = useState(""); // End date (for "inRange")

// Expose AG Grid Filter Lifecycle callbacks
useImperativeHandle(ref, () => ({
    doesFilterPass(params) {
        const cellValue = params.data[props.column.colId];
        if (!cellValue) return false;

        const cellDate = new Date(cellValue);
        const fromDate = dateFrom ? new Date(dateFrom) : null;
        const toDate = dateTo ? new Date(dateTo) : null;

        switch (filterType) {
            case "equals":
                return fromDate && cellDate.getTime() === fromDate.getTime();
            case "notEqual":
                return fromDate && cellDate.getTime() !== fromDate.getTime();
            case "lessThan":
                return fromDate && cellDate < fromDate;
            case "greaterThan":
                return fromDate && cellDate > fromDate;
            case "inRange":
                return fromDate && toDate && cellDate >= fromDate && cellDate <= toDate;
            default:
                return true;
        }
    },

    isFilterActive() {
        return !!dateFrom || !!dateTo;
    },

    getModel() {
        if (!this.isFilterActive()) {
            return null;
        }
        return {
            [props.column.colId]: { // Use the column ID as the key
                type: filterType,
                dateFrom: dateFrom,
                dateTo: filterType === "inRange" ? dateTo : null,
                filterType: "date",
            },
        };
    },

    setModel(model) {
        if (model && model[props.column.colId]) {
            const filterDetails = model[props.column.colId];
            setFilterType(filterDetails.type || "equals");
            setDateFrom(filterDetails.dateFrom || "");
            setDateTo(filterDetails.dateTo || "");
        } else {
            setFilterType("equals");
            setDateFrom("");
            setDateTo("");
        }
    },
}));

// Notify Ag-Grid when the filter changes
useEffect(() => {
    props.filterChangedCallback();
}, [filterType, dateFrom, dateTo]);

// Handle changes to the filter type
function onFilterTypeChange(event) {
    setFilterType(event.target.value);
}

// Handle changes to the "dateFrom" input
function onDateFromChange(event) {
    setDateFrom(event.target.value);
}

// Handle changes to the "dateTo" input (only for "inRange")
function onDateToChange(event) {
    setDateTo(event.target.value);
}

return React.createElement(
    "div",
    { style: { display: "flex", flexDirection: "column", padding: "5px" } },
    React.createElement(
        "select",
        {
            value: filterType,
            onChange: onFilterTypeChange,
            style: { marginBottom: "5px", padding: "5px", width: "100%" },
        },
        React.createElement("option", { value: "equals" }, "Equals"),
        React.createElement("option", { value: "notEqual" }, "Does not equal"),
        React.createElement("option", { value: "lessThan" }, "Before"),
        React.createElement("option", { value: "greaterThan" }, "After"),
        React.createElement("option", { value: "inRange" }, "Between")
    ),
    React.createElement("input", {
        type: "datetime-local", // HTML5 date-time picker
        value: dateFrom,
        onChange: onDateFromChange,
        style: { width: "100%", padding: "5px", marginBottom: "5px" },
    }),
    filterType === "inRange" &&
        React.createElement("input", {
            type: "datetime-local", // HTML5 date-time picker
            value: dateTo,
            onChange: onDateToChange,
            style: { width: "100%", padding: "5px" },
        })
); });

So now I’m getting the intended UI for DateTime filter. It is also getting triggered as soon as I start typing. However, I’m not able to get data from that input. For reference, I want my data to be parsed/captured like this for my filterModel : {'XXX_YY': {'dateFrom': '2025-04-02 00:00:00', 'dateTo': None, 'filterType': 'date', 'type': 'equals'}} where ‘XXX_YY’ is the name of column on which filter is being applied. Instead, at the moment, it just returns this: {}.

What mistake might I be committing here? I am at my wit’s end to figure out this conundrum. Or is there an easier alternative to my need – something like extending the functionality of “agDateColumnFilter” to have date-time input (instead of only date input) and the rest UI as is?

I’m using dash_ag_grid==31.2.0, plotly==5.23.0 & Python 3.12.4 and operating in Chrome browser.