Use getters/setters in Svelte Custom methods

Total
8
Shares

I am not able to compile my svelte component when using a get/set pair in custom methods. Is this not supported? Or am I doing something wrong?

Example:

Say I wanted to have a component that displays a name and I want to set the name using.

com.name = 'The new name';

However I only want the component to use the name if it has no spaces in the name.

<h1>Hello {{name}}!</h1>

<script>
    export default {
        data () {
            return {
                name: 'The Name',
            }
        },
        methods: {
            get displayName() {
                return this.get('name'); 
            },
            set displayName(val) {
                if (val.indexOf(' ') < 0) {
                    this.set('name', val);
                }
            }
        }
    }
</script>

The Issue is that when I try to compile this, it says there is a duplicate key.

    Duplicate property 'displayName'

    49:             return this.get('name');
    50:         },
    51:         set displayName(val) {

Here is a REPL – https://svelte.technology/repl?version=1.13.2&gist=0eeab5717526694139ba73eae766bb30

I don’t see anything in the documentation about this. I can just not use setters, but I would like to be able to.


Solution

tl;dr this is possible with a wrapper object

The error message here is a bit confusing — it’s not the duplicate property that’s a problem, is that you can’t have getters and setters in methods, which in any case is separate from the data object that populates a component’s internal state (along with data supplied at instantiation and any computed values there might be). I’ve opened an issue for that here.

The data itself also can’t have getters and setters — or rather it can, but they won’t be used, because the object returned from your data function isn’t the same as the internal state object (otherwise we’d all probably run into mutation-related bugs).

But it’s actually fairly easy to create a wrapper object that allows you to get and set a component’s data:

function wrap (component) {
  var wrapper = {};
  var data = component.get();

  Object.keys(data).forEach(key => {
    Object.defineProperty(wrapper, key, {
      get() {
        return component.get()[key];
      },
      set(value) {
        component.set({ obj[key]: value });
      }
    })
  });

  return wrapper;
}

var component = new Component({...});
var wrapper = wrap(component);

wrapper.name = 'Rich';

You could even do component.data = wrap(component) if you were so inclined — then you could manipulate component.data.name and so on.

I’ve put together a small repo demoing that approach — see it in action here.

Leave a Reply

Your email address will not be published. Required fields are marked *