Symfony API Platform subresource POST/PUT operations are not working as expected

I am unable to get subresource write operations (POST, PUT) working in API Platform 4.1.

I will walk you through the issues step-by-step. However, to summarize upfront, below are the expected behaviors as well as the actual results:

POST

  • Expected: new subresources can be created ad infinitum.
  • Actual: only one subresource can be created; additional attempts simply overwrite the original subresource.

PUT

  • Expected: subresources can be created at a specific IRI ad infinitum.
  • Actual: subresources can only be created at a specific IRI once.

Minimal Example

Assume we have two entities: User and UserEmail in a one-to-many relationship, like so:

User.php

#[Groups(['user:read'])]
#[ORMOneToMany(targetEntity: UserEmail::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
private Collection $emails;

UserEmail.php

#[ApiResource(
    uriTemplate: '/users/{userUuid}/emails/{uuid}',
    uriVariables: [
        'userUuid' => new Link(fromClass: User::class, fromProperty: 'emails'),
        'uuid' => new Link(fromClass: UserEmail::class),
    ],
    operations: [
        new Get(
            normalizationContext: ['groups' => ['userEmail:read']],
            security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
        ),
        new Put(
            normalizationContext: ['groups' => ['userEmail:read']],
            security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
            processor: UserEmailProcessor::class,
            allowCreate: true,
        ),
        new Delete(
            security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
        ),
    ]
)]
#[ApiResource(
    uriTemplate: '/users/{userUuid}/emails',
    uriVariables: [
        'userUuid' => new Link(fromClass: User::class, fromProperty: 'emails'),
    ],
    extraProperties: [
        'standard_put' => true,
    ],
    operations: [
        new GetCollection(
            normalizationContext: ['groups' => ['userEmail:read']],
            security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
        ),
        new Post(
            normalizationContext: ['groups' => ['userEmail:read']],
            security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
            processor: UserEmailProcessor::class,
        ),
    ]
)]
// @formatter:on

#[ORMEntity(repositoryClass: UserEmailRepository::class)]
#[ORMTable(name: 'user_email')]
#[UniqueEntity(fields: ['emailNumber'], message: 'This email number is already in use.')]
final class UserEmail
{
    #[ApiProperty(identifier: false)]
    #[ORMId]
    #[ORMGeneratedValue(strategy: 'SEQUENCE')]
    #[ORMColumn(type: 'integer')]
    private int $id;
    
    #[ApiProperty(identifier: true)]
    #[AssertUuid(versions: [4], groups: ['userEmail:read', 'userEmail:write'])]
    #[Groups(['userEmail:read', 'user:read'])]
    #[ORMColumn(type: 'string', length: 36, unique: true)]
    private string $uuid;

    #[ApiProperty]
    #[AssertNotBlank]
    #[AssertEmail]
    #[Groups(['userEmail:read', 'userEmail:write', 'user:read'])]
    #[ORMColumn(type: 'string', length: 20, unique: true)]
    private string $email;

    #[ApiProperty]
    #[Groups(['userEmail:read'])]
    #[ORMManyToOne(targetEntity: User::class, inversedBy: 'emails')]
    #[ORMJoinColumn(nullable: false)]
    private User $user;

    public function __construct(?UuidInterface $uuid = null)
    {
        $this->uuid = $uuid?->toString() ?? Uuid::uuid4()->toString();
    }

    // ...
}

POST

First, let’s discuss POST.

POST /users/00000000-0000-0000-0000-000000000001/emails
{
    "email": "[email protected]"
}
{
  "title": "An error occurred",
  "detail": "An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "user_id" of relation "user_email" violates not-null constraintnDETAIL:  Failing row contains (1, 6b63235a-8c25-468c-881f-b4ce80618c56, 2222222, null).",
  "status": 500,
  "type": "/errors/500"
}

UserEmail::$user is not being set from the URI as expected.

