How to Prevent Page Re-Rendering on Route Change with React, Shadcn-UI, and React-Table?

I am building a dashboard application using React, Shadcn-UI, and React-Router-Dom. The dashboard has a sidebar for navigation and various pages displaying data tables using React-Table.

const App = () => {
  const router = createBrowserRouter([
    {
      path: "/",
      element: <ProtectedRoute><RootLayout /></ProtectedRoute>,
      children: [
        { index: true, element: <Dashboard /> },
        { path: "/rolls", element: <RollsPage /> },
        { path: "/slits", element: <SlitsPage /> },
      ],
    },
    { path: "*", element: <>404</> },
  ]);
  return <RouterProvider router={router} />;
};
export default App;

RootLayout.jsx:

function RootLayout() {
  return (
    <SidebarProvider>
      <AppSidebar />
      <main>
        <Header />
        <Outlet />
      </main>
    </SidebarProvider>
  );
}

export default memo(RootLayout);

RollsPage.jsx:

function RollsPage() {
  return <RollTable />;
}
export default memo(RollsPage);

Question:
How can I prevent page re-rendering when navigating between routes in this setup? Are there better ways to optimize rendering for complex tables with actions and buttons in columns? Any tips on React-Router or React-Table configurations would be greatly appreciated!

React useState – getting stuck in generated data input form

I am developing a web application using React (React Bootstrap, Typescript, SCSS). I’ll be honest and say that I am completely new to JavaScript in general, so also to the components I am using. Great start, right!? But I have made progress; I fetch and display the items from my application server, I can search and I can open the item screen with all the details.

But now for the part where I am definitely getting confused, even after searching the internet. I am creating a page for editing an item. My application consists of modules (the application is Data Crow by the way). Each module has fields. Each field has a type.

So when I build up my page, I need to loop through the fields of the selected module.
I have made a context for the module (useModule). The page itself is sitting in an authorization context (RequireAuth).

Now, as you can see below I then loop though the fields and for each field I call a function (sitting in a separate .tsx file) to render the component. I kind of have to it this way as I have many module and user can define their own modules and fields.

So this is the item page:

import { useLocation, useNavigate } from "react-router-dom";
import { useEffect, useState } from "react";
import { fetchItem, fetchReferences, type Field, type Item, type References } from "../../services/datacrow_api";
import { RequireAuth } from "../../context/authentication_context";
import { useModule } from "../../context/module_context";
import { InputField } from "../../components/input/component_factory";
import { Button } from "react-bootstrap";
import Form from 'react-bootstrap/Form';

export function ItemPage() {

    const currentModule = useModule();

    useEffect(() => {
        currentModule.selectedModule && fetchItem(currentModule.selectedModule.index, state.itemID).then((data) => setItem(data));
    }, [currentModule.selectedModule]);

    useEffect(() => {
        currentModule.selectedModule && fetchReferences(currentModule.selectedModule.index).then((data) => setReferences(data));
    }, [currentModule.selectedModule]);

    
    const navigate = useNavigate();
    const { state } = useLocation();

    const [item, setItem] = useState<Item>();
    const [references, setReferences] = useState<References[]>();

    useEffect(() => {
        if (!state) {
            navigate('/');
        }
    }, []);
    
    
    const [validated, setValidated] = useState(false);
    
    function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
        event.preventDefault();
        event.stopPropagation();

        setValidated(true);
    };
    
    function ReferencesForField(field: Field) {

        var i = 0;
        while (i < references!.length) {
            if (references![i].moduleIdx === field.referencedModuleIdx)
                return references![i];

            i++;
        }

        return undefined;
    }

    return (
        <RequireAuth>
            <div style={{ display: "inline-block", width: "100%", textAlign: "left" }} key="item-details">
                <Form key="form-item-detail" noValidate validated={validated} onSubmit={handleSubmit} >
                    {references && item?.fields.map((fieldValue) => (
                        InputField(fieldValue.field, fieldValue.value, ReferencesForField(fieldValue.field))
                    ))}
                    
                    <Button type="submit">Save</Button>
                </Form>
            </div>
        </RequireAuth>
    );
}

So for each field the function InputField is called. This one looks as follows (work in progress hence the empty else if blocks):

import type { Field, References } from "../,,/../../services/datacrow_api";

import { Col, Form, Row } from "react-bootstrap";
import { DcTextField } from "./dc_textfield";
import { DcLongTextField } from "./dc_long_textfield";
import { DcCheckBox } from "./dc_checkbox";
import { DcUrlField } from "./dc_url_field";
import { DcDateField } from "./dc_datefield";
import { DcNumberField } from "./dc_numberfield";
import { DcDecimalField } from "./dc_decimalfield";
import { DcReferenceField } from "./dc_reference_field";

