2

I have some checkboxes on each object, and I would like to save the values.

Array of objects

[

    {
      "title": "Kevin Joe",
      "id": "365DmXom2V13xOqagTHczU",
      "enabledUnits": ""
    },
    {
      "title": "Kevin 2",
      "id": "365DmXom2V13xOqagTHczU",
      "enabledUnits": ""
    }

]

Some dummy units

  const dummyUnits = ["Unit 1", "Unit 2", "Unit 3", "Unit 4", "Unit 5"]

mockup

If I click on Unit 1 and Unit 2 For 'Kevin Joe'. This would be the desired result. Added to the object.

[

    {
      "title": "Kevin Joe",
      "id": "365DmXom2V13xOqagTHczU",
      "enabledUnits": "Unit 1, Unit 2"
    },
    {
      "title": "Kevin 2",
      "id": "365DmXom2V13xOqagTHczU",
      "enabledUnits": ""
    }

]

Current onChange handler, Is working but is just adding the single value, not multiple.

  const createOnChangeHandlerUnits = (floorPlan: FloorPlan, property: 'enabledUnits') => (
    e: React.ChangeEvent<HTMLInputElement>
) => {
    const {value} = e.target;

    setFloorPlans(floorPlans => {
        return floorPlans.map(entry => {

            if (entry.id === floorPlan.id) {
                return {...entry, [property]: value};
            }
            return entry;

        });
    });
    props.sdk.field.setValue(floorPlans);
};
{dummyUnits.map((unit, i) => {
   return (
      <CheckboxField id={unit} data-id={i} key={i} value={unit} onChange{(createOnChangeHandlerUnits(floorPlan, 'enabledUnits'))} labelText={unit} />)
})}

2 Answers 2

2

Use string concatenation as follows.

    setFloorPlans(floorPlans => {
        return floorPlans.map(entry => {

            if (entry.id === floorPlan.id) {
                return {...entry, [property]: entry[property].concat(`,${value}`)};
            }
            return entry;

        });
    });
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks but that seems to be adding to only one object and not toggling the unit values e.g enabledUnits: ",Unit 1,Unit 2,Unit 1"
got your point.
1

To toggle a value, you have to check if it's already in the string

if (entry.id === floorPlan.id && !entry[property].includes(value))

If it's not, I'd create an array using split and push the value inside, then join the values

entry[property].split(',').push(value).join(',')

If it is, you have to filter through the items to remove the toggled item, then join the values

entry[property].split(',').filter(item => item !== value).join(',')

The whole code

if (entry.id === floorPlan.id && !entry[property].includes(value)) {
  return { ...entry, [property]: entry[property].split(',').push(value).join(',') };
} else if (entry.id === floorPlan.id) {
  return {
    ...entry, 
    [property]: entry[property]
      .split(',')
      .filter(item => item !== value)
      .join(',') };
  }
}

return entry;

Although I don't think that's a good approach. I'd use an array as the type of enabledUnits for one. Maybe create a boolean variable to contain the toggled state. This seems a little overkill to me and also expensive to mutate the data all the time.


Edit

const setChecked = (
  floorPlan: FloorPlan,
  property: 'enabledUnits'
) => (e: React.ChangeEvent<HTMLInputElement>) => {
  const {value} = e.target;

  const item = floorPlans.find(entry => entry.id === floorPlan.id);
  return item[property].includes(value);
};

10 Comments

Thanks for this. I've changed the 'enabledUnits' to be an array. ` setFloorPlans(floorPlans => { return floorPlans.map(entry => { if (entry.id === floorPlan.id && !entry[property].includes(value)) { return {...entry, [property]: entry[property].concat(${value},)}; } else if (entry.id === floorPlan.id) { return { ...entry, [property]: entry[property] .filter(item => item !== value)}; } return entry; }); }); }; `
Though If i have multiple objects onChange only effects one which is strange onChange={(createOnChangeHandlerUnits(floorPlan, 'enabledUnits'))} would an index have to be passed through?
I'm not sure if I understand your question.. Why would you need an index? What do you mean multiple objects? You're already using an array of objects, which is technically 'multiple objects'
Sorry, ignore that. Is there a way to keep the checkbox active depending on the value saved on each object? ` <input type="checkbox" id={unit} key={i} value={unit} onChange={(createOnChangeHandlerUnits(floorPlan, 'enabledUnits'))} />`
Yes, you need to set checked={/* calculate if active */} which can be done like your onChange, but instead of mutating, you return true or false depending on the existence of the value
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.