We can use a state processor to set the UserEmail::$user field manually. We must attach this state processor to the POST operation.

Question #1

Is this something we can solve without a state processor?

UserEmail.php

#[ApiResource(
    operations: new Post(
        processor: UserEmailProcessor::class,
        // ...
    )
    // ...
)]

UserEmailProcessor.php

final readonly class UserEmailProcessor implements ProcessorInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private UserRepository $userRepository,
        private RequestStack $requestStack,
    ) {
    }

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
    {
        if (!$data instanceof UserEmail) {
            return $data;
        }

        $userUuid = $uriVariables['userUuid'] ?? null;
        
        $user = $this->userRepository->findOneBy(['uuid' => $userUuid]);
        if (!$user) {
            throw new NotFoundHttpException();
        }

        $data->setUser($user);

        $this->entityManager->persist($data);
        $this->entityManager->flush();

        return $data;
    }
}

Now let’s try the same request as before:

POST /users/00000000-0000-0000-0000-000000000001/emails
{
    "email": "[email protected]"
}

201 Created

{
  "uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
  "email": "[email protected]",
  "user": "/users/00000000-0000-0000-0000-000000000001"
}

It worked! Let’s test it one more time with a different email:

POST /users/00000000-0000-0000-0000-000000000001/emails
{
    "email": "[email protected]"
}

201 Created

{
  "uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
  "email": "[email protected]",
  "user": "/users/00000000-0000-0000-0000-000000000001"
}

WRONG. We received a 201 Created response code and the email is correct. However, the UUID is the exact same. The previous resource was updated or recreated. Note that if we try this with a different user’s UUID, it will also work the first time, but follow-up attempts will show the same problem.

Question #2

What is causing this, and how do we resolve it?

PUT

In the past, API Platform’s PUT operation was notorious for having incorrect behavior, functioning similarly to PATCH. However, with API Platform 4.0, these issues are purportedly resolved.

Let’s try a PUT request.

PUT /users/00000000-0000-0000-0000-000000000001/emails/cccccccc-cccc-cccc-cccc-cccccccccccc
{
    "email": "[email protected]"
}
{
  "uuid": "b797c3fd-2d31-4452-8aaa-b87a0644cc28",
  "email": "[email protected]",
  "user": "/users/00000000-0000-0000-0000-000000000001"
}

The email was created. However, the UUID is incorrect (and by extension, so is the IRI).

Let’s try it again.

PUT /users/00000000-0000-0000-0000-000000000001/emails/dddddddd-dddd-dddd-dddd-dddddddddddd
{
    "email": "[email protected]"
}
{
  "uuid": "92bde1cf-d103-406c-895d-9e96393089f6",
  "email": "[email protected]",
  "user": "/users/00000000-0000-0000-0000-000000000001"
}

The same issue occurred. However, the UUID is different! That means PUT is behaving how we expected POST to originally.

We can use a state processor to set the correct UUID. Since we already have a state processor from before, let’s update it as follows:

Question #3

Again—is this something we can solve without a state processor?

UserEmail.php

#[ApiResource(
    operations: new Put(
        processor: UserEmailProcessor::class,
        // ...
    )
    // ...
)]

UserEmailProcessor.php

// For PUT operations, ensure the UUID from the URI is used
if ($operation instanceof Put) {
    $emailUuid = $uriVariables['uuid'] ?? null;
    if ($emailUuid && $data->getUuid() !== $emailUuid) {
        $data->setUuid($emailUuid);
    }
}

Here, we are manually setting the UUID in the state processor. I don’t like having setters for my identifiers, but we’ll ignore that for now. Let’s try a request:

PUT /users/00000000-0000-0000-0000-000000000001/emails/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee
{
    "email": "[email protected]"
}
{
  "uuid": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee",
  "email": "[email protected]",
  "user": "/users/00000000-0000-0000-0000-000000000001"
}

It worked! This is exactly what we expected to see. Now let’s try replacing that same resource with a different email:

