Nodejs mongodb insert with `_id`, but `_id` becomes empty object

I’m inserting some records with _id = new ObjectId('a string with 24 length') to a collection in mongo with nodejs.
But the result _id in mongo becomes an empty object: {}, resulting in failure in subsequent insertions. (empty object are always equal).

This is what I got in console:
enter image description here

This is the result in mongo:
enter image description here

npm mongodb driver version: 4.11.0
mongo version: 3.6.23 (docker-compose)

Filtering data in reactable in R shiny. Reactivity and invalidatedLater

I have an R shiny app that works fine, but when I retrieve the data by pressing the ´Get data´ button all the components within the server function get executed twice, and I only want them to be executed once. The reason I only want it to be executed once, is that the second execution causes re-rendering of plots in the app which is noticeable when I run it on a remote server.

Ive attached a simplified version of the code. Note that the ranges variable is not applied in this simplified version, but I am including it to show the differences between the two reactive datasets dat_subset and **dat_filt ** , which are needed for the real app to work as expected.

I know that the code does get executed twice because of the invalidateLater(500) code – but if I do not include that, the plots do not re-render when I filter the reactable.

I only want the code to be executed once when I press get_data, but I also want the column plot to re-render and update when I filter the data in the table.

So my question is, can I trigger re-rendering of the plot when the table is filtered without having to use the invalidateLater function?

Here is the code:

library(shiny)
library(htmlwidgets)
library(reactable)
library(tidyr)
library(dplyr)
library(ggplot2)
library(shinyjs)
library(shinyWidgets)

jsCode <- 'shinyjs.getSortedAndFilteredData = function() {
  try {
    var instance = Reactable.getInstance("dat_table");
    if (instance) {
      var sortedIdx = instance.sortedFlatRows.map(x => x.index + 1);
      var filters = instance.state.filters;
      Shiny.onInputChange("sorted_data", sortedIdx);
      Shiny.onInputChange("filter_data", JSON.stringify(filters)); // Convert to JSON string
    }
  } catch (err) {
    console.error(err);
  }
}'


ui <- fluidPage(
  useShinyjs(),
  extendShinyjs(text = jsCode, functions = c("getSortedAndFilteredData")),
  theme = shinythemes::shinytheme("lumen"),
  fluidRow(
    column(width = 10,
           actionButton("get_data", "Get Data", class = "btn-primary")
    )
  ),
  fluidRow(
    column(width = 7,
           plotOutput("age_distribution_plot", height = 300)
    )
  ),
  fluidRow(
    column(width = 10,
           reactableOutput("dat_table")
    )
  )
)

get_age_cat_plot = function(dat){
  dat$age_cat <- cut(dat$age, breaks=c(6, 11, 21, 36, Inf), labels = c("<10","11-20","21-35","36+"), right = TRUE) 
  d <- dat %>% group_by(gender, age_cat) %>% summarise(count = n(), .groups="keep") %>% na.omit()
  d %>%
      ggplot(aes(factor(age_cat, levels=rev(levels(dat$age_cat))), count, fill = gender)) +
      scale_fill_manual(values = c("M"="#7285A5","F" = "pink3","U"="lightgray"))+
      geom_col(alpha=0.3, width=0.8, color="darkgrey") + theme_classic()+
      geom_text(aes(label = count),  # Adding percentage labels
            position = position_stack(vjust = 0.5), 
            color = "black", size = 5) +labs(y = "age", x="count") 
}


