boojum
boojum

Reputation: 741

Is it possible to update component variables from within Svelte action?

Can actions update component variables? For example, in the App.svelte below is it possible to update values of disabled and errors?

<script>
  import { form } from './use-form'

  let disabled
  let errors = {}

  const submit = e => {
    const formData = new FormData(e.target)

    const data = {}
    for (let field of formData) {
      const [key, value] = field
      data[key] = value
    }
    console.log(data)
    e.target.reset()
  }
</script>

<form on:submit|preventDefault={submit} use:form={[disabled, errors]}>
  <input name="email" type="email" required />
  {#if errors && errors.email} <p>{errors.email}</p>{/if}
  <input name="password" type="text" minlength="8" required />
  {#if errors && errors.password} <p>{errors.password}</p>{/if}
  <hr />
  <button formnovalidate disabled={!disabled}>submit</button>
</form>

Here's the use-form action:

export const form = (node, [disabled, errors]) => {
  let inputs = node.querySelectorAll('input:invalid')

  const handleBlur = event => {
    ;[...inputs].forEach(e => {
      if (e.value.length === 0) {
        return
      } else {
        errors[e.name] = e.validationMessage
      }
    })

    disabled = node.checkValidity()
  }

  const handleInput = event => {
    ;[...inputs].forEach(e => {
      if (e.value.length === 0) {
        return
      } else {
        errors[e.name] = e.validationMessage
      }
    })

    disabled = node.checkValidity()
  }

  document.addEventListener('blur', handleBlur, true)
  document.addEventListener('input', handleInput, true)

  return {
    update: (disabled, errors) => {
      return disabled, errors
    },
    destroy: () => {
      document.removeEventListener('blur', handleBlur, true)
      document.removeEventListener('input', handleInput, true)
    },
  }
}

To better illustrate what I'm trying to achieve here's a repel with a crude working solution albeit all is sandwiched in one file.

Upvotes: 1

Views: 1584

Answers (1)

dummdidumm
dummdidumm

Reputation: 5426

This doesn't work because Svelte does not know that they are updated. What you can do is either

  • add events to the action and do the reassignment inside callbacks of the component: use:form={{onDisabled: d => disabled = d, ...}} (inside the action call onDisabled(node.checkValidity()))
  • use stores instead because Svelte will notice when these are updated: let disabled = writable(false); ... (inside the action do disabled.set(node.checkValidity()))

Upvotes: 2

Related Questions