Dirk J. Faber
Dirk J. Faber

Reputation: 4691

Wordpress Gutenberg SetAttributes with attribute passed as argument

I am creating a Gutenberg block with many attributes and try to create a generic function for attributes that can be changed with an input field. For an attribute title I have:

<RichText
  onChange={this.props.onTitleChange}
  value={this.props.title}
/>

and

function onTitleChange(value) {
  setAttributes({title: value});
}

This works. Now though I wish to create a generic function where in setAttributes() title can be anything I pass from the React onChange. I tried with another function onValueChange:

<RichText
  onChange={this.props.onValueChange.bind("title")}
  value={this.props.title}
/>

and

function onValueChange(value) {
  setAttributes({this: value});
}

This won't work because 'this' is not an attribute of my block. Even though this in my function onValueChange does equal 'title', which was passed with the bind() function. I am not sure if what I am trying to do is possible, because I don't fully understand the setAttributes() function, but if it can be done, it would save a lot time and extra code, because otherwise I would have to create a onXChange() function for all of my attributes. So my question is: how can I set a value on a dynamic attribute with setAttributes()?

Upvotes: 1

Views: 5843

Answers (3)

Greg B.
Greg B.

Reputation: 1

This was fantastic finding the [this] in the answer here. I was trying to take this a step further and that made it simpler for me!

Now I have one component I can use over and over for all the attributes I want.

export const CustomComponents = {
    CustomRangeControl: (val, attribute, setAttributes) => {        
        return (
            <RangeControl
                label={[attribute]}
                value={val}
                onChange={(value) => setAttributes({[attribute]: value}) }
                min={20}
                max={800}
            />
        );
    }
}

And now I can add it to my blocks like this

<InspectorControls>
    <PanelBody ...>
        {CustomComponents.CustomRangeControl(width, "width", setAttributes)}
        {CustomComponents.CustomRangeControl(height, "height", setAttributes)}
        ...
    </PanelBody>
</InspectorControls>

Upvotes: 0

Dirk J. Faber
Dirk J. Faber

Reputation: 4691

It turns out all I had to do was to wrap this in brackets, so:

function onValueChange(value) {
  setAttributes({[this]: value});
}

Keeping the bound attribute:

onChange={onValueChange.bind('title')}

Another option is to use setAttributes inline like so:

onChange={ title => setAttributes( { title } ) }

make sure to changetitle to the name of the attribute.

Upvotes: 2

Prabhat Mishra
Prabhat Mishra

Reputation: 1021

Currently i can think of this :

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // create a ref to store the textInput DOM element
    this.textInput = React.createRef();
  }

  render() {
    // tell React that we want to associate the ref
    // with the `textInput` that we created in the constructor
    <RichText
      onChange={ ()=> this.props.onValueChange("title",value) }
      value={this.props.title}
      ref={this.textInput}
    />
  }
}


  function onValueChange(property ,value) {
    let element = ReactDOM.findDOMNode(this.refs.textInput);
    element.setAttributes({property: value});
  }

PS: Not Sure wheather this is going to work but yeah you can give a try.

Upvotes: 0

Related Questions