enum FieldType {
    CheckBox = 0,
    TextField = 1,
    LongTextField = 2,
    DropDown = 3,
    UrlField = 4,
    ReferencesField = 5,
    DateField = 6,
    FileField = 7,
    TagField = 8,
    RatingField = 9,
    IconField = 10,
    NumberField = 11,
    DecimalField = 12,
    DurationField = 13
}

function Field(field : Field, value : Object, references?: References) {
    if (field.type === FieldType.CheckBox) {
        return DcCheckBox(field, value);
    } else if (field.type === FieldType.TextField) {
        return DcTextField(field, value);
    } else if (field.type === FieldType.LongTextField) {
        return DcLongTextField(field, value);
    } else if (field.type === FieldType.DropDown) {
        return DcReferenceField(field, value, references);
    } else if (field.type === FieldType.UrlField) {
        return DcUrlField(field, value);
    } else if (field.type === FieldType.ReferencesField) {
        
    } else if (field.type === FieldType.DateField) {
        return DcDateField(field, value);
    } else if (field.type === FieldType.FileField) {
        
    } else if (field.type === FieldType.TagField) {
    
    } else if (field.type === FieldType.RatingField) {
        
    } else if (field.type === FieldType.IconField) {

    } else if (field.type === FieldType.NumberField) {
        return DcNumberField(field, value);
    } else if (field.type === FieldType.DecimalField) {
        return DcDecimalField(field, value);
    } else if (field.type === FieldType.DurationField) {
        
    }
}

export function InputField(field: Field, value: Object, references?: References) {
    return (
        <Col key={"detailsColField" + field.index}>
            {field.type != FieldType.CheckBox ?
                <Row key={"detailsRowLabelField" + field.index}>
                    <Form.Label
                        style={{ textAlign: "left" }}
                        className="text-secondary"
                        key={"label-" + field.index}
                        htmlFor={"field-" + field.index}>
                        {field.label}
                    </Form.Label>
                </Row>
                :
                ""}

            <Row key={"detailsRowInputField" + field.index} className="mb-3">
                <Form.Group>
                    {Field(field, value, references)}
                    <Form.Control.Feedback>ok</Form.Control.Feedback>
                </Form.Group>
            </Row>
        </Col>
    )
}

And now onto the problem at hand; I have a reference field (which is a React-Select component). I have also added this below. The only thing here is that I want to make a useState call to trigger an icon update for when the dropdown is collapsed. But this triggers the probably very well know error: React has detected a change in the order of Hooks called by ItemPage. This will lead to bugs and errors if not fixed. For more information (and a RTFM message, which I did and after which I did I get the feeling I am doomed).

This is what I am trying to add: const [selectedValue, setSelectedValue] = useState<null>();

I am I just completely doing the wrong thing? Am in a to deep a layer to make use of hooks here? That’s basically all I am looking for in an answer, more is appreciated but that is the essence of this post. Help…. 🙂

import Select, { components, type ActionMeta, type ControlProps, type GroupBase, type MultiValue, type OptionProps, type SingleValue } from 'react-select'
import { type Field, type References } from "../.././services/datacrow_api";
import type { JSX } from 'react/jsx-runtime';

export interface IconSelectOption {
    value: string;
    label: string;
    iconUrl: string;
}

export function DcReferenceField(field: Field, value: Object, references?: References) {

    const { Option } = components;

    const IconOption = (props: JSX.IntrinsicAttributes & OptionProps<IconSelectOption, boolean, GroupBase<IconSelectOption>>) => (
        <Option {...props}>
            <img
                src={props.data.iconUrl}
                style={{ width: 24 }}
            />
            {props.data.label}
        </Option>
    );

    function CurrentValue() {

        let idx = 0;
        let selectedIdx = -1;

        options.forEach((option) => {
            if (option.value === value)
                selectedIdx = idx;
            idx++;
        });

        return options[selectedIdx];
    }

    function Options() {

        let options: IconSelectOption[] = [];

        if (references && references.items) {
            references.items.map(reference =>
                options.push({ value: reference.id, label: reference.name, iconUrl: reference.iconUrl }),
            );
        }

        return options;
    }

    const options = Options();
    const currentValue = CurrentValue();

    const Control = ({ children, ...props }: ControlProps<IconSelectOption, boolean, GroupBase<IconSelectOption>>) => (
        <components.Control {...props}>
            <img src={currentValue.iconUrl} />
            {children}
        </components.Control>
    );

    function selectionChanged(newValue: SingleValue<IconSelectOption> | MultiValue<IconSelectOption>, actionMeta: ActionMeta<IconSelectOption>): void {

        if (!options || !newValue || !currentValue) return;

        if (Array.isArray(newValue)) {

        } else {
            //setSelectedValue(newValue as IconSelectOption);
        }
    }

    return (
        <Select
            className="basic-single"
            classNamePrefix="select"
            options={options}
            defaultValue={currentValue}
            onChange={selectionChanged}
            isClearable
            isSearchable
            placeholder="..."
            components={{ Option: IconOption, Control }} />
    );
}

