Optimizing React State Updates to Avoid Unnecessary Re-Renders

I’m working on a form-based React application where I manage a state object called editClient. One of the fields in this object, CallOutSection, is an array that contains multiple sections, and each section has a method field. I need to update the method value for a specific section when a user interacts with a dropdown (dxSelectBox).

The problem I’m facing is that when I update the method for one section, the entire state (editClient) is updated, which causes unnecessary re-renders of the entire component. This re-render is not only inefficient but also disrupts conditional rendering that depends on specific fields in CallOutSection.

Here’s how I’m currently handling the state update:

       Data.js code:
    
    export const client = {
     GUID: "Add",
      Name: "",
      Email: "",
      ClientCode: "",
      EMSDetails: {
        username: "",
        password: "",
        url: "",
        version: "",
      },
        CallOutSection: [],
    }
    
    client.js code:
    
    import {
      client,
    } from "./Data.js";
    export default function Clients(props) {
      const [editClient, setEditClient] = useState(null);
     function addNewClient() {
        setAddEditMode(1);
        setEditClient(deepCopy(client));
        setViewSapIdocFile(false);
        setViewOracleIdocFile(false);
      }
    function handleAddCallout() {
        if (editClient?.CallOutSection?.length < 2 || editClient?.CallOutSection == undefined || editClient?.CallOutSection == null) {
          setEditClient(prev => {
            const updatedClient = { ...prev };
            if (!updatedClient.CallOutSection) {
              updatedClient.CallOutSection = [];
            }
            updatedClient.CallOutSection.push({
              triggerCallOut: "",
              authenticationMethod: "",
              Username: "",
              Password: "",
              method: "",
              RequestPayload: "",
              url: "",
              waitforResponse: false,
              queryParams: "",
              timeout: "",
              abortifrequesttimesout: true,
              responseCode: "",
              abortifCodedoesntmatch: false,
              replaceKey: "",
              replaceValue: "",
              inCaseOfError: "",
              // Add other default fields for CallOutSection here
            });
            return updatedClient;
          });
        }
  }
<Tab title="Callout Configuration">
                  <SCButton text="Add Callout" className="addCalloutbtn" onClick={handleAddCallout} disabled={editClient?.CallOutSection?.length >= 2} />
                  {editClient?.CallOutSection &&
                    editClient.CallOutSection.map((callout, index) => (
                      <div style={{
                        flex: 1
                      }}>
                        <React.Fragment >
                          <ReactForm key={index} formData={callout} id={`callout-form-${index}`} >
                            <GroupItem className="callout-section">
                              {/* Header spanning both columns */}
                              <SimpleItem cssClass="group-heading" colSpan={2}>
                                <div
                                  style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
                                  onClick={() => toggleCollapse(index)}
                                >
                                  <FontAwesomeIcon
                                    icon={!isCollapsedArray[index] ? faAngleDown : faAngleUp} // Toggle icon
                                    style={{ marginRight: '10px' }}
                                  />
                                  <h5>{`Callout ${index + 1}`}</h5>
                                </div>
                              </SimpleItem>

                              {!isCollapsedArray[index] && (
                                <GroupItem colCount={2}>
                                  <GroupItem colCount={1}>
                                    <SimpleItem
                                      dataField="triggerCallOut"
                                      editorType="dxSelectBox"
                                      editorOptions={{
                                        dataSource: triggerOptions,
                                        readOnly: isReadOnlyArray[index],
                                        value: callout.triggerCallOut,

                                        dropDownOptions: {
                                          hideOnParentScroll: true,
                                          container: ".Clients.content"
                                        },
                                      }}>
                                      <Label text="Trigger Call Out" />
                                      <RequiredRule message="Please Select trigger" />
                                    </SimpleItem>

                                    <SimpleItem
                                      editorType="dxSelectBox"
                                      dataField="authenticationMethod"
                                      editorOptions={{
                                        dataSource: authenticationMethods,
                                        value: callout.authenticationMethod,
                                        readOnly: isReadOnlyArray[index],
                                        onValueChanged: (e) => {
                                          setEditClient(prev => {
                                            prev.CallOutSection[index].authenticationMethod = e.value;
                                            return deepCopy(prev);
                                          });
                                        },
                                        dropDownOptions: {
                                          hideOnParentScroll: true,
                                          container: ".Clients.content"
                                        },
                                      }}>
                                      <Label text="Authentication Method" />
                                      <RequiredRule message="Please Select authentication method" />
                                    </SimpleItem>

                                    {/* Conditionally render Username and Password fields */}
                                    {callout.authenticationMethod === "Basic" && (
                                      <GroupItem colCount={2}>
                                        <SimpleItem
                                          dataField="Username"
                                          editorType="dxTextBox"
                                          editorOptions={{
                                            maxLength: 200,
                                            readOnly: isReadOnlyArray[index],
                                            value: callout.Username,

                                          }}>
                                          <Label text="Username" />
                                          <RequiredRule message="Username Required" />
                                        </SimpleItem>
                                        <SimpleItem
                                          dataField="Password"
                                          editorType="dxTextBox"

                                          editorOptions={{
                                            maxLength: 200,
                                            mode: "password",
                                            readOnly: isReadOnlyArray[index],
                                            value: callout.Password,

                                          }}>
                                          <Label text="Password" />
                                          <RequiredRule message="Password Required" />
                                        </SimpleItem>
                                      </GroupItem>
                                    )}

                                    <SimpleItem
                                      dataField="method"
                                      editorType="dxSelectBox"
                                      editorOptions={{
                                        dataSource: methodOptions,
                                        value: callout.method,
                                        onValueChanged: (e) => {
                                          setEditClient(prev => {
                                            prev.CallOutSection[index].method = e.value;
                                            return deepCopy(prev);
                                          });
                                        },
                                        readOnly: isReadOnlyArray[index],
                                        dropDownOptions: {
                                          hideOnParentScroll: true,
                                          container: ".Clients.content"
                                        },
                                      }}>
                                      <Label text="Method" />
                                      <RequiredRule message="Please Select Method" />
                                    </SimpleItem>

                                    {/* Conditionally render Request Payload field if Method is POST */}
                                    {callout.method === "POST" && (
                                      <SimpleItem
                                        dataField="RequestPayload"
                                        editorType="dxTextBox"
                                        editorOptions={{
                                          readOnly: isReadOnlyArray[index],
                                          value: callout.RequestPayload,

                                        }}>
                                        <Label text="Request Payload" />
                                        <RequiredRule message="Payload Required" />
                                      </SimpleItem>
                                    )}

In this code, when a user changes the method field in a specific section, I’m updating the entire ‘editClient’ state by the property ‘onValueChanged’. However, React sees this as an update to the whole object, even though only one field is changing, and this causes the entire editClient state to re-render the entire screen.

Problem:

  1. I only need to update the method field for the specific section that
    has changed, but React triggers a full re-render of the entire
    component because the reference to editClient is being updated.

  2. This causes performance issues, especially when there are many
    sections in CallOutSection, and also disrupts conditional rendering
    based on field values.

I want to only update the method field of a specific CallOutSection and prevent the entire editClient state from being updated or re-rendered. My goal is to optimize performance and ensure that only the affected UI component re-renders when the method field is changed, without triggering a re-render for other parts of the state or other sections.

Questions:

  1. How can I update only the method field for a specific index in CallOutSection without updating the entire state and causing unnecessary re-renders?

  2. Is there a way to optimize React’s state update so that only the affected field is updated in the DOM without affecting other state parts?

Any suggestions or advice would be highly appreciated!

Thanks in advance!

Array function returning one number more than input [closed]

I have a function node in node-red to output messages to the next node based on a number input it receives set up as follows:

var cards = msg.payload.cards;
var controller = msg.payload.deviceId;
for (let i = 1; i <= cards; i++) {
    msg.payload = {"deviceId": controller, "index": i};    
    node.send(msg);
    };
return msg;

The input to the cards variable is for example 2 but returns three messages. Its is outputing i as 1,2,2 not just 1,2 as required

I’m think this is a misunderstanding of the operators on my part but can’t work out why. I have tried numerous examples and explanations from online research but can’t work out a solution. I have tried changing the initial value of i to zero or two but this doesn’t resolve the issue. I have also tried using just less than as the operator but this only returns 1.

TinyMCE split button – how to trigger an event on dropdown?

My goal is to style some items on the dropdown menu I get after clicking on the dropdown icon of split button, and to rearrange items via DOM manipulation as a custom function.

My issue is, I don’t see a way to do this. The only ‘on’ events there are are OnSetup (won’t work, the dropdown menu doesn’t exist at that point), and onAction/onActionSetup (they apply only after either applying or choosing an item, which is too late for me)

I’d be grateful for advice on how to deal with this. Hacky solutions are fine too.

How to delete parent SSR div in `use client` button?

I have this NextJS(v15) component redered with SSR and want the Item to be available for search engines. And I have a delete button that should delete this component from DOM. I can delete the parent in DeleteMeButton with getElementById(parentId) or by passing the parent ref to the DeleteMeButton. But what is the best React way to do this using SSR + use client? Thanks.

export const Item = () => {
  return (
    <div>
      <DeleteMeButton />
      Content here
    </div>
  );
};


Delete.tsx
("use client");
export const DeleteMeButton = () => {
  const handleDelete = () => {
    //delete the parent component here
  };
  return <button onClick={handleDelete}>Delete me</button>;
};

Fetching 10000+ data from Indexed DB [closed]

I have been fetching some study data from Indexed DB and for 10000+ records it is taking very long time to load (almost 40s). here dixie has already being used.

async getCdiscDataDistinctValues (realm: Realm, study: StudyIds, domain: Domain, property: string)
this._checkMainArgs (realm, study, domain, false, true);
checkReq (property, 'property', 'string');
const store = this._loaderCache.getStore(this._loaderCache.storeId(realm, domain));
const records await store.where('STUDYID').anyOf(asArray (study))..toArray();
console.log("Records", records);
console.log("Store", store);
return uniq(map(records, property));
export const fetchDistinctValuesFromRawData = createAsyncThunk<
 FetchDistinctValuesFromRawDataPayload,
 FetchDistinctValuesFromRawDataReturnType[]
>(
 `${SLICE_PREFIX}/fetchDistinctValuesFromRawData`,
 async ({ studyIds, realm, domains, columns }, { rejectWithValue, getState }) => {
   try {
     console.log("Redux fetch started", new Date().getTime());
     const state = getState() as RootState;
     const results: any[] = [];
     // Iterate through each domain
     await Promise.all(
       asArray(domains).map(async (domain) => {
         const dataItem = studyDataItemSelector(state, { domain });
         const chunks = chunk(columns, 10); // Split columns into chunks of 10
         for (const columnsChunk of chunks) {
           const chunkResults = await Promise.all(
             asArray(columnsChunk).map(async (column) => {
               const startTime = performance.now();
               // Fetch distinct values for the current domain and column
               const values = await coreSdwDataApi.getCdiscDataDistinctValues(
                 realm,
                 studyIds,
                 domain,
                 column
               );
               const endTime = performance.now();
               console.log(
                 `Fetched values for ${domain}-${column} in ${endTime - startTime}ms`
               );
               return {
                 values,
                 domain,
                 column,
                 domainLastSync: dataItem?.lastSync,
               };
             })
           );
           results.push(...chunkResults); // Add chunk results to overall results
         }
       })
     );
     console.log("Redux fetch results", new Date().getTime(), results);
     return results;
   } catch (error) {
     console.error("Error fetching distinct values:", error);
     return rejectWithValue(error);
   }
 }
);

I am expecting that 10000+ records should not take this long to get it loaded into the screen. I tried multiple ways to get it done , I tried increasing or decreasing the size of chunks nothing worked. Please help me with this issue.

IndexedDB access gets completely blocked on iOS

I’ve stumbled upon a peculiar issue while implementing LocalForage in my web app, and I’m wondering if anyone else has encountered this or if I’m doing something wrong here.

I’m using LocalForage to handle data persistence with IndexedDB as the storage engine. The architecture is pretty straightforward:

  • Main thread handles data saving via LocalForage
  • WebWorker reads the stored data and sends it to the server
  • Everything runs smoothly on Android, but not on iOS.

On iOS, if you navigate away from the page while either reading or writing data, the IndexedDB access gets completely blocked – you can’t read or write anything until you reset the browser.

Here’s a simplified version of what I’m doing:

// Main thread
localforage.setItem('key', value).then(() => {
  // This works fine... until it doesn't
});

// Web Worker
localforage.getItem('key').then(value => {
  // This is where iOS decides to throw a tantrum
});

Steps to reproduce:

  1. Open this demo on iOS
  2. Start a save/read operation
  3. Navigate to a different page during the operation
  4. IndexedDB is now blocked

The only way to fix this is a full browser reset.

My questions are:

  1. Has anyone else run into this iOS-specific behavior?
  2. Is this a known limitation of IndexedDB/LocalForage on iOS?
  3. Are there any workarounds?

Environment details:

  • iOS: Tested on 16.7.10, also reproduced on lower and higher versions
  • Browser: Safari and other iOS browsers (they all use WebKit anyway)
  • LocalForage: Latest version
  • IndexedDB: Used as storage driver

React does not recognize the `initialValues` prop on a DOM element

react does not recognize the initialValues prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase initialvalues instead….

I know the cause and the solution, but I want to change the solution to the minimum, such as how to turn off this warning, because I made my own component library, external props are not controllable, I can not filter one by one.

Chart.js Panning Not Working in ASP.NET MVC Application Using chartjs-plugin-zoom

I’m developing an ASP.NET 8 MVC application where I’m using Chart.js to display two real-time line charts: one for “Penetration Depth” and another for “Hydrophone Audio Levels.” I’ve integrated the chartjs-plugin-zoom to enable zooming and panning functionalities. While zooming (both wheel and pinch) works as expected, panning (click and drag) does not respond on either chart.

I’ve ensured that the plugin is correctly registered and have adjusted the threshold settings, but panning remains non-functional.

Problem:

I have integrated the chartjs-plugin-zoom to enable both zooming and panning on my Chart.js line charts. While zooming functionalities (using the mouse wheel and pinch gestures) work correctly, panning (clicking and dragging to move around the chart) does not respond. This issue persists across both charts in my application.

Code for the Charts being Displayed:





@model Sampling.Models.ViewModels.SamplingDataViewModel
@using System.Text.Json

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Real-Time Chart</title>
    <!-- jQuery Library -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

    <!-- Chart.js and Luxon Adapter -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chartjs-plugin-zoom.min.js"></script>

    <style>
        .chart-container {
            position: relative;
            width: 100%;
            height: 60vh;
            margin-bottom: 50px;
        }

        #penetrationChartContainer, #hydrophoneChartContainer {
            background-color: #1a2b4c;
            padding: 20px;
            border-radius: 8px;
        }

        h2.chart-title {
            color: black;
            text-align: center;
            margin-top: 40px;
            margin-bottom: 20px;
            font-size: 1.5em;
        }
    </style>
</head>

<body>
    <!-- Penetration Reading Chart Section -->
    <h2 class="chart-title">Penetration Readings Chart</h2>
    <div class="chart-container" id="penetrationChartContainer">
        <canvas id="penetrationChart"></canvas>
    </div>

    <script>
        let lastPenetrationTimestamp = null;

        function initializePenetrationChart() {
            const ctx = document.getElementById('penetrationChart').getContext('2d');
            window.penetrationChart = new Chart(ctx, {
                type: 'line',
                data: {
                    datasets: [{
                        label: 'Penetration Depth',
                        data: [],
                        borderColor: '#ffcc00',
                        backgroundColor: '#ffcc00',
                        fill: false,
                        borderWidth: 2,
                        pointRadius: 2,
                        pointHoverRadius: 7
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time',
                            time: { unit: 'second', tooltipFormat: 'yyyy-MM-dd HH:mm:ss.SSSSSSS' },
                            ticks: { color: '#ffffff' },
                            title: { display: true, text: 'Time', color: '#ffffff' }
                        },
                        y: {
                            beginAtZero: true,
                            ticks: { color: '#ffffff' },
                            title: { display: true, text: 'Penetration Depth', color: '#ffffff' }
                        }
                    },
                    plugins: {
                        legend: { display: true, labels: { color: '#ffffff' } },
                        zoom: {
                            pan: { enabled: true, mode: 'xy', threshold: 10 },
                            zoom: { wheel: { enabled: true, speed: 0.05 }, pinch: { enabled: false }, mode: 'xy' }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(0, 0, 0, 0.7)',
                            titleColor: '#ffffff',
                            bodyColor: '#ffffff',
                            borderColor: '#ffffff',
                            borderWidth: 1,
                            callbacks: {
                                title: tooltipItems => tooltipItems[0].raw.x.replace('T', ' ').replace('Z', ''),
                                label: tooltipItem => `Sample ID: ${tooltipItem.raw.sId}, Depth: ${tooltipItem.parsed.y} m`
                            }
                        }
                    }
                }
            });
        }

        function updatePenetrationChart(newData) {
            const chart = window.penetrationChart;
            if (chart && chart.data.datasets[0]) {
                const formattedData = newData.map(item => ({ x: item.timeStamp, y: item.penetrationDepth, sId: item.sampId }));
                chart.data.datasets[0].data.push(...formattedData);
                chart.update();
                lastPenetrationTimestamp = formattedData[formattedData.length - 1].x;
            }
        }

        function fetchPenetrationDataBatch() {
            const data = lastPenetrationTimestamp ? { lastTimestamp: lastPenetrationTimestamp } : {};

            $.ajax({
                url: '/PenetrationReadings/GetPenetrationReadingsBatch',
                method: 'GET',
                data: data,
                success: function (newData) {
                    if (newData && newData.length > 0) {
                        updatePenetrationChart(newData);
                    }
                },
                error: function (xhr, status, error) {
                    console.error('Error fetching penetration data batch:', error);
                    alert('Error fetching data: ' + xhr.responseText);
                }
            });
        }

        $(document).ready(function () {
            initializePenetrationChart();
            fetchPenetrationDataBatch();
            setInterval(fetchPenetrationDataBatch, 5000);
        });
    </script>

    <!-- Space between charts -->
    <br>
    <br>

    <!-- Hydrophone Audio Level Chart Section -->
    <h2 class="chart-title">Hydrophone Audio Level Chart</h2>
    <div class="chart-container" id="hydrophoneChartContainer">
        <canvas id="hydrophoneChart"></canvas>
    </div>

    <script>
        let lastHydrophoneTimestamp = null;

        function initializeHydrophoneChart() {
            const ctx2 = document.getElementById('hydrophoneChart').getContext('2d');
            const gradient = ctx2.createLinearGradient(0, 0, 0, 400);
            gradient.addColorStop(0, 'rgba(75, 192, 192, 0.05)');
            gradient.addColorStop(1, 'rgba(75, 192, 192, 0.15)');

            window.hydrophoneChart = new Chart(ctx2, {
                type: 'line',
                data: {
                    datasets: [{
                        label: 'Volume (dB)',
                        data: [],
                        borderColor: 'rgba(75, 192, 192, 1)',
                        backgroundColor: gradient,
                        fill: true,
                        tension: 0.4,
                        pointRadius: 2,
                        borderWidth: 2
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time',
                            time: {
                                unit: 'second',
                                tooltipFormat: 'yyyy-MM-dd HH:mm:ss',
                                displayFormats: {
                                    second: 'HH:mm:ss',
                                    minute: 'HH:mm',
                                    hour: 'HH:mm',
                                    day: 'yyyy-MM-dd',
                                },
                            },
                            title: { display: true, text: 'Time', color: '#ffffff' },
                            ticks: { color: '#ffffff' },
                            grid: { color: 'rgba(255, 255, 255, 0.1)' }
                        },
                        y: {
                            beginAtZero: true,
                            title: { display: true, text: 'Volume (dB)', color: '#ffffff' },
                            ticks: { color: '#ffffff' },
                            grid: { color: 'rgba(255, 255, 255, 0.1)' }
                        }
                    },
                    plugins: {
                        legend: {
                            display: true,
                            labels: { color: '#ffffff' }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(0, 0, 0, 0.7)',
                            titleColor: '#ffffff',
                            bodyColor: '#ffffff',
                            borderColor: '#ffffff',
                            borderWidth: 1,
                            callbacks: {
                                title: tooltipItems => tooltipItems[0].raw.x.replace('T', ' ').replace('Z', ''),
                                label: tooltipItem => `Volume: ${tooltipItem.parsed.y} dB, Sample ID: ${tooltipItem.raw.sId}`
                            }
                        },
                        zoom: {
                            pan: { enabled: true, mode: 'xy' },
                            zoom: { wheel: { enabled: true }, pinch: { enabled: true }, mode: 'xy' }
                        }
                    }
                }
            });
        }

        function updateHydrophoneChart(newData) {
            const chart = window.hydrophoneChart;
            if (chart && chart.data.datasets[0]) {
                const formattedData = newData.map(item => ({ x: item.timeStamp, y: item.volumeDb, sId: item.sampId }));
                chart.data.datasets[0].data.push(...formattedData);
                chart.update();
                lastHydrophoneTimestamp = formattedData[formattedData.length - 1].x;
            }
        }

        function fetchHydrophoneDataBatch() {
            const data = lastHydrophoneTimestamp ? { lastTimestamp: lastHydrophoneTimestamp } : {};

            $.ajax({
                url: '/PenetrationReadings/GetHydrophoneAudioLevelsBatch',
                method: 'GET',
                data: data,
                success: function (newData) {
                    if (newData && newData.length > 0) {
                        updateHydrophoneChart(newData);
                    }
                },
                error: function (xhr, status, error) {
                    console.error('Error fetching hydrophone data batch:', error);
                    alert('Error fetching data: ' + xhr.responseText);
                }
            });
        }

        $(document).ready(function () {
            initializeHydrophoneChart();
            fetchHydrophoneDataBatch();
            setInterval(fetchHydrophoneDataBatch, 5000);
        });
    </script>
</body>
</html>

What I’ve Tried:

Plugin Registration:
Ensured that the chartjs-plugin-zoom is correctly registered with Chart.js using:





if (typeof Chart !== 'undefined' && typeof ChartZoom !== 'undefined') {
    Chart.register(ChartZoom);
} else {
    console.error('Chart.js or ChartZoom plugin is not loaded.');
}

Adjusting Threshold:
Reduced the threshold value from 10 to 5 in the pan configuration to make panning more responsive:





pan: { enabled: true, mode: 'xy', threshold: 5 },

Make path points smooth in svg

In my svg, the path produces points at some places. But it looks like pixelated. I need to make curves smooth. How can achieve this in js.

I found text svgo library which reduces no. of points in the path. But I am not sure how to make curves smooth.

import { optimize } from 'svgo';


const optimizeSvg = (svgString) => {
    return  optimize(svgString, {
        multipass: true,
    }).data;
}

Form using more than one service – Ofbiz 18.12

I have a form to create and update a client entity, the field for the name is supposed to search in the entity, make autocompletion and if it finds a match, it is supposed to place the results to the other fields in the form for the client.

I defined a service using java code to create and update the client, this one works fine, to generate this other service I was trying to use javascript and groovy, but I don’t fully understand how to do this other service. I don’t understand well how to handle more than one service for the same form. The way I tried is, my form is calling the service to create and update the client, and my field is calling the other service.

Also, I have downloaded JQuery to use my .js script, but I can’t find the right version, I keep getting an error. I have tried with the latest one (1.14.1,), and others (1.13.1, 1.12.1, 1.7, …)

javascript Error

The form uses the createClient service to update and add a client (this one works) :

<form name="clientForm" default-entity-name="Client" target="createClient">
        <field name="editModeClient" title=" ">
            <radio>
                <option key="create" description="ADD"/>
                <option key="update" description="UPDATE"/>
            </radio>
        </field>
        <field name="nameClient" title="VALIDATE CLIENT" entity-name="Client" service-name="getClientDetails">
            <text size="50"/>
        </field>
        <field name="prefixClient" title="PREFIX">
            <text read-only="true" default-value="TEST" size="3"/>
        </field>
        <field name="typeRClient" title="TYPE R" >
            <drop-down allow-empty="false">
                <entity-options
                        entity-name="TypeRS"
                        key-field-name="typeRSId"
                        description="[${typeRSId} ${typeRSDesc}]">
                </entity-options>
            </drop-down>
        </field>
        <field name="rSClient" title="RS>
            <text client-autocomplete-field="false" size="50"/>
        </field>
        <field name="nameComClient" title="NCOM">
            <text client-autocomplete-field="false" size="50"/>
        </field>
        <field name="rfClient" title="RF">
            <text client-autocomplete-field="false" size="10"/>
        </field>
        <field name="phone" title="PHONE">
            <text client-autocomplete-field="false" size="15"/>
        </field>
        <field name="email" title="EMAIL">
            <text client-autocomplete-field="false" size="25"/>
        </field>
        <field name="cClient" title="C">
            <text client-autocomplete-field="false" size="40"/>
        </field>
        <field name="Save" title="SAVE">
            <!--<submit button-type="submit"/>-->
            <submit button-type="button"/>
        </field>
    </form>

The field nameClient uses the service getClientDetails to handle the search for the field, this is the one I’m having problems:

<service name="getClientDetails" engine="groovy"
             location="component://mycomponent/groovyScripts/ClientServices.groovy"
             invoke="getClientDetails" auth="true">
        <description>Get client details by name</description>
        <attribute name="searchTerm" type="String" mode="IN" optional="false"/>
        <attribute name="clientList" type="List" mode="OUT" optional="false"/>
    </service>

The request :

<request-map uri="getClientDetails">
        <security https="true" auth="true"/>
        <event type="service" invoke="getClientDetails"/>
        <response name="success" type="request" value="json"/>
        <response name="error" type="request" value="json"/>
    </request-map>

The groovy code:

import org.apache.ofbiz.entity.GenericValue
import org.apache.ofbiz.entity.util.EntityQuery
import org.apache.ofbiz.entity.util.EntityOperator

def getClientDetails(Map context) {
    Map result = [:]
    String searchTerm = context.searchTerm

    try {
        List<GenericValue> clientList = EntityQuery.use(delegator)
                .from("Client")
                .where(EntityCondition.makeCondition("nameClient", EntityOperator.LIKE, "%" + searchTerm + "%"))
                .queryList()

        result.clientList = clientList
    } catch (Exception e) {
        return error("Error getting client details: ${e.message}")
    }

    return result
}

The javascript code:

$(document).ready(function() {
    $("#nameClient").on("input", function() {
        var searchTerm = $(this).val();
        $.ajax({
            url: "getClientDetails",
            data: { searchTerm: searchTerm },
            type: "POST",
            success: function(response) {
                // ... (rest of your AJAX handling code) ...
            },
            // ...
        });
    });
})

So, can anyone help me to understand how to perform more than one service in a form?, is it better to try a .ftl file for the form and handle everything there?, and how to get the functionality described before?. Apologies, a lot of questions but I have not found the answers,Thanks!

I need to build an extension that summarises all the product reviews of a product, But reviews are present on different pages and need login to scrape

I cannot scrape reviews without login, so My extension needs to have user’s headers and cookies to summarise reviews using llm, but I am unable to get those, I cant seem to get any way to get this task done, I have little clue about web-request-blocking and it needing force-install-extensions, but still I am clueless, If Someone can help do!

I tried declarativeNetRequest, ended up realising it does not give headers or cookies,
I tried webrequest api, but it didnt give cookies and headers it returned were only possible when page refreshed infinite times,
I tried caching the headers but failed,
I tried to get cookies by document.cookies() but it gave partial cookies and I could do nothing with those cookies.
Please, Suggest me a way to get this task done.

Here, is the chrome debugger code used by me, it did not work for me as it fails to extract full useful headers and cookies for me:

chrome.action.onClicked.addListener(function (tab) {
  console.log('button Clicked...')
    if (tab.url.startsWith('https://www.amazon.in/')) {
      chrome.debugger.attach({ tabId: tab.id }, '1.2', function () {
        chrome.debugger.sendCommand(
          { tabId: tab.id },
          'Network.enable',
          {},
          function () {
            if (chrome.runtime.lastError) {
              console.error(chrome.runtime.lastError);
            }
          }
        );
      });
    } else {
      console.log('Debugger can only be attached to HTTP/HTTPS pages.');
    }
  });
  
  chrome.debugger.onEvent.addListener(function (source, method, params) {
    console.log('lsitender event addlistentetr')
    if (method === 'Network.responseReceived') {
      console.log('Response received:', params.response);
      console.log('Headers could be..', params.response.headers);
      //onsole.log(params.response.headers)
      // Perform your desired action with the response data
    }
    if (method === 'Network.requestWillBeSent') {
      // Access request headers
      console.log('params.request');
      console.log(params.request);
      const requestHeaders = params.request.headers;
      console.log('Request URL:', params.request.url);
      console.log('Request Headers:', requestHeaders);
    }
  }); 

Here is the cookies extraction code used, but cookies are partial cookies and using them gave no response back to me:

async function getCookie(tabId) {
    const [{result}] = await chrome.scripting.executeScript({
      func: () => document.cookie,
      args: [],
      target: {
        tabId: tabId ??
          (await chrome.tabs.query({active: true, currentWindow: true}))[0].id
      },
      world: "MAIN",
    });
    return result;
  }
  
  (async () => {
    const cookies = await getCookie();
    console.log("trying to print cookies in the console.")
    // visible in the extension's devtools console
    console.log("popup:", cookies);
  
    // visible in the extension's DOM
    document.querySelector("div").textContent = cookies;
  })();
  

Here, is the headers extraction code, I used that caused infinite reloads, but when I tried to resolve it, it failed to fetch headers and store them in cache(cache storage code is other code, not this one):

function getCurrentTabHeaders() {
    return new Promise((resolve, reject) => {
      // Get the active tab
      chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        if (tabs.length === 0) {
          reject('No active tab found');
          return;
        }
  
        const tab = tabs[0];
        const tabId = tab.id;
  
        function listener(details) {
          if (details.tabId === tabId && details.type === 'main_frame') {
            // Remove the listener after getting the headers
            chrome.webRequest.onHeadersReceived.removeListener(listener);
  
            // Resolve with the response headers
            resolve(details.responseHeaders);
          }
        }
  
        // Add the listener
        chrome.webRequest.onHeadersReceived.addListener(
          listener,
          { urls: ["<all_urls>"], types: ["main_frame"], tabId: tabId },
          ["responseHeaders"]
        );
  
        // Reload the tab to trigger the request and capture headers
        chrome.tabs.reload(tabId);
      });
    });
  }
  

  
  // Message listener to handle requests from popup or content scripts
  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'getCurrentTabHeaders') {
      getCurrentTabHeaders()
        .then((headers) => {
          sendResponse({ headers });
        })
        .catch((error) => {
          console.error('Error getting headers:', error);
          sendResponse({ error: error });
        });
      // Return true to indicate we will respond asynchronously
      return true;
    }
  });

Tried this to counter infinite reloads but failed too:

  if (!hasReloaded) {
                chrome.tabs.reload(tabId, () => {
                    hasReloaded = true; // Set the flag to true after reloading
                });
            } else {
                reject('Tab has already been reloaded once');
            }

Tried this to completely stop infinite reloads and just store headers in cache whenever request headers were recieved:

Then I tried to add listener to chrome tab by default that would read the requests and store them in cache, and extraction would simply be from cache storage, that failed too. (I deleted that code, don’t have it handy).

-I just need to get reviews of that product for which I need scraping of 10 pages using logged in account, so i was trying to logged in users’ cookies and headers to send to API to scrape and then summarise by llm, but I dont seem to have a way to do it.

Image cannot be edited after adding to TUI Image Editor

The image cannot be edited after being added to TUI Image Editor. The image is active and moving. There are checkpoints. But they are not active. I forcibly turned them on but to no avail. When several images are added to the canvas, they can be selected with the mouse and after that the points begin to work

 fabric.Image.fromURL(imagepath, (img) => {
        // Настраиваем параметры изображения, например, позицию и масштаб
        img.set({
          left: 100, // X-позиция
          top: 100, // Y-позиция
          scaleX: 1, // Масштаб по оси X
          scaleY: 1, // Масштаб по оси Y
          selectable: true // Делаем объект редактируемым и перемещаемым
        })
        console.log(img)
        // Добавляем изображение на холст
        canvas.add(img)

        // Делаем объект активным для редактирования
        canvas.setActiveObject(img)

        // Обновляем холст, чтобы отображались изменения
        canvas.renderAll()
      })

