Setting Properties for the Mendix API Client

0
Hello, everyone! I would like to ask a question that has been hindering my development. I am creating a widget from scratch, building a completely customizable chart. After completing 80% of the development (React, native Typescript) I came across the integration via Mendix client API. I would like help to understand, in the chart, I pass variables such as startDate and endDate, which can be updated, when updated, their new values ​​are received by updateStartDate and updateEndDate, which should be the value that Mendix would receive via API to change in the database by Microflow. Here is the code to update the variable const onDateChangedEvent = useCallback(async (task: Task): Promise<void> => {console.debug(`Firing onDateChangedEvent for task ${task.id}. Date range changed to ${task.start.toISOString()} - ${task.end.toISOString()}`);console.log("onDateChangedEvent called with taskId:", task.id, "and dates:", task.start, task.end); // Access the *latest* values from the ref:const currentData = latestData.current; if (currentData.onDateChanged && currentData.updatedStartDate && currentData.updatedEndDate) {try {if (currentData.updatedStartDate && typeof currentData.updatedStartDate === 'object' && 'setValue' in currentData.updatedStartDate) {currentData.updatedStartDate.setValue(task.start);} else {console.warn("updatedStartDate is not a valid object with a setValue method.");} if (currentData.updatedEndDate && typeof currentData.updatedEndDate === 'object' && 'setValue' in currentData.updatedEndDate) {currentData.updatedEndDate.setValue(task.end);} else {console.warn("updatedEndDate is not a valid object with a setValue method.");} // Execute Mendix Action await executeAction(currentData.onDateChanged); } catch (error) {console.error("Error during onDateChangedEvent:", error);}} else {console.warn("onDateChanged action or updatedStartDate/updatedEndDate is not properly defined.");}}, [executeAction]);     I thought that setValue would already be able to update the attribute value in the domain model through microflow, but it is not being received when debugged. I believe that my problem may be the properties that I am passing   Here are the properties   <propertyGroup caption="Events"> <propertyGroup caption="Shared"><property key="eventTaskIds" type="attribute" required="false"><caption>Event Task Ids</caption><description>Comma-separated list of Task IDs that triggered the event.</description><attributeTypes><attributeType name="String" /></attributeTypes></property></propertyGroup><propertyGroup caption="Date Update"><property key="updatedStartDate" type="attribute" required="false"><caption>Updated Start Date</caption><description>The attribute to update with the new start date.</description><attributeTypes><attributeType name="DateTime" /></attributeTypes></property><property key="updatedEndDate" type="attribute" required="false"><caption>Updated End Date</caption><description>The attribute to update with the new end date.</description><attributeTypes><attributeType name="DateTime" /></attributeTypes></property> <property key="onDateChanged" type="action" required="false"><caption>On Date Changed</caption><description>What should happen the user updates the dates on a task. The updatedStartDate and updatedEndDate attributes will be set *before* this action is executed. Be sure to refresh in client so the widget UI updates correctly.</description></property>   Could you help me understand what I'm doing wrong? Remembering that the updateDate property is being set as EditableValue<Date>;
asked
1 answers
0

Hi Isabella,

 

While it is hard to rule out modeling issues in the app, I did notice that your event handler is wrapped in a `useCallback()` react hook. This prevents the function from being redefined each render, until it detects a change in the dependencies which are given in the second argument. Can you try adding `currentData` to the array? It may be that you don't see the updated value because react is using a definition of the function of when it was last defined.

 

In this example the ButtonWithoutDependencies will always set the counter to the same value and log the same timestamp it received at its first render. ButtonWithDependencies however does behave as expected: Incrementing the current counter value by 1 and logging the latest timestamp.

export function App(props) {
  const [counter, setCounter] = useState(0);
  const timestamp = Date.now();

  return (
    <div className='App'>
      <h1>{counter}</h1>
      <h5>Clicks given</h5>
      <ButtonWithDependencies
        counter={counter}
        setCounter={setCounter}
        timestamp={timestamp}
      />
      <ButtonWithoutDependencies
        counter={counter}
        setCounter={setCounter}
        timestamp={timestamp}
      />
    </div>
  );
}

const ButtonWithDependencies = ({ timestamp, counter, setCounter }) => {
  const incrementCounter = useCallback(() => {
    console.log('With Dependencies', timestamp);
    setCounter(counter + 1);
  }, [timestamp, counter]);

  return <button onClick={incrementCounter}>I give a click</button>;
};

const ButtonWithoutDependencies = ({ timestamp, counter, setCounter }) => {
  const incrementCounter = useCallback(() => {
    console.log('Without Dependencies', timestamp);
    setCounter(counter + 1);
  }, []);

  return <button onClick={incrementCounter}>I don't give a click</button>;
};

 

If you find yourself running into this issue often, there is an eslint rule that will warn you when you access variables outside the scope of the useCallback that are not listed as dependencies.

 

On a different note, you can wrap code in code snippets to make them more readable. It is the last button on the toolbar (next to the image button).

 

I hope this helps,

Arjo

answered