Full error details:

React has detected a change in the order of Hooks called by ItemPage. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://react.dev/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useEffect                  useEffect
3. useEffect                  useEffect
4. useContext                 useContext
5. useContext                 useContext
6. useContext                 useContext
7. useContext                 useContext
8. useContext                 useContext
9. useContext                 useContext
10. useContext                useContext
11. useRef                    useRef
12. useContext                useContext
13. useLayoutEffect           useLayoutEffect
14. useCallback               useCallback
15. useContext                useContext
16. useContext                useContext
17. useState                  useState
18. useState                  useState
19. useEffect                 useEffect
20. useState                  useState
21. undefined                 useReducer
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Component Stack: 
    ItemPage item_details.tsx:12
    RenderedRoute chunk-D52XG6IA.mjs:4355
    Outlet chunk-D52XG6IA.mjs:4976
    div unknown:0
    Layout unknown:0
    RenderedRoute chunk-D52XG6IA.mjs:4355
    Routes chunk-D52XG6IA.mjs:5041
    ModuleProvider module_context.tsx:16
    AuthProvider authentication_context.tsx:17
    App unknown:0
    Router chunk-D52XG6IA.mjs:4984
    BrowserRouter chunk-D52XG6IA.mjs:7059

Many thanks for your time!

Vite React not building jsx into js when deploying to Github Pages [closed]

I am using Vite with a React project and the JSX extension for all the React files in the app. Before, I could see my app fine after building and previewing, but now receive an error saying ‘react is not defined’. Also, my original error was after I built and deployed my app to GitHub pages, I receive the message:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “main/jsx”.

I have made sure that the page deploys into a separate branch, and have tried many solutions of other similar questions to no avail.

Here is the repo: https://github.com/johnwaugh1/johnwaugh1.github.io

Send Mail after Form Submit to Google Sheet

I found this wonderful app script on Github for writing to my Google spreadsheet. It works perfectly. Now I’m looking for a way to send myself an email after the script has run. But this is proving difficult. I want to call my own EmailNote() function. It works very well on its own, i.e. when started from the editor, but when I try to integrate it in the doPost(e) script, no email is sent. Kindly ask for help!

My doPost(e) Script:

// Manual: https://github.com/levinunnink/html-form-to-google-sheet

var sheetName = 'Entries' var scriptProp = PropertiesService.getScriptProperties()

function intialSetup () {
  var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  scriptProp.setProperty('key', activeSpreadsheet.getId())
}

function doPost (e) {
  var lock = LockService.getScriptLock()
  lock.tryLock(10000)

  try {
    var doc = SpreadsheetApp.openById(scriptProp.getProperty('key'))
    var sheet = doc.getSheetByName(sheetName)

    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
    var nextRow = sheet.getLastRow() + 1

    var newRow = headers.map(function(header) {
      return header === 'timestamp' ? new Date() : e.parameter[header]
    })

    sheet.getRange(nextRow, 1, 1, newRow.length).setValues([newRow])
    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'success', 'row': nextRow }))
      .setMimeType(ContentService.MimeType.JSON)
  }
 
  catch (e) {
    return ContentService
      .createTextOutput(JSON.stringify({ 'result': 'error', 'error': e }))
      .setMimeType(ContentService.MimeType.JSON)
  }

  finally {
    lock.releaseLock()
  }
}

My EmailNote() Script:

function EmailNote() {
  var emailSender = "[email protected]";
  var emailRecipients = ["[email protected]", "[email protected]"];
  var emailSubject = "App Script - Email";
  var emailBody ='App Script - Email';

  // send mail
  GmailApp.sendEmail(emailRecipients.join(","), emailSubject, emailBody, {
    from: emailSender
  });
}

How to Extract JSON Data from a String with JavaScript Regex and Parse it?

