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.
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.
Edit: As Rich Harris pointed out in the comments below, getters and setters won't work within data
because Svelte copies the properties to a plain JS object internally (thus ignoring getters and setters). I think the next best thing you can do is make a method name
that can be called like name()
as a getter, and name(value)
as a setter.
<h1>Hello {{_name}}!</h1>
<script>
export default {
data() {
return {
_name: 'The Name'
}
},
methods: {
name(value) {
if (value === void 0) return this.get('_name')
this.set('_name', value)
}
}
}
</script>
Original Post:
Your getter and setter should be in your data
rather than your methods
, because they create a property in the end. This property conflicts with the name
you defined as equal to 'The Name'
inside your original data
method. I would suggest using a "private" property _name
instead.
<h1>Hello {{name}}!</h1>
<script>
export default {
data() {
return {
_name: 'The Name',
get name() {
return this._name
},
set name(value) {
/ /.test(this._name) || (this._name = value)
}
}
}
}
</script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With