PUT /users/00000000-0000-0000-0000-000000000001/emails/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee
{
    "email": "[email protected]"
}
{
  "title": "An error occurred",
  "detail": "An exception occurred while executing a query: SQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint "uniq_a68d6c85d17f50a6"nDETAIL:  Key (uuid)=(eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee) already exists.",
  "status": 500,
  "type": "/errors/500"
}

Yet another problem. PUT is neither updating the existing database rows, nor deleting and repopulating them. Instead, it is simply trying to create a new row with the specified UUID.

Question #4

Yet again—what is causing this, and how do we resolve it?


Thank you for your help!

How use “overrides” property in tseslint config?

I use typescript-eslint in my project. It has no property “overrides” as .eslintrc.js.
How i use “overrides” in my tseslint.config ?

export default tseslint.config(
    { ignores: ['dist'] },
    {
        extends: [js.configs.recommended, ...tseslint.configs.recommended, importPlugin.flatConfigs.recommended, i18next.configs['flat/recommended']],
        files: ['**/*.{ts,tsx}'],
        languageOptions: {
            ecmaVersion: 2020,
            globals: globals.browser,
        },
        plugins: {
            'react-hooks': reactHooks,
            'react-refresh': reactRefresh,
            'eslint-plugin-react': eslintPluginReact,
            'eslint-plugin-i18next': i18next
        },
        rules: {
            ...reactHooks.configs.recommended.rules,
            'i18next/no-literal-string': [
                "error",
                {
                    framework: 'react',
                    mode: "jsx-only",
                    'jsx-attributes': {
                        include: [],
                        exclude: ['*'],
                    },
                    callees: {
                        exclude: [
                            'content: <div>'
                        ],
                    },
                },
            ],
        },
        "settings": {
            "import/resolver": {
                "typescript": true,
                "node": true,
            },
        },
        "overrides": [
            {
                "files": ['**/*.stories.{ts,tsx}'],
                "rules": {
                    'i18next/no-literal-string': "off"
                }
            }
        ],
    }
)

i want override ‘i18next/no-literal-string’ rule for my storybook files.

How come this site can autoplay MP3 in any browsers?

This website really can autoplay mp3 automatically in firefox and other browsers. Not like others code, which failed in firefox.

The mp3 is not autoplayed at the landing page. But as I click the button to the main page, the sound play automatically at the main page (one page website).

https://share.linkundangan.com/inv-preview/wedding-premium050?to=Tamu+Undangan

I’ve tried to read the code, but I,m not a coder, I failed. Would anybody give me the audio code of this site, please.

Best Regard
Hendrik Virtuoso

Would anybody give me the audio code of this site, please.

how do I use javascript to display the files in the “posts” folder on my homepage?

I’ve researched a lot but have not yet found an answer to that. I want to create a simple blog (using sites like neocities) and wanted to test a script that rendered html files in the post containers on the home page. and that every time you had a new file, it would appear as a new container on top of the old container automatically. Is it possible to do?

i tried:

  • fetch
  • function
  • addContent()
  • appendChild()
  • GET request
  • getElementById

How to Fix Vertical Slider Direction and Hover Pause in Bricks Theme

I configured the Splide.js slider for vertical scrolling in a top-to-bottom direction. However, it is currently behaving in the opposite way, scrolling from bottom to top. Could you clarify why this is happening?

In the WordPress Bricks theme, I am using the Nestable Slider. It supports vertical sliding with the direction set to ttb (top-to-bottom).

My requirement is:

The slider should run continuously from top to bottom in an infinite loop with a duration of 40,000ms.

On hover, the slider should pause.

When the hover is removed, it should resume scrolling from top to bottom.

However, with my current JSON configuration:

The slider pauses on hover as expected, but

It scrolls in the wrong direction (bottom to top), not top to bottom.

I need the slider to:

Pause on hover.

