Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using resolveFields for array. #499

Open
Roshan54321 opened this issue Jun 6, 2024 · 2 comments
Open

Using resolveFields for array. #499

Roshan54321 opened this issue Jun 6, 2024 · 2 comments

Comments

@Roshan54321
Copy link

How can I use resolveFields api for an array. I want to look at the data and if a condition on any item of the array is satisfied, I want to do something with the fields of that item only.

ps: To make it more difficult, I have overriden the array field, so I am recursively rendering the overriden fields (have overriden all fields) to cover each type whatever comes.

@chrisvxd
Copy link
Member

chrisvxd commented Jun 7, 2024

This is a good question, ands something I overlooked in the initial implementation. Here are some suggestions:

  1. You can reach into the appState param provided to the resolveFields method, and check the (undocumented) ui.arrayState to determine which item is currently visible. This is undocumented because it's not final and may be subject to breaking changes in the future. I've tested this an it's unsuitable as changing the appState doesn't trigger resolveFields.
  2. You could use custom fields and the new <AutoField> component. Probably the cleanest approach, but doesn't use the resolveFields API.
  3. Otherwise, we will need to consider a new API to account for it, like an additional resolveFields API on the array field that receives the current index.

Here's an example of the custom field approach (untested) 👇

import { AutoField } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      fields: {
        myArray: {
          type: 'array',
          arrayFields: {
            data: {
              type: "custom",
              render: ({ value, onChange }) => {
                if (value.myCondition) {
                  return (
                    <>
                      <AutoField
                        field={{ type: "radio" }}
                        onChange={(fieldVal) => onChange({...value, myCondition: fieldVal })}
                        value={value.myCondition}
                      />
                      <AutoField
                        field={{ type: "text" }}
                        onChange={(fieldVal) => onChange(fieldVal)}
                        value={value.myText}
                      />
                    </>
                  );
                }

                return (
                  <AutoField
                    field={{ type: "radio" }}
                    onChange={(newVal) => onChange({...value, myCondition: newVal })}
                    value={value.myCondition}
                  />
                );
              }
            }
          }
        }
      }
    }
  }
};

Would be curious to know if that works for you, and how/whether to extend resolveFields to work for arrays properly.

@Roshan54321
Copy link
Author

Roshan54321 commented Jun 7, 2024

Using no.2 approach is a definite fix (really appreciate this, does it for me, yes), but it is limited to just that one. I guess resolveFields would be a better choice (even for me) considering it is a general approach for every array fields.

I haven't used much of those readOnly fields so don't know how I can override fields to also consider the usecase of readonly. And I am overriding everything right now, so would need something like this:

eg: arrayFields: {
   a: "",
   b: ""
}

while overriding:

for each item in value:
  {Object.keys(item).map((key, i) => {
      fieldType = field.arrayFields[key].type
      switch(fieldType){
                 --------------render the type of field-----------------
                 eg: case 'object':
                       return <OverridenObjectField key={`...`}  {........props........}/>
      }
  })}

the worst thing here is that the arrayFields is constant for each item. Here one needs something like :
key exists in field.arrayFields[itemId]? which needs different fields for each item in the array (makes it more complex).

My naive need: resolveField for array only so it becomes:

for each item in value:
  fields = resolveField(field.arrayFields, item)
  {Object.keys(item).map((key, i) => {
      fieldType = fields[key].type (if key not in fields, do nothing)
      switch(fieldType){
                 --------------render the type of field-----------------
                 eg: case 'object':
                       return <OverridenObjectField key={`...`}  {........props........}/>
      }
  })}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants