How to capture the google form submit button

I am developing an extension for my personal use. It will store the information that I fill in a google form.

The issue I am facing is that the submit button in google forms is actually a span with nested elements and does not actually have a specific button tag.

Additionally I am unable to intercept the submit event

The below code is not working


let forms = document.getElementsByTagName("form");
forms[0].addEventListener("submit", (ev) => {
   ev.preventDefault();

   // Store data locally using FormData

   // submit form after storing data only if form accepted the data

});

After running this in console the event listener is not triggered on clicking the button.

How do I add a submit event to the google form submit or next button ?

I have tried uaing the preventDefault amd returning false in the handler function but still cannot stop the from from submitting when submit button is pressed.

Uncaught TypeError: Cannot read null property (reading ‘value’) [duplicate]

I have JavaScript codes that give this error:

Uncaught TypeError: Cannot read null property (reading ‘value’)

Here are my codes

1.

let imgBox = document.getElementById("imgBox");
let qrImage = document.getElementById("qrImage");
let qrText = document.getElementById("qrText");

function generateQR() {
  if (qrText.value.length > 0) {
    qrImage.src =
      "https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=" +
      qrText.value;

    imgBox.classList.add("show-img");
  } else {
    qrText.classList.add("error");
    setTimeout(() => {
      rText.classList.remove("error");
    });
  }
}
document.getElementById("qrButton").addEventListener("click", function () {
  let qrInput = document.getElementById("qrText").value;

  new QRCode(document.getElementById(qrImage), qrInput);
});

What does this error mean?

I expected it to generate QR Code, but it returns the above error.

React Hook Form useFieldArray loses focus on input after typing – How to retain focus?

I’m using useFieldArray from React Hook Form to build a dynamic form where users can add or remove fields. However, I’ve run into an issue where the input field loses focus after typing in it. This happens specifically for the Link input in each dynamically added field.

Here’s a version of my component:

import axios from 'axios'; 
import { useEffect } from 'react';
import { useFieldArray, useForm } from 'react-hook-form';
import usePreview from '../../hooks/usePreview';
import { platforms } from '../../utils/platforms';