Resume automatically after hover.

Always scroll in the top-to-bottom direction with an infinite loop.

How can I fix this issue? Below is the JSON code I am currently using:
json code

{
“type”: “loop”,
“direction”: “ttb”,
“height”: “600px”,
“gap”: “1rem”,
“perPage”: 2,
“perMove”: 1,
“speed”: 40000,
“interval”: 40000,
“autoplay”: false,
“arrows”: false,
“pagination”: false,
“pauseOnHover”: true,
“pauseOnFocus”: false,
“mediaQuery”: “max”,
“breakpoints”: {
“991”: {
“direction”: “ltr”,
“height”: “400px”,
“perPage”: 2,
“perMove”: 1,
“speed”: 40000,
“interval”: 40000,
“autoplay”: false
},
“667”: {
“direction”: “ltr”,
“height”: “350px”,
“perPage”: 2,
“perMove”: 1,
“speed”: 40000,
“interval”: 40000,
“autoplay”: false
},
“480”: {
“direction”: “ltr”,
“height”: “300px”,
“perPage”: 1,
“perMove”: 1,
“speed”: 40000,
“interval”: 40000,
“autoplay”: false
}
}
}

JWT Sign Overloading error with typescript

Getting the following error when i am trying to sign in with my jwt.

No overload matches this call. Overload 1 of 5, '(payload: string | object | Buffer<ArrayBufferLike>, secretOrPrivateKey: null, options?: (SignOptions & { algorithm: "none"; }) | undefined): string', gave the following error. Argument of type 'string' is not assignable to parameter of type 'null'. Overload 2 of 5, '(payload: string | object | Buffer<ArrayBufferLike>, secretOrPrivateKey: Buffer<ArrayBufferLike> | Secret | PrivateKeyInput | JsonWebKeyInput, options?: SignOptions | undefined): string', gave the following error. Type 'string' is not assignable to type 'number | StringValue | undefined'. Overload 3 of 5, '(payload: string | object | Buffer<ArrayBufferLike>, secretOrPrivateKey: Buffer<ArrayBufferLike> | Secret | PrivateKeyInput | JsonWebKeyInput, callback: SignCallback): void', gave the following error. Object literal may only specify known properties, and 'expiresIn' does not exist in type 'SignCallback'.t
I read somewhere this is just typescript being dumb. and to use exclamation that the token is there. TS doesnt need to check, but to no avail.

What causes this error?
How to fix it?
Any other better practices?

And what even is Overloading ??

My config file is the following:

import dotenv from "dotenv";

dotenv.config();

const config: Config = {
  port: Number(process.env.PORT) || 3000,
  nodeEnv: process.env.NODE_ENV || "development",
  jwt: {
    accessSecret: process.env.JWT_ACCESS_SECRET!,
    refreshSecret: process.env.JWT_REFRESH_SECRET!,
    accessExpiry: "45m",
    refreshExpiry: "7d",
  },
};
export default config;

interface Config {
  port: Number;
  nodeEnv: string;
  jwt: jwtConfig;
}
interface jwtConfig {
  accessSecret: string;
  refreshSecret: string;
  accessExpiry: string;
  refreshExpiry: string;
}

and jwt code the following :

import jwt from "jsonwebtoken";
import config from "../config/config";

export const generateAccessToken = (userId: string): string => {
  return jwt.sign(
    {
      id: userId,
    },
    config.jwt.accessSecret,
    {
      expiresIn: config.jwt.accessExpiry,
    }
  );
};

Passing Detailed Event Data (sample, note) from a Strudel.js REPL to a p5.js Canvas

I’m trying to integrate an interactive audiovisual feature into my website, with a Strudel.js REPL and a p5.js canvas working together. The idea is to let visitors live-code music in the REPL and see a reactive visualization of the website’s animations changing.

For example, s("bd*4") might trigger a large pulse using my site’s primary color, while n("0 2 4 5").s("arpy") could generate animated shapes.