I am trying to extract a specific JSON-like structure from a string using JavaScript. The data contains entries that look like "NCR1": [...], "NCR2": {...}, and I want to parse this into a valid JSON object. However, when I attempt to extract and parse the data, I encounter issues.

function extractJSON2(strData) {
    const jsonPattern = /"NCRd+":s*[.*?]/g;
    const match = strData.match(jsonPattern);

    if (match) {
        let jsonString = match.join(""); 
        try {
            const FJson = match.join(""); 
            const x = JSON.parse(FJson);
            return FJson;
        } catch (error) {
            console.error("Error parsing extracted data:", error);
            return null;
        }
    } else {
        console.warn("Data structure not found in provided string.");
        return null;
    }
}

Problem:

  • The string strData contains multiple JavaScript <script> tags and embedded JavaScript objects, along with the data that I need to extract (the "NCRd+" objects).

  • I am using a regular expression to match the "NCRd+" objects and then trying to parse them into JSON. However, after extraction, when I attempt to parse it, I receive an error or unexpected result.

  • The data in strData seems to be quite complex, with scripts and other JavaScript objects around the target JSON-like data.

    What I’ve Tried:

    • I’ve tried using the regular expression /NCRd+":s*[.*?]/g to match all "NCRd+" patterns but haven’t been able to successfully extract and parse the JSON.

    • I joined the matches into one string and tried parsing, but the result is not as expected.

    Questions:

    1. How can I correctly extract the JSON-like data and ensure it is a valid JSON object?

    2. Is there a better way to parse this data, especially considering it might have extra JavaScript code around it?

      My Sample Data:

      Strdata = <script language=”JavaScript” src=”WEB-CORE/scripts/sapphirersaencrypt.js”></script>

      <script language=”JavaScript”>var rsa = new RSAKey();rsa.setPublic(‘…’);</script>

      <script type=”text/javascript” src=”WEB-CORE/scripts/json.js”></script>

      <script type=”text/javascript”>…some more scripts…</script>

      <!– The JSON data in the JavaScript code –>

      “NCR1”:[{“unit”:”DCT”,”year”:2021,”sum”:0},…]

      “NCR2”:{“color”:[“#A40000″,”#A40000″,”#DA0000″,”#F20000”],…}

      My Expect Result is

      {
         "NCR1":[
            {
               "unit":"DCT",
               "year":2021,
               "sum":0
            },
            {
               "unit":"DCT",
               "year":2022,
               "sum":0
            },
            {
               "unit":"DCT",
               "year":2023,
               "sum":0
            },
            {
               "unit":"DCT",
               "year":2024,
               "sum":3
            },
            {
               "unit":"Final product",
               "year":2021,
               "sum":0
            },
            {
               "unit":"Final product",
               "year":2022,
               "sum":0
            },
            {
               "unit":"Final product",
               "year":2023,
               "sum":0
            },
            {
               "unit":"Final product",
               "year":2024,
               "sum":1
            }
         ],
         "NCR2":{
            "color":[
               "#A40000",
               "#A40000",
               "#DA0000",
               "#F20000",
               "#FF6969",
               "#FF9797",
               "#FFBDBD",
               "#FFD5D5",
               "#FEBB00",
               "#FEBB00",
               "#FFD966",
               "#FFEDB3",
               "#FF00FF",
               "#FF00FF",
               "#FF66FF",
               "#FF99FF",
               "#70AD47",
               "#70AD47",
               "#A9D08E",
               "#C6E0B4",
               "#C6E0B4",
               "#305496",
               "#305496",
               "#2F75B5",
               "#5597D3",
               "#88B6E0",
               "#B4C6E7",
               "#D9E1F2"
            ],
            "objSeries":[
               {
                  "grp":"Properties",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Properties"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     1
                  ],
                  "name":"Flow"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Mechanical"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     1
                  ],
                  "name":"Chemical & Residual"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Addtive"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Heat stability"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Special F-Emission"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Others"
               },
               {
                  "grp":"Color & App",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Color & App"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Color"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Transparency"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Appearance"
               },
               {
                  "grp":"Contaminate",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Contaminate"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Contamination"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Burned Material"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Foreign Material"
               },
               {
                  "grp":"Others",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Others"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Packaging"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Trial product"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Suspect product"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Others"
               },
               {
                  "grp":"Raw Mat",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Raw Mat"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Appearance"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Contamination"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Properties"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Over Shelflife"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Packaging"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Other"
               }
            ],
            "categories":[
               2021,
               2022,
               2023,
               2024
            ]
         },
         "NCR3":{
            "color":[
               "#DA0000",
               "#DA0000",
               "#FF6969",
               "#2F75B5",
               "#2F75B5",
               "#5597D3",
               "#88B6E0",
               "#B4C6E7",
               "#FEBB00",
               "#FEBB00",
               "#FFD966",
               "#FFEDB3",
               "#FFEDB3",
               "#FF00FF",
               "#FF00FF",
               "#FF66FF",
               "#FF99FF",
               "#70AD47",
               "#70AD47",
               "#A9D08E",
               "#C6E0B4"
            ],
            "objSeries":[
               {
                  "grp":"Man",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Man"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Mis-additive/recipe"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     1
                  ],
                  "name":"Mis-operation/condition"
               },
               {
                  "grp":"Machine",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Machine"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Polymerization Facility"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     1
                  ],
                  "name":"Extrusion & Pelletizing Facility"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Packing Facility"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Process instrument / equipment trouble"
               },
               {
                  "grp":"Method",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Method"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"RM preparing method"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Process Condition / operation & environment control"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Inspection method"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Recipe or Technology"
               },
               {
                  "grp":"Material",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Material"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     3
                  ],
                  "name":"RM quality"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Base resin"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Packaging"
               },
               {
                  "grp":"Other",
                  "data":[
                     null,
                     null,
                     null,
                     null
                  ],
                  "name":"Other"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Storage & delivery"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Over shelf life / Dead stock"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Other"
               }
            ],
            "categories":[
               2021,
               2022,
               2023,
               2024
            ]
         },
         "NCR4":{
            "color":[
               "#70AD47",
               "#A9D08E",
               "#FFFF99",
               "#F4B084",
               "#ED49F1",
               "#FFC000",
               "#FF6969",
               "#7030A0",
               "#EA0000",
               "#AEAAAA"
            ],
            "objSeries":[
               {
                  "data":[
                     0,
                     0,
                     0,
                     3
                  ],
                  "name":"Special accept as normal"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Special accept with condition"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Grade change as specified"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Rework"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Multiple handling as specified"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Off spec for sale as wide spec"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Off spec for recycle"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Reject"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Waste"
               },
               {
                  "data":[
                     0,
                     0,
                     0,
                     0
                  ],
                  "name":"Other"
               }
            ],
            "categories":[
               2021,
               2022,
               2023,
               2024
            ]
         }
      }
      
  • What I’ve Tried:

    • What I have tried:

      • I used the match method with a regular expression to extract the JSON-like data from the string.

      • I joined the matched results and attempted to parse them with JSON.parse().

      Any help would be appreciated!

