Support for two-way binding on custom elements
nsaunders opened this issue · 9 comments
Custom Elements (as in Web Components) cannot currently take advantage of two-way binding syntax.
For example, instead of this...
<custom-textbox
label="Email Address"
type="email"
placeholder="Enter your email address"
style="width: 300px"
bind:value="email" />
...I have to do this...
<custom-textbox
label="Email Address"
type="email"
placeholder="Enter your email address"
style="width: 300px"
value="{{email}}"
on:input="set({ email: event.target.value })" />
I think this is kind of a bummer. :-(
Wrote a simple example using a web component library that shows this
https://svelte.dev/repl/bc48abd5c41d4dee833e5757745cf57f?version=3.4.4
Seems like this is blocked in the compiler.
But it does not work when bypassing this validation
this.bindings.forEach(binding => {
const { name } = binding;
if (name === 'value') {
if (this.name !== 'input' &&
this.name !== 'textarea' &&
this.name !== 'select') {
component.error(binding, {
code: `invalid-binding`,
message: `'value' is not a valid binding on <${this.name}> elements`
});
}
@nsaunders I don't know if this is what you looking for, I try to add bind:value
on bootstrap modal, and it works.
Modal.svelte
<script>
import { onMount } from 'svelte'
export let value = false
let modalElement
const displayModal = value => {
if (process.browser) {
value
? window.$(modalElement).modal('show')
: window.$(modalElement).modal('hide')
}
}
onMount(() => {
window.$(modalElement).on('hidden.bs.modal', () => {
value = false
})
})
$: process.browser && displayModal(value)'
</script>
Parent.svelte
<script>
import Modal from '../Modal.svelte'
let modal
</script>
<div>
<button
on:click={() => (modal = true)}
class="btn btn-label-primary">
Add New
</button>
<Modal bind:value={modal}/>
</div>
If someones comes across this is search of a clearer answer,
If you want to bind to a "regular" html input, you can use the usual bind:value={yourValue}
.
If you want to bind to a custom element you created:
<YourComponent bind:yourExportedVarNameHere={yourValue} />
then in your custom component:
<script>
export let yourExportedVarNameHere;
</script>
Cheers,
@sudomaxime any hint while this is not working for ui5-input element?
The propname in ui5-input is "value"
https://codesandbox.io/s/divine-architecture-3qvlc?file=/App.svelte
It seems the method mentioned by @sudomaxime is not working when customElement: true
is set in rollup.config.js
.
HelloWorld.svelte (child)
<script>
import Hello from './components/Hello'
import World from './components/World'
export let value;
</script>
<svelte:options tag={'x-app-helloworld'}/>
<input type="text" bind:value={value} >
<input>
<x-app-hello />
<x-app-world />
App.svslte(parent)
<x-app-helloworld bind:value={value}/>
Then the parent will show an error: 'value' is not a valid binding on <x-app-helloworld> elements
.
How can I solve this?
@MAXI0008 I opened another issue... #4838
Same issue with ionic ion-input element. A webcomponent too.
Hi @antony - just curious if it is possible to reopen this one? You closed it maybe because of @sudomaxime comment, but that solution only works if you control the webcomponent
As you can see per later comments and still there - looking at my comment - if you don't control the webcomponent you can still not bind:value to get the binding to the elements value property.
Or do we need a workaround like mentioned here - https://css-tricks.com/using-custom-elements-in-svelte/
Wrapping the custom element in another custom element and then making the property reflective or something like that? Or even use:action for it?