I tried adding an image both through addImageObject in TUI and directly in fabric.js fabric.Image.fromURL. After loading JSON the problem remains

How to resolve the warning: reexported as ‘imultiselectref’) was not found react dropdown?

I have a react-native expo app. And I installed the newest version of react-native-element-dropdown:

"react-native-element-dropdown": "^2.12.2",

But when I try to build the app: I get this two warnings:

WARNING in ./node_modules/react-native-element-dropdown/lib/module/index.js:6
export 'IDropdownRef' (reexported as 'IDropdownRef') was not found in './components/Dropdown/model' (module has no exports)
  4 | import { IDropdownRef } from "./components/Dropdown/model";
  5 | import { IMultiSelectRef } from "./components/MultiSelect/model";
> 6 | export { Dropdown, MultiSelect, SelectCountry, IDropdownRef, IMultiSelectRef };

WARNING in ./node_modules/react-native-element-dropdown/lib/module/index.js:6
export 'IMultiSelectRef' (reexported as 'IMultiSelectRef') was not found in './components/MultiSelect/model' (module has no exports)
  4 | import { IDropdownRef } from "./components/Dropdown/model";
  5 | import { IMultiSelectRef } from "./components/MultiSelect/model";
> 6 | export { Dropdown, MultiSelect, SelectCountry, IDropdownRef, IMultiSelectRef };