Intl.NumberFormat alter currency symbol

I’ve read through the Intl.NumberFormat docs and can’t find a simple way to achieve something.
I want to use a custom character for the minus symbol:

− instead of -

(UNICODE &#8722; instead of ASCII Code &#45;)

for screen reader reasons.

I don’t see an option to do this in the Intl.NumberFormat – is there a way to change the character for currency formatting as part of the options?

Or is simply tagging a replace onto the end the best approach?

Zoom in ChartJS is not centered in the mouse position

I’m having trouble with the zoom using ChartJS. I’m using a canvas with a candle chart to display the stock price and other two canvas to display bars for the volume.
The problem is that when zooming, it does not zoom where I have the cursor. It moves the X axis and it ends up in a different position. I attach a gif below:

https://gifyu.com/image/SJPgi

This is the code I use to populate the data into the candle chart

const customPlugins = [
    crosshairPlugin,
    smaPlugin,
    emaPlugin,
    fixedWidthYAxisPlugin,
    chartMaxCandleWidthPlugin,
    createPanPlugin,
    createZoomPlugin,
];

candleChart = new Chart(ctx, {
    type: 'candlestick',
    data: {
        datasets: [{
            label: stock.Name,
            data: items,
        }]
    },
    options: {
        animation: false,
        scales: {
            x: {
                type: 'timeseries',
                time: {
                    unit: intradayUnit,
                },
                grid: {
                    display: false
                },
                ticks: {
                    display: true,
                    beginAtZero: true,
                    autoSkip: false,
                    stepSize: intradayStepSize,
                    maxRotation: 90,
                    minRotation: 90,
                    padding: 10,
                    color: 'transparent'
                },
                offset: false,
                min: minDate,
                max: new Date()
            },
            y: {
                position: 'right',
                title: {
                    display: true,
                    text: 'Price'
                }
            }
        },
        hover: {
            mode: 'index',
            intersect: false,
        },
        plugins: {
            legend: {
                display: false
            },
            tooltip: {
                enabled: false
            },
            zoomPlugin: {},
            sync: { targets: [] },
            sma: {
                enabled: $scope.FilteringOptions.Filters.ShowSMA,
                itemProperty: 'c',
                locked: $scope.FilteringOptions.Filters.SMALocked,
            },
            ema: {
                enabled: $scope.FilteringOptions.Filters.ShowEMA,
                itemProperty: 'c',
                locked: $scope.FilteringOptions.Filters.SMALocked,
            },
            fixedWidthYAxis: true,
        },
        layout: {
            padding: {
                bottom: -30
            }
        },
        onHover: function (event, elements) {
            $timeout(function () {
                $scope.SelectChartElement(elements);
            });

            const rect = event.chart.canvas.getBoundingClientRect();
            candleChart.mouseX = event.native.clientX - rect.left;
            candleChart.mouseY = event.native.clientY - rect.top;
            candleChart.mouseActive = true;
            candleChart.update();
        }
    },
    plugins: customPlugins
});

ctx.canvas.addEventListener('mouseout', () => {
    candleChart.mouseActive = false;
    candleChart.update();
});

return candleChart;

This is the code for the Zoom (generated with chatGPT, tried a lot of prompts but none worked, always the same code):

const createZoomPlugin = {
    id: 'zoomPlugin',
    afterInit: (chart) => {
        const canvas = chart.canvas;

        chart.zoomState = {
            zoomFactor: 1.15,
            minZoomRange: 1000 * 60 * 5,
            maxZoomRange: 1000 * 60 * 60 * 24 * 60, 
        };

        canvas.addEventListener('wheel', (event) => {
            event.preventDefault();

            const xScale = chart.scales.x;
            if (!xScale) return;

            const mouseX = event.offsetX;
            const mouseValue = xScale.getValueForPixel(mouseX);

            const currentMin = xScale.min;
            const currentMax = xScale.max;
            const currentRange = currentMax - currentMin;

            const zoomFactor = event.deltaY > 0 ? chart.zoomState.zoomFactor : 1 / chart.zoomState.zoomFactor;
            const newRange = currentRange * zoomFactor;

            if (newRange > chart.zoomState.maxZoomRange || newRange < chart.zoomState.minZoomRange) {
                return;
            }

            const rangeProportion = (mouseValue - currentMin) / currentRange;
            const correctedMouseValue = Math.round(mouseValue);
            const newMin = correctedMouseValue - rangeProportion * newRange;
            const newMax = newMin + newRange;

            xScale.options.min = newMin;
            xScale.options.max = newMax;

            chart.update('none');

            if (chart.config.options.plugins.sync) {
                chart.config.options.plugins.sync.targets.forEach((targetChart) => {
                    const targetXScale = targetChart.scales.x;
                    if (!targetXScale) return;

                    targetXScale.options.min = xScale.options.min;
                    targetXScale.options.max = xScale.options.max;

                    targetChart.update('none');
                });
            }
        });


    },
};

Using “time” instead of “timeseries” is making it work correctly. But the problem is the holes in the chart, thats why we use timeseries.

What I want to achieve is that when zooming in/out, it it always centered in the mouse position, not moving the candles to right/left.

Scripts I’m using:
chartJS 4.4.5
luxon 3.5.0
chartjs-adapter-luxon v1.3.1
hammer 2.0.7

thanks

I tried different solutions provided by chatGPT for the zoom function but none worked.

I expect it to zoom centered in the mouse position.

I actually is zooming but moving the chart X axis to the side and the cursor ends up in a different position.

The breakdown of a regex [duplicate]

.replace(/B(?=(d{3})+(?!d))/g, “,”)

can someone explain what this means I know it is a regular expression but I dont understand what it is doing and what it means and what the purpose is. Its currently in my tooltip.

Svelte 5 : loading data server side and allow global access client side

I’m having a hard time understanding the use of Runes and data loading.
I load a supabase json file and I want to access the data globally.

+page.server.js:

export async function load() {
    const [_portfolioSummary, error] = await getFullPortfolio('/');
    return _portfolioSummary;
}

shared.svelte.js:


export let portfolioSummary = $state({});

+page.js:


import { portfolioSummary } from '../lib/js/shared.svelte.js';

export async function load({ data }) {
    portfolioSummary = data.portfolioSummary;
}

I get this error :
TypeError: Cannot set property portfolioSummary of #<Object> which has only a getter

What should I do to get portfolioData globally so I can use it anywhere ?

Thank you

How to access a class method inside of function which is inside of another method or same method? In JavaScript [duplicate]

How can I access a class method inside of a function which is inside of a method?
Look the code if I am unable to illustrate what I mean!

//example.js

class Example {
  getA(value) {
    let x = 5;
    return value + x;
  }
  
  getB(value) {
    const func = function(value) {
      return this.getA(value)
    }
  }
}
let ex = new Example();
console.log(ex.getB(2))

I think there must be a way

puppeteer solution for screenshot of a codeigniter modal has stopped working

I am revisiting a solution that has been working fine for several years but has just stopped working. I suspected old versions of node/npm/puppeteer and possibly incompatability of Chromium as suggested in my research. What I am trying to do is take a screenshot of a codeigniter modal in the background so users can share the image.

So I now have on my Ubuntu 20.04 server,
node v20.18.1 (which I believe is the latest LTS version),
npm v10.9.2,
and I have run npm i puppeteer which reports uptodate and no vulnerabilities.

I followed some instructions on downloading an uptodate Chromium so feel reasonably confident I should have a working system. However my little script is not reproducing the screen shot I require.

The script is as follows:

// node script for taking a screenshot of the gobig modal and writing it the "canvas" file
// gen_jpeg.js $ref $canvas_path

var myArgs = process.argv.slice(2);

const minimal_args = [
  '--autoplay-policy=user-gesture-required',
  '--disable-background-networking',
  '--disable-background-timer-throttling',
  '--disable-backgrounding-occluded-windows',
  '--disable-breakpad',
  '--disable-client-side-phishing-detection',
  '--disable-component-update',
  '--disable-default-apps',
  '--disable-dev-shm-usage',
  '--disable-domain-reliability',
  '--disable-features=AudioServiceOutOfProcess',
  '--disable-hang-monitor',
  '--disable-ipc-flooding-protection',
  '--disable-notifications',
  '--disable-offer-store-unmasked-wallet-cards',
  '--disable-popup-blocking',
  '--disable-print-preview',
  '--disable-prompt-on-repost',
  '--disable-renderer-backgrounding',
  '--disable-setuid-sandbox',
  '--disable-speech-api',
  '--disable-sync',
  '--hide-scrollbars',
  '--ignore-gpu-blacklist',
  '--metrics-recording-only',
  '--mute-audio',
  '--no-default-browser-check',
  '--no-first-run',
  '--no-pings',
  '--no-sandbox',
  '--no-zygote',
  '--password-store=basic',
  '--use-gl=swiftshader',
  '--use-mock-keychain',
  '--allow-insecure-localhost',
];

const puppeteer = require('puppeteer');
const VIEWPORT = {width: 1024, height: 1500};
const URL = 'http://localhost/make-canvas/'+myArgs[0]; 

(async () => {
    const browser = await puppeteer.launch({args:minimal_args,headless:true,ignoreHTTPSErrors: true,userDataDir:'/var/www/html/res/node/puppeteer_cache'});
    const page = await browser.newPage();
    await page.setViewport(VIEWPORT);
    //await page.setCookie({name:'GNB_cookies',value:'dismiss',domain:'goodnewsbig.com'});
    //await page.goto(URL);
    await page.goto(URL,{waitUntil: 'domcontentloaded'});
    const modal = await page.waitForSelector('#gobig',{visible:true});
    await modal.screenshot({ path: myArgs[1], type: 'jpeg' });
    await page.close();
    await browser.close();
})()

The above script appears to run without error but the finished image is incomplete.
Can anyone see any obvious gotchas or suggest how I might get some more useful debugging info please?

TIA , Paul

Error: Debug Failure after updating Angular from 16 to 17 during build or serve

I recently updated my Angular project from version 16 to 17. The update went smoothly, including the installation of node_modules. However, when I attempt to build or serve the project, I get the following error:

./src/app/pages/faculty/faculty-basic-details-update/faculty-basic-details-update.component.ts - Error: Module build failed (from ./node_modules/@ngtools/webpack/src/ivy/index.js): Error: Debug Failure.

Versions in use :

@angular-devkit/architect          0.1703.11
@angular-devkit/build-angular      17.3.11
@angular-devkit/core               17.3.11
@angular-devkit/schematics         17.3.11
@angular/cdk                       17.3.10
@angular/cli                       17.3.11
@angular/material                  17.3.10
@angular/material-moment-adapter   17.3.10
@schematics/angular                17.3.11
rxjs                               7.8.1
typescript                         5.4.5
zone.js                            0.14.10
Node                               18.13.0

What I’ve tried so far:

  1. Deleted node_modules and reinstalled them using npm install.
  2. Ran ng update @angular/cli @angular/core to ensure compatibility.
  3. Cleared the Angular cache using ng cache clean.
  4. Checked for deprecated dependencies or breaking changes in package.json.

Despite these steps, the issue persists.

Has anyone encountered a similar issue during an upgrade to Angular 17? What are the possible causes of this Debug Failure error? Any advice or debugging tips would be greatly appreciated!

background-image svg scaling not working svelte

So I have multiple < p > elements inside a < div > which is inside an overall container. The container has an svg graphic as a background image with the top and bottom being wavy sides (so should not get cropped)

I’ve tried writting some JS to automatically scale the svg to 1) stretch the width of the screen and 2) stretch the vertical so all text is inside the svg.

