1

I have a piece of code, using cycle.js and the reactive xstream library, like the one shown below. It consists of a form field whose value is rendered in a p tag on submit. The questions follow: 1. How can the form's input field be reset to the default value when the form is submitted? 2. Is there a way to reset the input$ and submit$ streams to their initial values after submit?

function formIntent (sourcesDOM) {
  const fNameInput$ = sourcesDOM
    .select('form#user .fname')
    .events('input')
    .compose(debounce(1000))
    .map((e: {target: any}) => e.target.value)

  const submit$ = sourcesDOM
    .select('form#user')
    .events('submit')
    .map((e) => e.preventDefault())
    .mapTo({type: 'USER'})

  const actions$ = xs.combine(fNameInput$, submit$)

  const initState = {fNameInput: ''}

  return actions$
    .map(([fNameInput, {type}]) => {
      return type === 'USER' ? {fNameInput} : initState
    })
    .startWith(initState)
}

function formView (state$) {
  return state$
    .map(({fNameInput}) => 
      div([
        form('#user', [
          label('Name'),
          hr(),
          input('.fname', {attrs: {id: 'first-name', type: 'text', placeholder: 'First name'}}),
          hr(),
          input('.sub', {attrs: {type: 'submit', value: 'Save'}})
        ]),
        div([
          h2('Submitted value'),
          p(fNameInput),
          hr()
        ])
      ])
    )
}

Is there a better way to create a form like this? P.S. the output of formIntent function is fed into the input of the formView function.

bloodyKnuckles
  • 11,551
  • 3
  • 29
  • 37
7puns
  • 1,505
  • 1
  • 9
  • 9

2 Answers2

1

This is what I ended up doing. It does what I wanted. I will still be interested to know a better way of achieving the same goal.

function formIntent (sourcesDOM) {
  const fNameInput$ = sourcesDOM
    .select('form#user .fname')
    .events('input')
    .compose(debounce(1000))
    .filter((e: {target: any}) => e.target.value.length > 2)
    .map((e: {target: any}) => e.target)

    const submit$ = sourcesDOM
    .select('form#user')
    .events('submit')
    .map(e => {
      e.preventDefault()
      console.log('3: Inside intent', e)
      return {user: 'CLICKED'}
    })

  return xs.combine(fNameInput$, submit$)
}

function formModel (actions$) {
  const initState = {user: '', fNameInput: {}}
  return actions$
    .map(([fNameInput, user]) => {
      const fName = fNameInput.value
      if (user.user === 'CLICKED') {
         fNameInput.value = fNameInput.defaultValue
         user.user = 'DISPLAY'
         return {user: user.user, fNameInput: fName}
      } else return initState
    })
    .startWith(initState)
}

function formView (state$) {
  return state$
    .map(({user, fNameInput}) =>
      div([
        form('#user', [
          label('Name'),
          hr(),
          input('.fname', {attrs: {id: 'first-name', type: 'text', placeholder: 'First name'}}),
          hr(),
          input('.sub', {attrs: {type: 'submit', value: 'Save'}})
        ]),
        (user === 'DISPLAY') && div([
          h2('Submitted value'),
          p(fNameInput),
          hr()
        ])
      ])
    )
}

function main (sources) {
  const actions$ = formIntent(sources.DOM)
  const state$ = formModel(actions$)
  const vtree$ = formView(state$)

  return {
    DOM: vtree$
  }
}
7puns
  • 1,505
  • 1
  • 9
  • 9
1

You can use hook for updating input value when DOM refreshed. So if you use @cycle/dom version >11.0 which uses Snabbdom you can use as this:

input({
    hook: {
        update: (o, n) => n.elm.value = ''
    }
})

Where empty string you can pass default value which you want. It will refresh input value every time when state updates.

Nurlan Mirzayev
  • 1,120
  • 1
  • 7
  • 15