So I checked inside the file: ./node_modules/react-native-element-dropdown/lib/module/index.js:6

import Dropdown from './components/Dropdown';
import MultiSelect from './components/MultiSelect';
import SelectCountry from './components/SelectCountry';
import { IDropdownRef } from './components/Dropdown/model';
import { IMultiSelectRef } from './components/MultiSelect/model';
export { Dropdown, MultiSelect, SelectCountry, IDropdownRef, IMultiSelectRef };

And I checked the file:

was not found in './components/Dropdown/model' (module has no exports):

This file has just one line:

export {};

And this is the component:

import {
  AccountBackground,
  AccountContainer,
  AccountCover,
  AuthButton,
  AuthInput,
  ErrorContainer,
  Title,
} from "../../account/components/account.styles";
import React, { useContext, useEffect, useState } from "react";

import { AccountRequest } from "../../../services/authentication/authentication.service";
import { ActivityIndicator } from "react-native-paper";
import AntDesign from "@expo/vector-icons/AntDesign";
import { AuthContext } from "../../../services/authentication/authentication.context";
import { CategoryContext } from "../../../services/category/category.context";
import { Dropdown } from "react-native-element-dropdown";
import { Spacer } from "../../../components/spacer/spacer.component";
import { StyleSheet } from "react-native";
import { Text } from "../../../components/typography/text.component";
import { View } from "react-native";
import { createStackNavigator } from "@react-navigation/stack";