This is in the OnMount function: (paraContainer is the overall container)

    function updateScale() {
        const paraContainer = document.getElementById('introPara');
        const style = window.getComputedStyle(paraContainer, "::before");
        const backgroundImage = style.backgroundImage;

        let imageUrl = backgroundImage.slice(5, -2);
        let imgHeight = 0;
        let imgWidth = 0;
        const img = new Image();
        img.onload = function () {
            imgHeight = img.height;
            imgWidth = img.width;
            const containerHeight = paraContainer.offsetHeight;
            const containerWidth = paraContainer.offsetWidth;

            const scaleX = (containerWidth / imgWidth) * 2;
            const scaleY = (containerHeight / imgHeight) * 1.2;

            paraContainer.style.backgroundSize = `${scaleX * 100}% ${scaleY * 100}%`;

        };
        img.src = imageUrl;
    }

    window.addEventListener('resize', updateScale);
    updateScale();

And this is my CSS:

.intro-para {
    color: white !important;
     padding: 2vw 5vw 2vw 5vw !important;
    width: 100vw !important;
    max-width: 100% !important;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow-x: clip;
}

#introPara::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-image: url('../../static/SVG/Asset 8 pink.svg#svgView(preserveAspectRatio(none))');
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    z-index: -1;
}

And then the HTML:

