I working on a WordPress Gutenberg block that has the following attributes:
attributes: {
panels: {
type: "array",
default: [{
id: uuid(),
h2: "",
h3: "",
backgroundImage: "",
highlightText: "",
featureList: [""],
buttonText: "",
buttonUrl: "",
buttonColor: ""
}
}
}
As you can see, it is an array of objects (panels[]). The problem I'm having is this: when there are 2 or more panels and I start typing into one of the panels (the h2, for example) all other panels disappear.
Here is the JSX that is returned:
return (
<div {...blockProps}>
<h2 className="tpp-heading">Tariff Product Panel</h2>
{props.attributes.panels.map((panel, panelIndex) => {
return (
<div className="tpp-product" id={panel.id}>
<h2 className="tpp-sub-heading">Product {panelIndex + 1}</h2>
<Button
onClick={() => removePanel(panelIndex)}
className="tpp-remove-panel"
title="Delete Panel">
<Icon
icon={
"remove"
}
/>
</Button>
<Flex>
<FlexBlock className="tpp-attribute">
<TextControl
value={panel.h2}
label="Heading"
onChange={(value) => updateAttribute(panelIndex, value, "h2", panel.id)}
/>
</FlexBlock>
<FlexBlock>
<TextControl
value={panel.h3}
label="Sub Heading"
onChange={(value) => updateAttribute(panelIndex, value, "h3", panel.id)}
/>
</FlexBlock>
</Flex>
<Flex>
<FlexBlock className="tpp-attribute">
<TextControl
value={panel.backgroundImage}
label="Background Image"
onChange={(value) => updateAttribute(panelIndex, value, "backgroundImage", panel.id)}
/>
</FlexBlock>
<FlexBlock>
<TextControl
value={panel.highlightText}
label="Highlight Text (if filled in, panel will have highlight)"
onChange={(value) => updateAttribute(panelIndex, value, "highlightText", panel.id)}
/>
</FlexBlock>
</Flex>
<Flex>
<FlexBlock className="tpp-attribute">
<TextControl
value={panel.buttonText}
label="Button Text"
onChange={(value) => updateAttribute(panelIndex, value, "buttonText", panel.id)}
/>
</FlexBlock>
<FlexBlock>
<SelectControl
label="Button Color"
value={panel.buttonColor}
options={[
{ label: 'Default', value: 'default' },
{ label: 'Primary', value: 'primary' },
{ label: 'Secondary', value: 'secondary' },
]}
onChange={(value) => updateAttribute(panelIndex, value, "buttonColor", panel.id)}
/>
</FlexBlock>
</Flex>
<Flex>
<FlexBlock className="tpp-attribute">
<TextControl
value={panel.buttonUrl}
label="Button URL"
onChange={(value) => updateAttribute(panelIndex, value, "buttonUrl", panel.id)}
/>
</FlexBlock>
</Flex>
<label class="components-base-control__label css-1v57ksj">Features:</label>
{panel.featureList.map((feature, featureIndex) => {
return (
<Flex>
<FlexBlock>
<TextControl
value={feature}
onChange={(feature) => updateFeaturelist(panelIndex, featureIndex, feature)}
/>
</FlexBlock>
<FlexBlock>
<Button
onClick={() => removeFeature(panelIndex, featureIndex)}
className="tpp-delete-feature"
title="Delete Feature">
<Icon
icon={
"trash"
}
/>
</Button>
</FlexBlock>
</Flex>
)
})}
<Button
onClick={() => addNewFeature(panelIndex)}
className="tpp-add-feature">
Add feature
</Button>
</div>
)
})}
<Button
isPrimary
onClick={() => addNewProduct()}>
Add product
</Button>
</div>
)
}
And here is the function that updates the panel:
function updateAttribute(panelIndex, value, el, id) {
let panel = props.attributes.panels.find((item) => item.id == id)
panel[el] = value
props.setAttributes({
panels: props.attributes.panels.splice(panelIndex, 1, panel)
})
}
I'd really appreciate a bit of help with this. Everything else is working fine.
In the updateAttribute function I've tried various ways to get this to work but without any luck. Obviously, what I'm expecting is that when typing into a panel, the other panels do not disappear.
OK... I've managed to figure it out - but it took quite a while!
So it turns out that I needed to update the a copy of the whole array (panels) first before calling setAttribute.
function updateAttribute(panelIndex, value, el, id) {
let panel = props.attributes.panels.find((item) => item.id == id)
panel[el] = value
const newPanels = [...props.attributes.panels]
newPanels[panelIndex] = panel;
props.setAttributes({
panels: newPanels
})
}
I'm still a bit confused as to why my earlier attempts were not working but at least I've managed to solve my issue.