server <- shinyServer(function(input, output, session) {
    ranges <- reactiveValues(x = NULL, y = NULL)
    gene_table_ready <- reactiveVal(FALSE)

     dat <-  eventReactive(input$get_data,{
        print("Getting dat")
        ranges$x <- NULL; ranges$y <- NULL
        gene_table_ready(TRUE)
        age <- sample(0:75, 200, replace = TRUE)
        gender <- sample(c("M", "F"), 200, replace = TRUE)
        data.frame(age = age, gender = gender)
    })
  
      dat_subset <- reactive({
        print("getting dat subset")
        dat <- dat()
        if (!is.null(ranges$x)) 
          dat <- subset(dat, chr_start >= ranges$x[1] & chr_start <= ranges$x[2])
        dat
      })
      observe({
        if(gene_table_ready()){
          js$getSortedAndFilteredData()
          invalidateLater(500)
       }
      })
      dat_filt <- reactive({
        dat <- dat_subset()
        if(!is.null(input$sorted_data))
          dat <- dat[input$sorted_data, ]
        dat
      })
      output$dat_table <- renderReactable({
        print("Updating the data table")
        dat <- dat_subset()
        reactable(
          dat,
          filterable = TRUE,
        ) 
      })
      output$age_distribution_plot <- renderPlot({
        print("Getting age cat plot... ")
        get_age_cat_plot(dat_filt())
      })


    })

shinyApp(ui = ui, server = server)

`

Seeking Advice on Which Programming Languages to Learn for Full Stack Web Development [closed]

I’m currently preparing to learn web development, but I’m not sure if I’m on the right track. I need some guidance on which programming languages and technologies I should focus on and why.

I’ve shortlisted the following technologies:

  • HTML
  • CSS
  • JavaScript (JS)
  • React.js
  • Node.js
  • Express.js
  • SQL
  • PostgreSQL
    What do you think? Is this a good path for becoming a proficient web developer, or should I consider other technologies? Any advice would be greatly appreciated.

I tried HTML, CSS, and JavaScript. I was expecting to gain a solid foundation in front-end web development, but I’m not sure if I’m fully prepared to move on to more advanced technologies.

Fibonacci sequence using recursion

I try to make a function that returns an arrays of fib sequence up to Nth term. I’ve done this using iteration and returning n-th term alone with recursion but I can’t understand how to save the terms in the array using recursion.

function fibRec(n) {

  if (n == 1) {
    return 0;
  }
  if (n == 2) {
    return 1;
  }
  let array = [];
  return (array[n] = fibRec(n - 1) + fibRec(n - 2));
}

I tried with this but it only returns last term and not as an array but a number

Unable to read video streams on FFMPEG and send it to youTube RTMP server

I’m trying to send two video stream from browser as array buffer (webcam and screen share video) to server via Web RTC data channels and want ffmpeg to add webcam as overlay on screen share video and send it to youtube RTMP server, the RTC connections are established and server does receives buffer , Im getting error in Ffmpeg..error is at bottom , any tips on to add overlay and send it to youtube RTMP server would be appreciated.

Client.js

`
const webCamStream = await navigator.mediaDevices.getUserMedia({ video: true ,audio:true });
const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });

const webcamRecorder = new MediaRecorder(webCamStream, { mimeType: 'video/webm' });
webcamRecorder.ondataavailable = (event) => {
    if (event.data.size > 0 && webcamDataChannel.readyState === 'open') {
        const reader = new FileReader();
        reader.onload = function () {
            const arrayBuffer = this.result;
            webcamDataChannel.send(arrayBuffer);
        };
        reader.readAsArrayBuffer(event.data);
    }
};
webcamRecorder.start(100);  // Adjust the interval as needed

// Send screen share stream data
const screenRecorder = new MediaRecorder(screenStream, { mimeType: 'video/webm' });
screenRecorder.ondataavailable = (event) => {
    if (event.data.size > 0 && screenDataChannel.readyState === 'open') {
        const reader = new FileReader();
        reader.onload = function () {
            const arrayBuffer = this.result;
            screenDataChannel.send(arrayBuffer);
        };
        reader.readAsArrayBuffer(event.data);
    }
};
screenRecorder.start(100); 