<div class="container intro-para" id="introPara">
    <div class="para-content" id="textContainer">
        <p>Text</p>
        <p>Text</p>
        <p>Text</p>
        <p>Text</p>
    </div>
</div>

However this does not scale the image, even tweaking the background-size % values in paraContainer’s inspect element doesn’t change anything. What’ve I done wrong here? Any help appreciated 🙂

Strange behavior of nativewind in expo application, half working, half not

This is very weird, here is an example of what exactly is happening

enter image description here

import { View, Text } from "react-native";
import { StyleSheet } from "react-native";

export default function EditScreenInfo({ path }: { path: string }) {
  return (
    <>
      <View className='mt-12 items-center'>
        <Text>Open up the code for this screen:</Text>
      </View>
      <View className='mt-12'>
        <Text className='text-center'>
          Change any of the text, save the file, and your app will automatically
          update.
        </Text>
      </View>
    </>
  );
}

The problem is that if you change 12 in mt-12 to any other number, mt will stop working

and text-center not working as well

enter image description here

import { View, Text } from "react-native";
import { StyleSheet } from "react-native";

export default function EditScreenInfo({ path }: { path: string }) {
  return (
    <>
      <View className='mt-12 items-center'>
        <Text>Open up the code for this screen:</Text>
      </View>
      <View className='mt-10'>
        <Text className='text-center'>
          Change any of the text, save the file, and your app will automatically
          update.
        </Text>
      </View>
    </>
  );
}

see? I changed

<View className='mt-12'>
  <Text className='text-center'>
     Change any of the text, save the file, and your app will automatically
     update.
  </Text>
</View>

to

<View className='mt-10'>
  <Text className='text-center'>
     Change any of the text, save the file, and your app will automatically
     update.
  </Text>
</View>

className='mt-12' to className='mt-10'

and it stopped working, no matter what number I enter there, it only works with mt-12, why is that?

"nativewind": "^4.1.23",
"tailwindcss": "^3.4.16"

implemented everything according to the documentation

I tried restarting via npx expo start –clear without cache, but mt-10 still didn’t apply after that

Can I check whether a browser already allows the user to ‘see password’?

Building a site in React, and on the login screen I have the usual password fields. I’ve created my own ‘See Password’ icon which works, but when I looked at the site in Edge rather than Chrome I realised that there’s already a built-in ‘eye’ icon to see the password. Is there a way to tell whether the user’s browser has this feature so that I can hide my own version when it’s not needed?