const DynamicForm = () => {
    const { token } = JSON.parse(localStorage.getItem('user'));
    const apiConfig = {
        headers: { Authorization: `Bearer ${token}` },
    };
    const { preview, setPreview } = usePreview();
    const { register, control, handleSubmit, reset } = useForm({
        defaultValues: {
            links: preview?.links?.length
                ? preview.links
                : [{ platform: '', url: '' }],
        },
    });

    const { fields, append, remove } = useFieldArray({
        control,
        name: 'links',
    });

    // Update form with preview values when preview changes
    useEffect(() => {
        if (preview?.links?.length) {
            reset({ links: preview.links });
        }
    }, [preview, reset]);

    const handleInputChange = (index, fieldName, value) => {
        // Update the field directly in fields array
        const updatedLinks = fields.map((field, i) =>
            i === index ? { ...field, [fieldName]: value } : field
        );
        setPreview({ links: updatedLinks });
    };

    const handleRemove = (index) => {
        // Remove the field from the form
        remove(index);

        // Remove the corresponding entry from preview state
        const updatedPreviewLinks = [...preview.links];
        updatedPreviewLinks.splice(index, 1); // Remove the item at the specified index
        setPreview({ links: updatedPreviewLinks });
    };

    const onSubmit = async (data) => {
        try {
            const response = await axios.post('/links', data, apiConfig);

            // Update only the "links" part of localStorage with the response
            const userData = JSON.parse(localStorage.getItem('user'));
            userData.links = response.data.links; // Update the links array
            localStorage.setItem('user', JSON.stringify(userData));

            console.log('Form submitted successfully:', response.data);
        } catch (error) {
            console.error('Error submitting form:', error);
        }
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
            {/* Add New Link Button */}
            <button
                type="button"
                onClick={() => append({ platform: '', url: '' })}
                className="block w-full bg-transparent text-brandColor font-bold py-2 px-4 rounded-md border border-brandColor"
            >
                + Add new link
            </button>

            {fields.map((field, index) => (
                <div
                    key={field.id}
                    className="bg-gray-50 p-6 rounded-lg shadow-md relative"
                >
                    <h3 className="font-semibold text-lg mb-4">Link #{index + 1}</h3>
                    <div className="">
                        {/* Platform Selection */}
                        <div>
                            <label className="block text-sm font-medium text-gray-700">
                                Platform
                            </label>
                            <select
                                {...register(`links.${index}.platform`)}
                                onChange={(e) =>
                                    handleInputChange(index, 'platform', e.target.value)
                                }
                                className="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                            >
                                <option value="">Select platform</option>
                                {platforms.map((platform) => (
                                    <option key={platform.platform} value={platform.platform}>
                                        {platform.platform.charAt(0).toUpperCase() +
                                            platform.platform.slice(1)}
                                    </option>
                                ))}
                            </select>
                        </div>

                        {/* Link URL Input */}
                        <div>
                            <label className="block text-sm font-medium text-gray-700">
                                Link
                            </label>
                            <input
                                {...register(`links.${index}.url`)}
                                type="url"
                                onChange={(e) =>
                                    handleInputChange(index, 'url', e.target.value)
                                }
                                className="mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                                placeholder="https://example.com"
                            />
                        </div>
                    </div>

                    {/* Remove Button */}
                    {fields.length > 1 && (
                        <button
                            type="button"
                            onClick={() => handleRemove(index)}
                            className="absolute top-4 right-4 text-red-500 hover:text-red-700"
                        >
                            Remove
                        </button>
                    )}
                </div>
            ))}

            {/* Save Button */}
            <div className="flex justify-end mt-3">
                <button
                    type="submit"
                    className="w-fit bg-brandColor text-white font-bold py-2 px-6 rounded outline-none"
                >
                    Save
                </button>
            </div>
        </form>
    );
};

export default DynamicForm;

How can I prevent the input from losing focus while typing when using useFieldArray in React Hook Form.
Thanks in advance!

Javascript, map array from index

How is it possible to map an array from a index and then map the rest based on a criteria.

const array = [4, 2, 8, 3, 4, 6];

const map = array.map((x, index) => {
  if(x<8){
    return index;
  };
 
});

console.log(">> "+map);

// Output array should be [1,3,4,5];  * Final array will be a lot bigger;

For example I want to search the array from index 1 and then return the indexes of all values less than 8.

Is map the best way or is there another?

Any help / advice would be appreciated.

Leaflet JS custom marker icon not showing

I am working on a personal project using LeafletJS and Vue3. I want to change the default marker icon so I copied the png file directly into the same file as my script and created a new Icon as shown below.

import leaflet from "leaflet";

let DefaultIcon = new leaflet.Icon({
  iconUrl: './Banner.png',
  iconSize: [50, 50]
})