A key requirement is that these animations must feel thematic and integrated, not random. They need to match the website’s design to maintain a consistent and polished User Experience (UX). This means I need very fine-grained control to map specific musical events to specific, pre-designed visuals.

This leads to my core question. I’ve been searching online but have found very little information on tightly coupling these two specific libraries for this kind of interactive experience. So, I thought I might as well ask here in case somebody has tried this before and found an optimal way to handle it.

How can I access and pass detailed event data (like the specific sample name, MIDI note value, and velocity) from an embedded Strudel instance to a p5.js instance?I’ve tried using the generic on(‘play’) event, but it doesn’t seem to contain the specific details I need.

Frontend Development Without JavaScript – Is It Possible?

I’m starting out in web development and honestly, I’m not a big fan of JavaScript. I’d love to build websites without relying on it or any of its frameworks.

it actually possible to build a modern, interactive frontend without relying on JavaScript? What are the real-world alternatives people are using?

And if I manage to pull it off, would my site automatically be faster and more stable? Would I avoid all those dependency nightmares I keep hearing about?

I’d love to hear from anyone who’s gone down this path. Thanks for any advice you can

So far, I’ve only worked with plain HTML and CSS to build basic static websites. I’ve created simple landing pages, personal portfolios، using only these two technologies

ETIMEOUT error connecting to free MongoDB atlas using mongoose and express server

terminal error while connecting mongodb atlas database using compass string

I have been stuck here for many days while connecting to MongoDB database using mongoose and express server.i have followed same steps and connected to database at other PC, but when connecting to my PC it wouldn’t work.

I am using internet through hotspot on mobile data, creating an account on MongoDB Atlas, and making clusters and add network and database user online and run server locally on port 8000 using express.

import dotenv from 'dotenv'
import connectDB from './db/index.js'
import express from 'express'

dotenv.config({ path: './.env' })

const app = express()

connectDB().then(() => {
  app.listen(process.env.PORT || 8000,
    () => {
      console.log(`⚙️ Server is running at port : ${process.env.PORT}`);
    }
  )
}).catch((err) => {
  console.log("MONGO db connection failed !!! ", err);
})

How can I run a C file inside a Tauri app?

I have made a C file which displays certain data using the printf command

I want to make a Tauri app to display this data. For now, I am still trying to get the data from the Tauri app. How could I do this? I would prefer not to add the C file to my app. Instead, I want to generate the executable file manually and include the executable file in my app

I have already tried multiple different methods to run the C file from within the Tauri app. However, nothing has worked.

I have tried using Tauri Sidecar to do this

I have also tried using this code:

const command = new Command('run-c-app', ['./myapp']);
const output = await command.execute();
console.log('Output:', output.stdout);

I have also tried using this code:

#[command]
fn run_c_program() -> String {
    let output = Command::new("./myapp")
        .output()
        .expect("Failed to execute C program");
    
    if output.status.success() {
        String::from_utf8_lossy(&output.stdout).to_string()
    } else {
        String::from_utf8_lossy(&output.stderr).to_string()
    }
}

I am using the following package versions:

@tauri-apps/api: 2.8.0
@tauri-apps/plugin-opener: 2.5.0
react: 19.1.1
react-dom: 19.1.1
@tauri-apps/cli: 2.8.4
vitejs/plugin-react: 4.7.0
vite: 7.1.7

GraphQL Codegen + Apollo Client v4: Generated file uses skipToken import incorrectly in Next.js App Router

I’m using Apollo Client v4 (4.0.5) with Next.js App Router and GraphQL Code Generator (typescript-react-apollo) to generate TypeScript types and hooks for my GraphQL API.

Everything was working fine until I recently added some queries/mutations on the backend and regenerated my GraphQL types. Now, the generated code fails to compile with the following error:

Export skipToken doesn't exist in target module
  1 | import { gql } from '@apollo/client';