const data = [
  { label: "Item 1", value: "1" },
  { label: "Item 2", value: "2" },
  { label: "Item 3", value: "3" },
  { label: "Item 4", value: "4" },
  { label: "Item 5", value: "5" },
  { label: "Item 6", value: "6" },
  { label: "Item 7", value: "7" },
  { label: "Item 8", value: "8" },
];

export const SetScreen = ({ navigation }) => {
  const OPTIONS = [
    { label: "Male", value: "male" },
    { label: "Female", value: "female" },
    { label: "Other", value: "other" },
  ];

  const [gender, setGender] = useState("");
  const [value, setValue] = useState(null);
    const [isFocus, setIsFocus] = useState(false);
  const Stack = createStackNavigator();
 
  const {
    isLoading,
    onLogout,
    error,
    handleValidPassword,
    UpdateUserProfileRequest,
  } = useContext(AuthContext);

  const {
    categoryList, // Get the categories from the context
    loading: categoryLoading, // Track loading state for categories
    error: categoryError, // Handle any error from fetching categories
    sortBy,
    order,
    toggleSortOrder, // Function to toggle sorting order
    changeSortBy,
  } = useContext(CategoryContext);

  useEffect(() => {
    AccountRequest().then((data) => {
     
    });
  }, []);

  const handleSortByName = () => {
    changeSortBy("name");
  };

  const renderLabel = () => {
    if (value || isFocus) {
      return (
        <Text style={[styles.label, isFocus && { color: "blue" }]}>
          Dropdown label
        </Text>
      );
    }
    return null;
  };

  return (
    <>
      <AccountBackground>
        <AccountCover />
        <Title>
          <b> Instellingen</b>
        </Title>
      tainer>

        <Title>
          <b> Sorteren</b>
        </Title>
       
          <Spacer size="large">
          <View style={styles.container}>
        
        <Dropdown
          style={[styles.dropdown, isFocus && { borderColor: "blue" }]}
          placeholderStyle={styles.placeholderStyle}
          selectedTextStyle={styles.selectedTextStyle}
          inputSearchStyle={styles.inputSearchStyle}
          iconStyle={styles.iconStyle}
          data={data}
          search
          maxHeight={300}
          labelField="label"
          valueField="value"
          placeholder={!isFocus ? "Select item" : "..."}
          searchPlaceholder="Search..."
          value={value}
         
          onChange={item => {
            setValue(item.value);
            setIsFocus(false);
          }}
          renderLeftIcon={() => (
            <AntDesign
              style={styles.icon}
              color={isFocus ? "blue" : "black"}
              name="Safety"
              size={20}
            />
          )}
        />
      </View>
          </Spacer>
        

        <Spacer size="large">
          <AuthButton mode="contained" onPress={() => navigation.goBack()}>
            Terug
          </AuthButton>
        </Spacer>
      </AccountBackground>
    </>
  );
};
const styles = StyleSheet.create({
  container: {
    backgroundColor: "white",
    padding: 16,
  },
  dropdown: {
    height: 50,
    borderColor: "gray",
    borderWidth: 0.5,
    borderRadius: 8,
    paddingHorizontal: 8,
  },
  icon: {
    marginRight: 5,
  },
  label: {
    position: "absolute",
    backgroundColor: "white",
    left: 22,
    top: 8,
    zIndex: 999,
    paddingHorizontal: 8,
    fontSize: 14,
  },
  placeholderStyle: {
    fontSize: 16,
  },
  selectedTextStyle: {
    fontSize: 16,
  },
  iconStyle: {
    width: 20,
    height: 20,
  },
  inputSearchStyle: {
    height: 40,
    fontSize: 16,
  },
});