export default class Info {
  constructor(
    name = "", notes = "", icon = DefaultIcon
  ){
    this.name = name;
    this.notes = notes;
    this.icon = icon;
  }
...

and when I create the marker I access this icon…

...
  constructor(data) {
    this.id = data.id;
    this.info = new Info(data.info.name, data.info.notes);
    console.log("Icon", this.info.icon)

    if (mapStore.map != null) {
      this.object = new leaflet.marker(
        [data.lat, data.lng], 
        {
          icon: this.info.icon,
          draggable: true,
          riseOnHover: true
        }
      ).addTo(mapStore.map)
    }
...

This was all working fine using the default blue marker icon before I specified icon: this.info.icon in the options. Now the markers still appear (I can see their tooltips) but there is no icon. I’m absolutely stumped on what could be causing this. The log statement shows that data.info.name is a leaflet.Icon with the proper path and everything.

I’ve tried setting the path as an absolute path from the project root, a relative path from the script location, and providing option values when initializing the Icon. I also tried to initialize DefaultIcon without the new keyword, just because thats what I saw here (although I don’t really know why there’s no new keyword in that example), but I got an error about initialization hooks. I would expect the default blue marker icon to be replaced with my Banner.png marker icon, but instead there is no marker icon at all. Why isn’t it the icon rendering on the map?

How to smooth out the line animation in an HTML5 canvas?

community!

I am working on a project using HTML5 Canvas and JavaScript/jQuery, where I have multiple animated routes between points on a grid. The animation should smoothly draw lines from point A to point B, but I’m having trouble achieving a smoother movement for the line.

enter image description here

Here’s the code I’m using:

$(document).ready(function () {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const points = [];
    const routes = [];
    const pointRadius = 10;
    const gridSize = 60; // Spacing between points
    const numRows = Math.floor(canvas.width / gridSize);
    const numCols = Math.floor(canvas.height / gridSize);
    const animationDuration = 2000; // Total animation time (adjustable)

    // Function to draw a point
    function drawPoint(x, y, color = 'black') {
        ctx.beginPath();
        ctx.arc(x, y, pointRadius, 0, 2 * Math.PI);
        ctx.fillStyle = color;
        ctx.fill();
        ctx.strokeStyle = color;
        ctx.stroke();
    }

    // Function to draw the full curve from A to B
    function drawFullCurve(pointA, pointB, colorStart, colorEnd) {
        const midX = (pointA.x + pointB.x) / 2;
        const midY = (pointA.y + pointB.y) / 2 - 50; // Curve elevation

        const gradient = ctx.createLinearGradient(pointA.x, pointA.y, pointB.x, pointB.y);
        gradient.addColorStop(0, colorStart);
        gradient.addColorStop(1, colorEnd);

        ctx.beginPath();
        ctx.moveTo(pointA.x, pointA.y);
        ctx.quadraticCurveTo(midX, midY, pointB.x, pointB.y);
        ctx.strokeStyle = gradient;
        ctx.lineWidth = 2;
        ctx.stroke();
    }

    // Function to animate the reveal of the curve from A to B
    function animateCurve(pointA, pointB, colorStart, colorEnd, duration) {
        let startTime = performance.now();

        function animateStep(timestamp) {
            const elapsedTime = timestamp - startTime;
            const progress = Math.min(elapsedTime / duration, 1); // Progress from 0 to 1

            // Do not clear the entire canvas! Keep previous routes
            ctx.save();
            ctx.beginPath();
            ctx.moveTo(pointA.x, pointA.y);

            // Calculate intermediate position using linear interpolation
            const t = progress;
            const midX = (pointA.x + pointB.x) / 2;
            const midY = (pointA.y + pointB.y) / 2 - 50;

            const revealX = (1 - t) * ((1 - t) * pointA.x + t * midX) + t * ((1 - t) * midX + t * pointB.x);
            const revealY = (1 - t) * ((1 - t) * pointA.y + t * midY) + t * ((1 - t) * midY + t * pointB.y);

            ctx.quadraticCurveTo(midX, midY, revealX, revealY);
            ctx.clip();

            drawFullCurve(pointA, pointB, colorStart, colorEnd);

            ctx.restore();

            drawPoint(pointA.x, pointA.y, colorStart);
            drawPoint(pointB.x, pointB.y, colorEnd);

            if (progress < 1) {
                requestAnimationFrame(animateStep);
            }
        }

        requestAnimationFrame(animateStep);
    }

    // Generate points
    for (let i = 0; i < numRows; i++) {
        for (let j = 0; j < numCols; j++) {
            const x = i * gridSize + gridSize / 2;
            const y = j * gridSize + gridSize / 2;
            points.push({ x, y });
            drawPoint(x, y);
        }
    }

    // Generate 20 random routes
    function generateRandomRoutes() {
        for (let i = 0; i < 20; i++) {
            const startPoint = points[Math.floor(Math.random() * points.length)];
            const endPoint = points[Math.floor(Math.random() * points.length)];
            routes.push({ startPoint, endPoint });
        }
    }

    generateRandomRoutes();

    // Function to animate routes simultaneously
    function animateRoutes() {
        routes.forEach(route => {
            const colorStart = 'blue';
            const colorEnd = 'red';
            const { startPoint, endPoint } = route;

            // Execute the animation for each route without clearing the canvas
            animateCurve(startPoint, endPoint, colorStart, colorEnd, animationDuration);
        });
    }

    // Execute the animation of the routes
    animateRoutes();
});

Problem:
The animation is not as smooth as I would like. Instead, the line seems to be “drawn” abruptly from A to B. What I want is for the line to be drawn smoothly, as if it’s being traced over time, instead of appearing all at once.

Question:
How can I smooth out this animation so that the line appears more fluid? Any tips on improving the interpolation calculation or how the line is drawn would be greatly appreciated!

Thank you in advance for your help!

Why does my anchor in a pug file ignores current URL

I am using Express and the PUG rendering engine.
In my pug file, I define a link using a(href) like this:

a.link-btn(href='#session-popup') + (it is an “add” button, supposed to display a popup using a :target CSS property, but this is not useful information for my question I think)

My current URL is http://localhost:3000/movies/form.

When the HTML is rendered, on my browser, the link is localhost:3000/#session-popup
I do not understand why it happens this way, it should be localhost:3000/movies/form#session-popup and should not refresh the page.

I do not know if this behaviour comes from Express or PUG. I use express like this:

app.use("/movies", moviesRouter);
router.get("/form", movies_controller.movie_form_get); // in a different file
// and then movie_form_get in a different file renders the PUG file:

exports.movie_form_get = async (req, res, next) => {
  res.status(200).render("movie-form", {
    versions: movieVersions,
    tags: movieTags,
  });
};

(sorry for this unconventional code extraction, I tried to put only relevant code)

My link a.link-btn(href='#session-popup') + is in the “movie-form.pug” file.

I tried a.link-btn(href='./#session-popup') + without really thinking it would work (it does not).

I tried a.link-btn(href='movies/form/#session-popup') + ==> it works, of course, but I would like not to write the full URL in my PUG file, I would like a relative link.

Why does the PUG engine render my link that way, ignoring the current URL?

How to click id by Puppeteer, but id is changed each access?

I want to click check-box inperson name by using Puppeteer.
And the person name has unique id which is diffrent each time.

  1. I have tried to make this method
const selector = '#id^="/^[A-Za-z0-9_]+-[0-9]+/g"';
await page.click(selector) 

But Puppeteer says error which is:

    DOMException: Failed to execute 'querySelector' on 'Document': '#id^="/^[A-Za-z0-9_]+-[0-9]+/g"' is not a valid selector.

I thought my reguler expression is wrong so I made sure its correct.

const id = '9538-0';
const regex = /^[A-Za-z0-9_]+-[0-9]+/g;
const found = id.match(regex);
console.log(found); // [ '9538-0' ]
  1. Here is HTML at check box.
<div class="e-content e-dropdownbase" _ngcontent-ng-c184323="" data-ripple="true" style="max-height: 300px;">
  <ul class="e-list-parent e-ul" _ngcontent-ng-c184323="" role="listbox" tabindex="0" id="ej2_multiselect_1_options" aria-hidden="false" aria-label="list">
    <li class="e-list-item e-hover" id="9538-0" _ngcontent-ng-c184323="" role="option" data-value="i-8532876">
        <div class="e-checkbox-wrapper e-css" _ngcontent-ng-c184323="">
          <span class="e-ripple-container" _ngcontent-ng-c184323="" data-ripple="true"></span>
          <span class="e-frame e-icons" _ngcontent-ng-c184323=""></span>
</div>

       <span _ngcontent-ng-c184323="" class="recipient-item-desktop">MIKE CHASE (12345086)</span>
       <span _ngcontent-ng-c184323="" class="recipient-item-desktop">AGO</span>
       <span _ngcontent-ng-c184323="" class="recipient-item-desktop">$0.00</span>
    </li>
   </ul>
</div>
  1. And this is snapshot
    enter image description here

  2. my software versions
    Lang : JavaScript
    node.js : v20.16.0 (node -v)
    Puppeteer : [email protected] (npm list –depth=0)

Could you please teach me why I am not able to click check box by ID(id=”9538-0″) or
How to do it best.

Thank you for your time.

THREE.OBJLoader: Unexpected line: “”

When I am trying to load my .obj file in three js using OBJLoader then its showing a yellow alert error:-
THREE.OBJLoader: Unexpected line: “”

import * as THREE from "./node_modules/three/build/three.module.js";
import { OBJLoader } from "OBJLoader.js";
// Basic Three.js setup
const scene= new THREE.Scene();
const camera=new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1,1000);
const renderer= new THREE.WebGLRenderer({
canvas: document.querySelector('#bg'),
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
camera.position.setZ(30);
renderer.render(scene,camera);
// Load the OBJ model
const loader= new OBJLoader();
loader.load('asset/EvilScreamingManBaseMesh_1subd.obj', function(obj) {
const model=obj.scene;
scene.add(model);

});

How to allow up and down arrow keys to wrap in menu

In bootstrap 5 menu, pressing up arrow key in first item or down allow key in last item does nothing.

How to make up arrow to move to last item in menu if pressed in first item and down arrow to move to first item if pressed in last item just like in normal windows desktop application menus?

To reproduce open page

<div class="btn-group">
  <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
    Action
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#"><u>A</u>ction</a></li>
    <li><a class="dropdown-item" href="#">A<u>n</u>other action</a></li>
    <li><a class="dropdown-item" href="#"><u>S</u>omething else here</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a class="dropdown-item" href="#">S<u>e</u>parated link</a></li>
  </ul>
</div>

https://jsfiddle.net/b6or2s5e/

Open Action menu. Pressing up arrow in first menu line or pressing down arrow in last menu line does nothi

Why the src of Image tag doesn’t recognizes my jpg?

I’m trying to insert an image in my portfolio, but for some reason the tag returns 404 and the Next Image returns the error The requested resource isn't a valid image for /myImage.jpg received text/html

this is the code block:

import Image from "next/image";
import { ReactElement } from "react";

const MyImage = ():ReactElement => {
    return (
        <Image
            fill
            src='/myImage.jpg'
            alt="MyImage"
            />
    )
}

export default MyImage

Oracle Dpi-1080 connection was closed by ORA-25412

I am receiving the following when the program runs for longer duration; if you restart the node app, the error will not appear and everything will function as it should. This error only happens sporadically. ORA-25412 closed the DPI-1080 connection. Min: 2 max: 18 pool size. Oracle, Knex, and Node.js are the tools I use. Iterations: 16.20.0 Knex: “^2.4.2”; Orthocledb: “^5.1.0”. There shouldn’t be any connection-related problems, and the application should function properly. Is this configured in any way?

problem opening Sqlite3 database from Java Script Web Worker

I’m trying to insert data from an Sqlite3 database into a web page hosted by a Beaglebone black.
Using a Java Script web worker form an on line example for a number count, the JS worker and HTML page work fine. If I modify the worker code to get the data from a database,and run that in a terminal on the host, that also works fine, the data base is accessed and the data printed out. However, the code will NOT operate as a worker.
HTML code (wkr_tst.html)

<html>
<body>

<p>Count numbers: <output id="result"></output></p>
<p>Count numbers: <output id="result2"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>

<script>
var w;

function startWorker() {
  if (typeof(Worker) !== "undefined") {
    if (typeof(w) == "undefined") {
      w = new Worker("dbase1.js");
    }
    w.onmessage = function(event) {
      document.getElementById("result").innerHTML = event.data;
      document.getElementById("result2").innerHTML = event.data;
    };
  } else {
    document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
  }
}

function stopWorker() {
  w.terminate();
  w = undefined;
}
</script>

</body>
</html> 

Java script worker:(dbase1.js)

const sqlite3 = require("sqlite3")
var i = 0;
const db = new sqlite3.Database("/home/debian/examples/C_BMS/test2.db",sqlite3.OPEN_READONLY );

function timedCount() {
    i=i+1;
   db.all("SELECT * FROM EpiData", [], (err, rows) => {
        console.log(rows);
    })
postMessage(rows);
//postMessage(i);
//postMessage(i+2);
//setTimeout("timedCount()",500);
}
timedCount(); 
db.close();

With 2 different browsers, using the inspect function, both show that the “require(Sqlite3) function is not defined.

I’ve tried re-installing both Nodejs and the squlite3 extension, with the same result.

Is there possible navigate to prev page with nextjs route handler

i need to make return button which will return to previous page.

First i tried to make component:

"use client";

import React from "react";
import {useRouter} from "@i18n/routing";
import {IRedirect} from "@t/hooks/redirect";

const RedirectBack = ({children, redirectTo, className}: IRedirect) => {
  const router = useRouter();

  const redirect = () => {
    switch (redirectTo) {
      case "back":
        router.back();
      default:
        return;
    }
  };

  return (
    <div
      className={className}
      onClick={redirect}>
      {children}
    </div>
  );
};

export default RedirectBack;

but it will cause it to be "use client" and i want to avoid it, so i found the way, where i can create route handler and create a GET request which will redirect to another page

import {redirect, useRouter} from "@i18n/routing";
import {IRedirectHandler} from "@t/route-handlers/redirect";
import {NextResponse} from "next/server";

export async function GET(_request: Request, context: {params: IRedirectHandler}) {
    redirect(`/${context.params.to}`);
}

but the only way I know how to return to the previous page is to use useRouter with route.back() command, but if i try to do so inside route handler and GET request i get an error with code 500

enter image description here

HTTP/1.1 500 Internal Server Error
link: <http://localhost:3000/en/api/route-handlers/redirect/back>; rel="alternate"; hreflang="en", <http://localhost:3000/ua/api/route-handlers/redirect/back>; rel="alternate"; hreflang="ua"
x-middleware-rewrite: /en/api/route-handlers/redirect/back
vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch
Date: Sat, 12 Oct 2024 18:01:55 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked
GET /en/api/route-handlers/redirect/back HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: uk,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Cookie: NEXT_LOCALE=en
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Priority: u=0, i

so is there any way to use useRoute inside route handler

OR

Still use route handler but be able to return to previous page?

i did try but it cause error request code 500 and do nothing

import {redirect, useRouter} from "@i18n/routing";
import {IRedirectHandler} from "@t/route-handlers/redirect";
import {NextResponse} from "next/server";

export async function GET(_request: Request, context: {params: IRedirectHandler}) {
  const router = useRouter();
  router.back();
}

I’m hoping to find some way to get back to the previous page using route handler

Issues with category synchronization between the client and API in Vue.js

I’m working on a Vue.js app that syncs categories with a server via an API. I’m having issues with category display after setting parent and child categories.

Situations encountered:

  • No category assignments: Works fine on both client and API.
  • Parent category assigned: Correct nesting on the client, API data accurate.
  • Parent + child categories assigned: Displays correctly on both client and API.
  • After “Cancel Child”: Before reload, categories are correct, but after reload, they desync, and the structure differs from the API.

The fetchCategories function retrieves categories from the server, but syncing fails after updating the structure.

How can I ensure proper synchronization between the client and API to prevent discrepancies in the category hierarchy?

async fetchCategories() {
  try {
    const response = await fetch(`${this.apiUrl}/categories`);
    this.logResponse(response, 'fetchCategories');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    this.categories = await response.json();
    this.checkCyclicDependencies();  // Check for cyclic dependencies after fetching
    console.log("Fetched categories:", this.categories);
  } catch (error) {
    console.error("Error fetching categories:", error);
    this.showMessage(`Failed to load categories: ${error.message}`, 'error');
  }
}
// Method for checking cyclic dependencies
checkCyclicDependencies() {
  const visited = new Set();
  const recStack = new Set();

  const hasCycle = (id) => {
    if (!visited.has(id)) {
      visited.add(id);
      recStack.add(id);

      const category = this.categories.find(cat => cat.ID === id);
      if (category) {
        if (recStack.has(category.ParentID)) {
          return { hasCycle: true, cycleStart: category.ParentID };
        }

        if (category.ParentID !== null) {
          const result = hasCycle(category.ParentID);
          if (result.hasCycle) {
            return result;
          }
        }
      }
    }
    recStack.delete(id);
    return { hasCycle: false };
  };

  for (const cat of this.categories) {
    const result = hasCycle(cat.ID);
    if (result.hasCycle) {
      const cyclePath = this.getCyclePath(result.cycleStart);
      this.showMessage(`Cyclic dependency detected: ${cyclePath.join(" -> ")}`, 'warning');
      this.breakCycle(result.cycleStart);
      break;
    }
  }
}

// Method to get the cycle path for displaying cyclic dependency
getCyclePath(startId) {
  const path = [];
  let currentId = startId;
  do {
    path.push(this.categories.find(cat => cat.ID === currentId).Name);
    currentId = this.categories.find(cat => cat.ID === currentId).ParentID;
  } while (currentId !== startId);
  path.push(path[0]);  // Return to the start of the cycle
  return path;
}

// Method to break the cycle in case of cyclic dependency
breakCycle(startId) {
  let currentId = startId;
  let nextId;
  do {
    nextId = this.categories.find(cat => cat.ID === currentId).ParentID;
    this.categories.find(cat => cat.ID === currentId).ParentID = null;  // Break the cycle by removing the parent
    currentId = nextId;
  } while (currentId !== startId);
  this.showMessage("Cyclic dependency automatically broken", 'info');
}

async toggleParentCategory(cat) {
    const confirmToggle = confirm("Вы уверены, что хотите отменить родительскую категорию?");
    if (confirmToggle) {
        try {
            const updatedCategory = {
                ...cat,
                ParentID: null
            };

            const response = await fetch(`${this.apiUrl}/categories/${cat.ID}`, {
                method: "PUT",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify(updatedCategory),
            });
            this.logResponse(response, 'toggleParentCategory');

            if (!response.ok) {
                throw new Error('Не удалось отменить родительскую категорию');
            }

            // Обновляем локальный массив категорий
            const index = this.categories.findIndex(c => c.ID === cat.ID);
            if (index !== -1) {
                this.categories[index] = {...this.categories[index], ParentID: null};
            }

            // Обновляем визуальное представление
            this.$forceUpdate();

            this.showMessage('Статус родительской категории успешно изменен', 'success');
        } catch (error) {
            console.error("Ошибка при отмене родительской категории:", error);
            this.showMessage(`Ошибка при отмене родительской категории: ${error.message}`, 'error');

            // Откатываем изменения в случае ошибки
            await this.fetchCategories();
        }
    }
}

async toggleParentCategory(cat) {
  const confirmToggle = confirm("Are you sure you want to remove the parent category?");
  if (confirmToggle) {
    try {
      const updatedCategory = {
        ...cat,
        ParentID: null
      };

      const response = await fetch(`${this.apiUrl}/categories/${cat.ID}`, {
        method: "PUT",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(updatedCategory),
      });
      this.logResponse(response, 'toggleParentCategory');

      if (!response.ok) {
        throw new Error('Failed to remove parent category');
      }

      // Update the local categories array
      const index = this.categories.findIndex(c => c.ID === cat.ID);
      if (index !== -1) {
        this.categories[index] = { ...this.categories[index], ParentID: null };
      }

      // Force update the UI
      this.$forceUpdate();

      this.showMessage('Parent category successfully removed', 'success');
    } catch (error) {
      console.error("Error removing parent category:", error);
      this.showMessage(`Error removing parent category: ${error.message}`, 'error');

      // Rollback changes in case of error
      await this.fetchCategories();
    }
  }
}