> 2 | import * as Apollo from '@apollo/client';
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  3 | export type Maybe<T> = T | null;
  4 | export type InputMaybe<T> = Maybe<T>;

The export skipToken was not found in module .../@apollo/client/core/index.js [app-client] (ecmascript).

If I manually edit the file after generation to destructure skipToken like this, it works fine:

import * as Apollo from '@apollo/client/react';
const { skipToken } = Apollo;

here is my codegen config:

overwrite: true
schema: 'http://localhost:5000/graphql'
documents: 'src/graphql/**/*.graphql'
generates:
  src/graphql/generated/graphql.ts:
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-react-apollo'
    config:
      withHooks: true
      withComponent: false
      withHOC: false
      skipTypename: false
      # Tried disabling but didn't help:
      # withSkipToken: false
      # reactApolloVersion: 3

So why does GraphQL Codegen generate a broken skipToken import when using Apollo v4 in Next.js App Router and how can I configure typescript-react-apollo so it does not generate skipToken imports at all (or generates them in a working way)?

javascript, how to select an element with random “dataset” attribute [duplicate]

there is a set of elements that looks like <a data-v-924a11e2 ... </a>

‘924a11e2’ of ‘data-v-924a11e2’ is random each time when page updates. And this dataset ‘data-v-924a11e2’ has no value. It looks like data-v-924a11e2=”” when you copy it as element.
i cant seem to find appropriate Selector that will select theese elements with random dataset name could it be ‘data-v-924a11e2’ or ‘data-v-12345678’ or other random name

tried querySelectorAll() with different params but didnt succeed

TMDb API Error: signal timed out when fetching popular movies

Problem:
I’m trying to fetch popular movies from the TMDb API in my Next.js project, but I keep getting a signal timed out error.

Here’s the error log:

TMDb API Error: signal timed out
  at TMDbService.fetchFromTMDb (/lib/tmdb)
  at async TMDbService.getPopularMovies (/lib/tmdb)
  at async loadPopularMovies (/app/page)

Error fetching popular movies: signal timed out
  at TMDbService.getPopularMovies (/lib/tmdb)
  at async loadPopularMovies (/app/page)

What I tried:

  • Verified my TMDb API key (works in Postman).

  • Tried increasing the timeout value.

  • Checked my internet connection (it’s fine).

  • The same API works if I call it with curl or Postman.

    Code (simplified):

    // lib/tmdb.js
    export class TMDbService {
      static async fetchFromTMDb(endpoint) {
        try {
          const response = await fetch(`https://api.themoviedb.org/3/${endpoint}`, {
            headers: {
              Authorization: `Bearer ${process.env.TMDB_API_KEY}`,
            },
            signal: AbortSignal.timeout(5000), // added timeout
          });
    
          if (!response.ok) {
            throw new Error(`TMDb API Error: ${response.status}`);
          }
    
          return await response.json();
        } catch (error) {
          console.error("TMDb API Error:", error.message);
          throw error;
        }
      }
    
      static async getPopularMovies() {
        return this.fetchFromTMDb("movie/popular");
      }
    }
    
    // app/page.js
    export default async function loadPopularMovies() {
      try {
        const movies = await TMDbService.getPopularMovies();
        return movies;
      } catch (error) {
        console.error("Error fetching popular movies:", error.message);
      }
    }
    
    

TypeScript: How to prevent external access to child component’s updateData() while allowing parent access?

TypeScript/JavaScript: Parent-Child Component State Management Design

Background

I’m currently working on a UI system with a parent component (Facade) and multiple child components. Each component maintains its own state, while the parent manages everything centrally. I’d love to get some advice on the best practices for this kind of architecture.

Current Design

// Parent component
class ParentFacade {
    private state: ParentState;
    private childComponentA: ChildComponentA;
    private childComponentB: ChildComponentB;
    private childComponentC: ChildComponentC;