And I googled this error and I found this thread from 2023:

https://github.com/hoaphantn7604/react-native-element-dropdown/issues/174

I also deleted and re-installed

node_modules

Question: How te resolve the warnings?

disable-devtool package not updating ref values after route navigation

I am using Vue 3 in my application and have implemented the disable-devtool package to detect when the browser’s developer tools are opened or closed. Everything works fine when I first load the component. However, when the user is redirected away and then navigates back to this component, ref values such as isDevToolsOpen and counter don’t update anymore, even though no errors are thrown. It’s as if Vue stops tracking the changes in these ref variables after the route change.

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import DisableDevtool from 'disable-devtool'
import router from '@/router'
import { useCreateLog } from '@/composables/controls/useCreateLog'

const isDevToolsOpen = ref(false)
let devToolsTimeout = null
let isLogged = false
const counter = ref(0)

const { createLog } = useCreateLog()

DisableDevtool({
  ondevtoolopen: () => {
    isDevToolsOpen.value = true
    counter.value++
    if (!isLogged) {
      createLog('Developer tools opened')
      isLogged = true
    }
    if (!devToolsTimeout) {
      devToolsTimeout = setTimeout(() => {
        router.push({ name: 'ProductList' })
      }, 5000)
    }
  }
})

onMounted(() => {
  DisableDevtool.isSuspend = false
})