`

Server.js

const youtubeRTMP = 'rtmp://a.rtmp.youtube.com/live2/youtube key';

// Create PassThrough streams for webcam and screen
const webcamStream = new PassThrough();
const screenStream = new PassThrough();

// FFmpeg arguments for processing live streams
const ffmpegArgs = [
  '-re',
  '-i', 'pipe:3',                  // Webcam input via pipe:3
  '-i', 'pipe:4',                  // Screen share input via pipe:4
  '-filter_complex',               // Complex filter for overlay
  '[0:v]scale=320:240[overlay];[1:v][overlay]overlay=10:10[out]',
  '-map', '[out]',                 // Map the output video stream
  '-c:v', 'libx264',               // Use H.264 codec for video
  '-preset', 'ultrafast',          // Use ultrafast preset for low latency
  '-crf', '25',                    // Set CRF for quality/size balance
  '-pix_fmt', 'yuv420p',           // Pixel format for compatibility
  '-c:a', 'aac',                   // Use AAC codec for audio
  '-b:a', '128k',                  // Set audio bitrate
  '-f', 'flv',                     // Output format (FLV for RTMP)
  youtubeRTMP                      // Output to YouTube RTMP server
];

// Spawn the FFmpeg process
const ffmpegProcess = spawn('ffmpeg', ffmpegArgs, {
  stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe']
});

// Pipe the PassThrough streams into FFmpeg
webcamStream.pipe(ffmpegProcess.stdio[3]);
screenStream.pipe(ffmpegProcess.stdio[4]);

ffmpegProcess.on('close', code => {
  console.log(`FFmpeg process exited with code ${code}`);
});

ffmpegProcess.on('error', error => {
  console.error(`FFmpeg error: ${error.message}`);
});

const handleIncomingData = (data, stream) => {
  const buffer = Buffer.from(data);
  stream.write(buffer);
};

the server gets the video buffer via webrtc data channels

pc.ondatachannel = event => {
        const dataChannel = event.channel;
        pc.dc = event.channel;
        pc.dc.onmessage = event => {
            // Spawn the FFmpeg process
            // console.log('Message from client:', event.data);
            const data = event.data;

            if (dataChannel.label === 'webcam') {
            handleIncomingData(data, webcamStream);
            } else if (dataChannel.label === 'screen') {
            handleIncomingData(data, screenStream);
            }
          
        };
        pc.dc.onopen = e=>{
            // recHead.innerText = "Waiting for user to send files"
            console.log("channel opened!")
        }
    };

Im getting this error in ffmpeg

[in#0 @ 0000020e585a1b40] Error opening input: Bad file descriptor
Error opening input file pipe:3.
Error opening input files: Bad file descriptor

Valor digitado em campo na grid replica para todos as outras colunas [closed]

Ao digitar o valor no InputNumber,ele não adiciona o valor na sua propria coluna ele replica para todos os outros.

enter image description here

como eu faço para que ao digitar o valor em cada input, apenas altere o TN aplicado daquela coluna.

          `</Box>
          <Box className={`noWrap CellRowTable ${classes.flex12}`}>
          {pending.storage.name}
          </Box>
          <Box className={`noWrap CellRowTable ${classes.flex20}`}>
          {pending.storage.capacity}
          </Box>
          <Box className={`noWrap CellRowTable ${classes.flex10}`}>
          {pending.storage.qtty}
          </Box>
          <Box className={`noWrap CellRowTable center ${classes.flex10}`}
          style={{
            marginBottom:'40px'
          }}
          >
            {((+pending.storage.capacity * pending.totalUnits) / 1000).toFixed(2)}
          </Box>
          <Box className={`noWrap CellRowTable ${classes.flex10}`}
          style={{
            marginTop:'-10px'
          }}
          >
         <InputNumber
                  className={`${classes.input}`}
                  id={`kgs-applied-${index}`}
                  type="number"
                  value={qttiesByLocation.processedQtty}
                  onChange={(value) => {
                    if (/^d+$/.test(value) || value === "") {
                      let newQttiesByLocation = [...qttiesByLocation];
                      newQttiesByLocation[index] = {
                        ...newQttiesByLocation[index],
                        processedQtty: value
                      };
                      setQttiesByLocation(newQttiesByLocation);
                    }}}
                     />
          </Box>
          <Box 
          id={`kgs-applied-${index}`}
          className={`noWrap CellRowTable center ${classes.flex10}`} 
          style={{
            marginBottom:'40px'
          }}>{totalApplied}</Box>`

Corrir o problema o mais rápido possivel

Disable Caching while fetching Gifs from Tenor Api

The problem is that the gifs which I am fetching from tenor are being cached by the browser .If user keeps fetching for a long time it will take a decent amount of memory. So, how to disable caching of gifs or clear the cache programmatically.

lang:js
stack:sveltekit

I cannot implement reloading page due to some other functionalities, and i also have tried method of setting cache control headers but it didn’t worked 🙁

Why is my key up function not working for input field with ID #lastshop

I have several input fields that I use to Calculate the Cost of the last shop visit. My keyup function works fine but for me to get correct Last Shop Visit Cost I often have to type twice. On all the other input fields my keyup function works as I type.

To understand my problem simply put 1000 in the field called Invoice value, the field called cost of last shop visit should be equal to 1000 as you type but instead i have to press enter twice to get the fields to be equal. It seems the output is lagging.

I tried the code below, for some reason it seems the input field with #lastshop is lagging in getting a result.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Input Form</title>
    <script src="https://code.jquery.com/jquery-3.7.1.js"
        integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
    <script>
        $(document).ready(function () {
            // Get value on keyup funtion
            $("#lastshop, #invoice, #aoidisks, #aoibnv, #aoilabour, #aoival, #stolbnv, #stoldisks, #stolval,#aoilabour ")
                .keyup(
                    function () {
                        var aoival = 0;
                        var aoilabour = 0;
                        var lastshop = 0;
                        var stolbnv = 0;
                        var g = Number($("#lastshop").val());
                        var a = Number($("#invoice").val());
                        var b = Number($("#aoidisks").val());
                        var c = Number($("#aoibnv").val());
                        var d = Number($("#aoilabour").val());
                        var e = Number($("#stolbnv").val());
                        var f = Number($("#stoldisks").val());
                        g = c + d + e;
                        aoilabour = a - b - c;
                        var aoival = aoilabour + b + c;
                        $('#aoilabour').val(aoilabour);
                        $('#aoival').val(aoival);
                        var stolval = e + f;
                        $('#stolval').val(stolval);
                        $('#lastshop').val(g);



                    });
        });
    </script>


</head>

<body>
    <center>

        <form action="" method="post">
            <p>

                <label for="">Date</label>
            </p>
            <p>
                <input type="text" name="thedate" id="thedate" class='thedate'>
            </p>


            <p><label for="">Engine</label></p>

            <p>
                <select name="" id="">
                    <option value="" selected>Select Engine</option>
                    <option value="">E268509</option>
                    <option value="">E268588</option>
                    <option value="">E268660</option>

                </select>
            </p>


            <p><label for="">Cycles To Run</label></p>

            <p><input type="text" name="cyclestorun" id="cyclestorun"></p>




            <label for="">Invoice Value</label>
            <p>
                <input type="text" name='invoice' id='invoice' class='invoice'>
            </p>
            <p>
                <label for="">AOI Disks</label>
            </p>
            <p>
                <input type="text" name="aoidisks" id="aoidisks">
            </p>
            <p>
                <label for="">AOI B & V</label>
            </p>
            <P>
                <input type="text" name="aoibnv" id="aoibnv">
            </P>
            <p>
                <label for="">AOI Labour</label>
            </p>

            <p>
                <input type="text" name="aoilabour" id="aoilabour" readonly>
            </p>


            <p>
                <label for="">AOI Value</label>
            </p>

            <p>
                <input type="text" name="aoival" id="aoival" readonly>
            </p>



            <p>
                <label for="">Stol B & V</label>
            </p>


            <P>
                <input type="text" name="stolbnv" id="stolbnv">
            </P>


            <p>
                <label for="">Stol Disks</label>
            </p>


            <P>
                <input type="text" name="stoldisks" id="stoldisks">
            </P>



            <p>
                <label for="">Stol Value</label>
            </p>


            <P>
                <input type="text" name="stolval" id="stolval" readonly>
            </P>




            <p>
                <label for="">Cost of Last Shop Visit</label>
            </p>


            <P>
                <input type="text" name="lastshop" id="lastshop" readonly>
            </P>





        </form>


    </center>
</body>

</html>

Automatic Calendar Week based on TodaysDate, Slow script or time exceeded

I’ve made a semi automated calender []https://docs.google.com/spreadsheets/d/1hkgDEGrxfZqbCCnslHTbMlVaa96bG1mSgBx0MUWYCSM/edit?gid=787834846#gid=787834846, it’s supposed to work like this, when the pc starts , a batch file automatically opens the browser with the calender, the script then runs on open, the calender has 52 sheets which is a lot i know, each sheet representing a calender week, the script is supposed to check all 52 sheets (only the 5 cells contianing a date) compare that with the date on week1, row100 which always shows todays date, and if there is a match activates that sheet containing the date e.g
it’s 1.4.24 which was week 14 so the sheet named “week 14” will be selected on opening the sheet.

first the script became slower and slower, it started from about 15 seconds now up to about 45 seconds (the more data there is in the calender throughout the year), which is annoying but given the data not surprising, is there a better way to get to the same result?
second and way bigger issue is that now i get over 50% of failed excecutions due to timeout, this only happens when the script runs automatically, if i start it manually it works fine.

function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheetNames = ["KW01", "KW02", "KW03", "KW04", "KW05", "KW06", "KW07", "KW08", "KW09", "KW10", "KW11", "KW12", "KW13", "KW14", "KW15", "KW16", "KW17", "KW18", "KW19", "KW20", "KW21", "KW22", "KW23", "KW24", "KW25", "KW26", "KW27", "KW28", "KW29", "KW30", "KW31", "KW32", "KW33", "KW34", "KW35", "KW36", "KW37", "KW38", "KW39", "KW40", "KW41", "KW42", "KW43", "KW44", "KW45", "KW46", "KW47", "KW48", "KW49", "KW50", "KW51", "KW52"];
  var dateCells = ["B3", "E3", "H3", "K3", "N3",];
  var comparisonSheet = spreadsheet.getSheetByName("KW01");
  var comparisonDate = comparisonSheet.getRange("A100").getValue();

  for (var i = 0; i < sheetNames.length; i++) {
    var sheet = spreadsheet.getSheetByName(sheetNames[i]);
    for (var j = 0; j < dateCells.length; j++) {
      var cellDate = sheet.getRange(dateCells[j]).getValue();
      if (cellDate.getTime() === comparisonDate.getTime()) {
        spreadsheet.setActiveSheet(sheet);
        return;
      }
    }
  }
}

before i found this method i’ve searched a lot trying to find a similar script or template i can use, there are if searched for day, month or year but not for calendar week, since i had no success i’ve tried chat gpt after a while i got the script being used, knowing chat gpt there is a good chance the script isn’t even a good one but the only one that worked, even if slow it was good enough for what was needed until it stopped working.

Difference between real element borders and gsap markers

I was using GSAP ScrollTrigger to make a vertical slider of images. The idea is that a hidden elements with id=scroller takes a certain height (I choose it to be 400 vh) while all the content is in fixed position, when you scroll down the #scroller element scrolltrigger moves the slider vertically, each time an element x of the slider enters a certain area the main background changes to the x background

I have a scroll trigger that animates the slider:

gsap.to('#slider',{
        scrollTrigger:{
            trigger: "#scroller",
            start: 0,
            scrub: 1,
            snap:"labelsDirectional"
        },
        y:-sliderH*6-80,
    })

and another trigger that changes the background according to slider position

let elems=document.querySelectorAll('.slider-elem')
let heroBacks=document.querySelectorAll('.hero-back')
elems=Array.from(elems)
ScrollTrigger.batch(elems, {
    onLeave: (elements, triggers) => {
        gsap.to(heroBacks[heroBacks.length-elems.indexOf(elements[0])-1], { opacity: 0})
    },
    onEnterBack: (elements, triggers) => {
        x=gsap.to(heroBacks[heroBacks.length-elems.indexOf(elements[0])-1], { opacity: 1})
        console.log(x)
    },
    start:'top 60%',
    end:'bottom 10%',
    markers:true
});

When I scroll down everything works fine except that a difference occurs between slider elements real borders (top bottom) and the ones indicated in the markers

no difference

difference

Typescript group modules like namespaces in C#

The issue

I work with DTO pattern and in general I use a domain-driven design, so I have many DTO, DM, types and interfaces, enums etc.

So eventually there will be a mess and it may get difficult to coordinate in the project and find everything.

I took a look at namespacing in typescript, but it didn’t work as expected, that’s what I tried to implement grouping:

some-test-transaction.dto.ts file:

export namespace MyExampleApi {
    export namespace Dtos {
        export namespace SomeTestTransactionDto {
            export interface Request {
                example: string;
                example2: string;
            }
            export interface Response {
                success: boolean;
            }
        }
    }
}

some-other.dto.ts file:

export namespace MyExampleApi {
    export namespace Dtos {
        export namespace SomeOtherDto {
            export interface Request {
                example2424: string;
                example24242: string;
            }
            export interface Response {
                success2424: boolean;
            }
        }
    }
}

I expect namespace merging to occur so I can access to the MyExampleApi anywhere in the project and see all the types I can use:

MyExampleApi.Dtos.SomeOtherDto.Request to get the Request dto type.

But this doesn’t work, what happens instead is the last loaded file that contains the declaration for MyExampleApi overrides it and you can use only that specific namespace.

This is because javascript doesn’t have native handling for namespacing like in C# so it is not possible.

On the other hand I tried to do something similar with modules and namespace:

hello.dto.ts file:

export namespace HelloDto {
    export interface Request {
        id2: number;
        name2: string;
    }

    export interface Response {
        success: boolean;
    }
}

test.dto.ts file:

export namespace TestDto {
    export interface Request {
        id: number;
        name: string;
    }

    export interface Response {
        success: boolean;
        data: {
            id: number;
            name: string;
            createdAt: Date;
        };
    }
}

in ./dtos directory i created index.ts:

export * from './test.dto';
export * from './hello.dto';

myapi.ts file:

import * as Dtos from './dtos';
export const MyApi = {
    Dtos,
};

I try to access something like this: MyApi.Dtos.TestDto.Request but I don’t get auto-complete for the interfaces for TestDto or for HelloDto by webstorm.

What did I do wrong, and how can I get this idea to work in typescript for better organization of code?

Hosting a peerjs server on iisnode, client side unable to connect status “Finished”, not sure why this is happening?

So I have built a WebSocket server on ws and this works perfectly for sending basic messages.
What I wanted to do next was create a peer to peer calling service using PeerServer server side and PeerJS client side.
However the client cannot connect to the server the WebSocket keeps returning status:”Finished”.
Again this is specifically iisnode.

Here is my web.config file :

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="iisnode" path="node_app.js" verb="*" modules="iisnode" />
        </handlers>
        <rewrite>
            <rules>
                <rule name="ws" patternSyntax="ECMAScript" stopProcessing="true">
                    <match url="^NodeJS/WebSocket/WS/?$" />
                    <action type="Rewrite" url="NodeJSWebSocketWSnode_app.js" />
                </rule>
                <rule name="peerjs" patternSyntax="ECMAScript" stopProcessing="true">
                    <match url="^NodeJS/PeerJS/Server/?.*" />
                    <action type="Rewrite" url="NodeJSPeerJSServernode_app.js" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

The rule name=”ws” is for the basic WebSocket server.

Server side code for PeerServer “NodeJSPeerJSServernode_app.js” :

// peer_server
var ExpressPeerServer = require('peer').ExpressPeerServer;
var peerExpress = require('express');
var peerApp = peerExpress();
var peerServer = require('http').createServer(peerApp);
var options = { debug: true }
var peerPort = process.env.PORT;

peerApp.use('/', ExpressPeerServer(peerServer, options));
peerServer.listen(peerPort);

Client side Javascript :

window.addEventListener('load', function() {
    var url = '/NodeJS/PeerJS/Server/'; 
    var peer_url = location.hostname + url;
    var thisCallerID = 123; 
    
    peerJS = new Peer(thisCallerID,{
        host: location.hostname,
        path: url,
        debug: 1
    });
}); 

The error log I get sever side is :

(node:17520) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use node --trace-deprecation ... to show where the warning was cre
ated)

However I get this warning on the WebSocket server too and it works just fine.

Any help would be greatly appreciated.

How can I make the datepicker div above and the Modal.Footer when the Modal.Body scrollable is enable?

Here is my component:

import { useState } from 'react';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import "./TestModal.css";
export default function TestModal() {
    const [scroll, setScroll] = useState(false);
    return (
        <Modal scrollable={scroll} show={true} size="lg">
            <Modal.Header closeButton>
                <Modal.Title>Time off</Modal.Title>
            </Modal.Header>
            <Modal.Body className='position-relative'>
                Start Time:
                <div className='position-relative d-inline-block'>
                    <div className="border border-black">sdfsdfs</div>
                    <div className='datepicker bg-white border border-black'>
                        date picker                       
                    </div>
                </div>
            </Modal.Body>
            <Modal.Footer>
                <Button variant="secondary" onClick={() => setScroll(!scroll)}>
                    Scroll
                </Button>
                
            </Modal.Footer>
        </Modal>
    )
}

TestModal.css

.datepicker{
    position:absolute;
    z-index: 2000;
}

In the beginning, the datepicker div can be above the Model.Footer, and the datepicker div hide the Modal.Footer.

When I click on the “scroll” button, the script will enable the scrollable feature of the Modal.Body, unfortunately, it make the Model.Footer hide the datepicker div.

Would you tell me what is the reason for this issue?

Cropper.js not displaying crop box after adding image with Dropzone.js

The problem:

I’m having trouble getting Cropper.js to display the crop box on an image after adding it with Dropzone.js. The image uploads successfully, but the crop box doesn’t appear. Cropper is supposed to work in two use cases in one modal: the first is to crop an existing images and the second is the one I am having trouble with, after a user adds an image with Dropzone. Once an image is saved, it is sent to the server.. This problem really concerns proper Cropper initialization. Here is my code:

Dropzone.autoDiscover = false;
var cropper;

$(document).ready(function() {
  $('[data-bs-toggle="tooltip"]').tooltip();

  $('#cropperModal').on('shown.bs.modal', function() {
    console.log('shown.bs.modal called');
    let imageElm = document.getElementById('modalImage');
    $(imageElm).show();
    initializeCropper(imageElm);
    console.log('shown.bs.modal cropper');
    console.log(cropper);
  }).on('hidden.bs.modal', function() {
    if (cropper) {
      cropper.destroy();
      cropper = null;
      resetDropzone("#hidden-dropzone");
      $('#modalImage').attr('src', '').hide();
      $('#upload-button').hide();
    }
  });

  $('#upload-header, #upload-horizontal, #upload-logo').on('click', function() {
    let section = $(this).data('section');
    let imageUrl = $(this).find('img').attr('src');
    openModalAndInitializeDropzone(section, imageUrl);
  });

  $('#save-changes-button').on('click', function() {
    saveCroppedImage(cropper);
  });

  function openModalAndInitializeDropzone(section, imageUrl) {
    $('#status-gyph-image').html('').removeClass('text-success').removeClass('text-danger');
    $('#cropperModal').modal('show');
    $('#modalImage').attr('src', imageUrl).data('section', section).show();
    initializeDropzone("#hidden-dropzone");
  }

  function initializeDropzone(dropzoneId) {
    console.log('initializeDropzone called, ' + dropzoneId);
    if (Dropzone.instances.length > 0) {
      Dropzone.instances.forEach(instance => instance.destroy());
    }
    let dropzoneElement = document.querySelector(dropzoneId);
    if (!dropzoneElement.dropzone) {
      let dropzone = new Dropzone(dropzoneId, {
        url: "/file/post",
        maxFilesize: 2,
        acceptedFiles: ".jpeg,.jpg,.png",
        maxFiles: 1,
        init: function() {
          this.on("addedfile", function(file) {
            console.log('initializeDropzone addedfile');
            var reader = new FileReader();
            reader.onload = function(event) {
              $('#modalImage').attr('src', event.target.result).show();
              $('#modalImage').on('load', function() {
                console.log('......modalImage on load........');

                let imageElm = document.getElementById('modalImage');
                initializeCropper(imageElm);
                console.log(cropper);
              });
            };
            reader.readAsDataURL(file);
          });
          this.on("thumbnail", function(file) {
            file.previewElement.remove();
          });
        }
      });
      $(dropzoneId).css({
        display: 'block',
        width: '100%',
        height: '200px',
        border: '2px dashed #007bff',
        padding: '20px',
        textAlign: 'center',
        lineHeight: '160px',
        fontSize: '16px',
        color: '#007bff'
      }).text('Drag and drop an image here or click to upload');
    } else {
      console.log('Dropzone already initialized for this element.');
    }
  }

  function resetDropzone(dropzoneId) {
    let dropzoneElement = Dropzone.forElement(dropzoneId);
    if (dropzoneElement) {
      dropzoneElement.removeAllFiles(true);
    }
  }

  function initializeCropper(imageId) {
    console.log('initializeCropper called');
    var $image = $(imageId);
    console.log($image);
    console.log($image.length);
    if ($image.length) {
      if (cropper) {
        cropper.destroy();
      }
      $image.cropper({
        autoCropArea: 0.5,
        responsive: true,
        viewMode: 2,
        scalable: false,
        zoomable: false,
        crop: function(e) {},
        ready: function() {
          console.log('ready called');
          cropper = $image.data('cropper');
          console.log(cropper);
        }
      });
      $('#upload-button').show();
      return $image.data('cropper');
    }
    console.error('Image element not found:', imageId);
    return null;
  }

  function saveCroppedImage(cropper) {
    if (cropper) {
      var canvas = cropper.getCroppedCanvas();
      let imageElm = document.getElementById('modalImage');
      let section = $(imageElm).data('section');
      if (canvas) {
        canvas.toBlob(function(blob) {
          var formData = new FormData();
          console.log(formData);
          formData.append('croppedImage', blob, 'croppedImage.' + blob.type.split('/')[1]);
          formData.append('section', section);
          $.ajax('/main/uploadFile', {
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(response) {
              $('#status-gyph-image').html('<strong>Successfully saved image.</strong>').addClass('text-success').removeClass('text-danger');
            },
            error: function(xhr, status, error) {
              $('#status-gyph-image').html('An internal error occurred.').addClass('text-danger').removeClass('text-success');
            }
          });
        });
      } else {
        $('#status-gyph-image').html('An internal error occurred.').addClass('text-danger').removeClass('text-success');
      }
    }
  }
});

Problem:

After uploading an image with Dropzone.js, the image is displayed in the modal, but the Cropper.js crop box does not appear. The cropper variable is null when I log it after calling initializeCropper.

Any help or suggestions would be greatly appreciated!

What I’ve tried:

Ensuring the image element is fully loaded before initializing Cropper.
Checking the timing of when initializeCropper is called.
Adding console logs to trace the initialization process.
Expected behavior:

The crop box should appear on the image after it is added via Dropzone and displayed in the modal.

Actual behavior:

The image is displayed, but the crop box does not appear…