    async setData(data: Data): Promise<void> {
        await this.state.setData(data);
        await this.handleDataChange(data);
    }

    private async handleDataChange(data: Data): Promise<void> {
        await this.state.setData(data);
        this.notifyAllComponents(data);
        await this.reflectStatus();
    }

    private notifyAllComponents(data: Data): void {
        this.childComponentA.updateData(data);
        this.childComponentB.updateData(data);
        this.childComponentC.updateData(data);
    }
}

// Child component
class ChildComponent {
    private state = { data: initialData };
    private onDataChange?: (data: Data) => void;

    public updateData(data: Data): void {
        this.setState({ data });
    }

    public async updateDataField(newValue: string): Promise<void> {
        const updatedData = { ...this.state.data, field: newValue };
        await this.service.updateDataField(updatedData);
        this.onDataChange?.(updatedData); // Notify parent
    }
}

The Problem

When external code directly calls a child component’s updateData() method, it creates state inconsistencies:

// Dangerous example
childComponent.updateData(newData); // Only this child gets updated
// Other child components and parent state remain outdated!

I actually have this issue in another file:

// external-service.ts
export async function updateDataStatus(
    element: HTMLElement,
    childComponent: ChildComponent
): Promise<void> {
    // ... processing ...

    // Direct child component update (dangerous)
    childComponent.updateData(updatedData);
}

Solutions I’ve Tried (and Why They Don’t Work)

1. Making updateData() private

class ChildComponent {
    private updateData(data: Data): void {
        // private
        this.setState({ data });
    }
}

Problem: The parent can’t call it either, breaking the design

2. Requiring parent reference

class ChildComponent {
    constructor(private parentFacade: ParentFacade) {}
    // updateData() removed
}

Problem: No way for parent to update child components

3. Stateless child components

class ChildComponent {
    render(data: ReadonlyData) {
        this.updateUI(data);
    }
}

Problem: Still need a mechanism to notify parent of changes, and mutation risk remains the same

My Questions

I’d really appreciate your thoughts on these questions:

  1. Is there a way to prevent external code from calling updateData() while still allowing the parent to call it?

  2. What are the best design patterns for parent-child component state management that prevent inconsistencies?

  3. Is it possible in TypeScript/JavaScript to prevent external direct manipulation while still allowing parent-to-child updates?

  4. Is my current design (each child component having its own state) appropriate, or would you recommend a different pattern?

Technical Stack

  • TypeScript
  • Custom UI framework (not React/Vue/Angular)
  • No state management libraries

Constraints

  • Significant changes to existing codebase are difficult
  • External library introduction is possible but should be minimal
  • Performance is important

I’d be so grateful for any advice or suggestions you might have! Thank you for taking the time to read this.

Anchor link loads wrong page on click, but correct page after refresh (HTML/XAMPP)

I have this div in index.html at C:xampphtdocsproyectindex.html:

<div class="splide__slide">
                            <div class="card card-style slide-1">
                                <div class="content mb-0">
                                    <h1 class="text-center-editado-slide1">Bars&Restaurants</h1>
                                    <p class="text-center-editado-subtitulo-slide1"> Descubrí propuestas
                                        irresistibles para tu próxima salida </p>
                                    <p class="boxed-text-xl-slide1-contenido mt-n3 font-14">
                                        Salir a comer es un plan único, por eso reunimos varias propuestas para vos.
                                    </p>
                                    <a href="../whereTo/barsRestaurants.html"
                                        class="btn btn-m btn-center-l rounded-s shadow-xl mb-4 btn-personalizado-1">
                                        Ver opciones...
                                    </a>
                                </div>
                            </div>

When I click the button, it opens the wrong page:

On click → incorrect page, after refresh → correct page.

If I press F5, it then goes to the correct file:

correct-images

This also happens in production, not only in XAMPP.

I don’t understand why the link works incorrectly on the first click, but correctly after refresh.
How can I fix this?