Using a relationships entry title as a repeatable components entry title

Hi!

I just thought I would share an extension I’ve working on. In my project, we link many content entries together using relationships inside components. However, it’s currently not possible to make the title of a repeatable component to be the entry title of a relationship established inside of the component. Ex:

In this example, I would want the title of the Button relationship to show in the expandable repeatable component.

I was able to do this by extending this file: extensions/content-manager/admin/src/components/RepeatableComponent/DraggedItem/utils/select.js

import { useMemo } from 'react';
import { get, toString } from 'lodash';
import { useContentManagerEditViewDataManager } from 'strapi-helper-plugin';

function useSelect({ schema, componentFieldName }) {
  const {
    checkFormErrors,
    modifiedData,
    moveComponentField,
    removeRepeatableField,
    triggerFormValidation,
  } = useContentManagerEditViewDataManager();

  const mainField = useMemo(() => get(schema, ['settings', 'mainField'], 'id'), [schema]);
  const nestedObjectTitle = schema.layouts.edit?.[0]?.[0]?.metadatas?.mainField?.name;
  const nestedObjectField = schema.layouts.edit?.[0]?.[0]?.name;
  const displayValuePath = (mainField === 'id' && !!nestedObjectTitle)
    ? [...componentFieldName.split('.'), nestedObjectField, nestedObjectTitle]
    : [...componentFieldName.split('.'), mainField];
  const displayedValue = toString(
    get(modifiedData, displayValuePath, '')
  );

  return {
    displayedValue,
    mainField,
    checkFormErrors,
    moveComponentField,
    removeRepeatableField,
    schema,
    triggerFormValidation,
  };
}

export default useSelect;

With this extension, the repeatable component will attempt to use the first items relationship entry title if a title for the repeatable component has not be specified.
Here is the result:

Just wanted to share in case someone was trying to solve the same problem!

2 Likes

Hey, I created this file exactly where you mentioned but it didn’t work. It’s still giving me only one option “id”. So, I thought maybe it isn’t extending for some reason so I went to the node_modules and edited this file there. It still didn’t work =(

Any hints?

@starrett67 Thank you, this saved me a ton of searching!

@dydx-git Do you have strapi running with npm run develop -- --watch-admin so that it builds the admin interace when a file is changed? Also make sure to configure the view to make it show the id as entry title. I added the supplied code to extensions and it worked out of the box like a charm!

@starrett67 This doesn’t work with v4, right?

Its not working in v4, im also interested how to make it in v4.

I’m also interested in this functionality for v4. The above code works when the relevant file is updated in node_modules perfectly @starrett67 so thanks for providing this.

Does anyone how to do this for v4?

Hi, same, would be really interested as well to get this working on v4

Following my previous message, I figured out how to make this code work with v4, by inserting the logic exposed above (@starrett67 thanks again) inside the corresponding v4 file, directly in the @strapi node module (as copying files & hierarchy in the extension folder doesn’t work anymore for a basic override).

So: in node_modules/@strapi/admin/admin/src/content-manager/components/RepeatableComponent/DraggedItem/utils/select.js here is the code I inserted :

import { useMemo } from "react";
import { get, toString } from "lodash";
import { useCMEditViewDataManager } from "@strapi/helper-plugin";

function useSelect({ schema, componentFieldName }) {
  const {
    checkFormErrors,
    modifiedData,
    moveComponentField,
    removeRepeatableField,
    triggerFormValidation,
  } = useCMEditViewDataManager();

  const mainField = useMemo(
    () => get(schema, ["settings", "mainField"], "id"),
    [schema]
  );

  const nestedObjectTitle = schema.layouts.edit?.[0]?.[0]?.metadatas?.mainField?.name;  
  const nestedObjectField = schema.layouts.edit?.[0]?.[0]?.name;
  
      const displayValuePath = (mainField === 'id' && !!nestedObjectTitle)
    ? [...componentFieldName.split('.'), nestedObjectField, nestedObjectTitle]
    : [...componentFieldName.split('.'), mainField];

  const displayedValue = toString(
    get(modifiedData, displayValuePath, '')
  );

  return {
    displayedValue,
    mainField,
    checkFormErrors,
    moveComponentField,
    removeRepeatableField,
    schema,
    triggerFormValidation,
  };
}

export default useSelect;

Then we have to rebuild using npm run build --clean (to clean the cache).

As modyfying the node_module is a very ugly process, some recommendations I found browsing the official Discord are to use the path-package, so that basically we don’t loose the file as soon as we reinstall the packages, but it is suggest to break.

Some folks say it will be fixed in future version, which I highly expect :slightly_smiling_face:.

2 Likes

Worked like a charm! Now only if I can get this working with list view…

This did not work for me but I am using yarn. I’ve been seeing conversations about this since 2020 so I doubt this will happen anytime soon.