onUnmounted(() => {
  DisableDevtool.isSuspend = true
})
</script>

No ‘Access-Control-Allow-Origin’ header is present on the requested resource – 502 proxy error

I am facing issues with cors issue in localhost. API call from reactjs is working prod environment but somehow its broken in localhost. Even curl command is working from terminal by using proxy

here is my api call code

    const chatbotAPI = process.env.NODE_ENV === 'production'
      ? `${constructPath('/api/chat')}`
      : `${process.env.REACT_APP_CHATBOT_API}/chat`;

    try {
      const response = await fetch(`${chatbotAPI}?shop_url=${shopUrl}`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${process.env.REACT_APP_CHATBOT_API_ACCESS_CODE}`,
        },
        body: JSON.stringify({input_message: message}),
      });

      console.log("response", response)

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      const data = await response.json();

      return data.output || "No response received from chatbot.";
    } catch (error) {
      console.error("Error fetching chatbot response:", error);

      return "Error: Could not reach chatbot.";
    }

here is server.js code

// Proxy FastAPI chatbot requests
app.post('/api/chat', function(req, res) {

  console.log("req.query.shop_url", req.query.shop_url)
  console.log("chatApiUrl", chatApiUrl)

  req.pipe(request(chatApiUrl + `/chat?shop_url=${req.query.shop_url}`)).pipe(res);
});

error

from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

POST http://xxxx:xxxx/chat?shop_url=xxxx 
 net::ERR_FAILED 502 (Proxy Error)