Search code examples
smalltalkamber-smalltalk

How do I get the values of all the fields of a form?


I have a HTML form like this in a client side Amber solution

<form id="myForm1">
  Creator:  <input type="text" name="creator" />
  <br>
  Title:  <input type="text" name="title" />
  <br>
  Description:  <input type="text" name="description" />
  <br>
  Doctype:  <input type="text" name="doctype" />
  <br>
  Tags:  <input type="text" name="tags" />
</form>

Question

How do I iterate through all of the fields of the form in order to put the content of the fields into a Amber dictionary with the field name as key and the text content as value?

New version of the question after answer by Stephen-Eggermont and MKroenert

How do I get the values of all the fields of the form in order to put them into an Amber dictionary with the field name as key and the text content as value?

Or is there an idiomatic way to create a form and retrieve the values?

Note: The form may be constructed with Amber code if this makes things more readable.

References

Edit after answer: FileIn code

The answer provided by MKroenert works fine

Below is his code I tested. It may be filed in directly in a workspace

    Widget subclass: #AmberFormExample
    instanceVariableNames: 'dictionary inputs'
    package: 'TodoList'!

!AmberFormExample methodsFor: 'not yet classified'!

collectValues
    inputs do: [ :each |
        dictionary at: (each asJQuery attr: 'name')
            put: (each asJQuery val).
        ].

Transcript show: dictionary printString
!

initialize
    dictionary := Dictionary new.
    inputs := Array new.
!

renderInput: inputName on: html
    html p: [
        html label with: inputName.
            inputs add: (html input id: inputName;
                name: inputName;
                yourself)]
!

renderOn: html
    inputs removeAll.
    html form id: 'myForm1'; with: [
        #('Creator' 'Title' 'Description' 'Doctype' 'Tags') do: [ :each |
            self renderInput: each on: html]].
    html button
        with: 'Collect Inputfield Values';
        onClick: [
            self collectValues.
            ]
! !

Solution

  • I reused the code from this SO question and rewrote it in Amber to address the first part of your question. Here is how you iterate over all input fields:

    (('#myForm1 *' asJQuery)
        filter: ':input')
            each: [ :thisArg :index |
                console log: thisArg ] currySelf
    

    This Amber recipe is required to get access to the JavaScript this.

    Printing both name and value of the input fields to the JavaScript console can be done like this:

    (('#myForm1 *' asJQuery)
        filter: ':input')
            each: [ :thisArg :index |
                console log: (thisArg asJQuery attr: 'name').
                console log: (thisArg asJQuery val)] currySelf
    

    Putting the values into a dictionary:

    | dict |
    dict := Dictionary new.
    (('#myForm1 *' asJQuery)
        filter: ':input')
            each: [ :thisArg :index |
                dict at: (thisArg asJQuery attr: 'name')
                    put: (thisArg asJQuery val)] currySelf
    

    As for the second part of your question, there is the Web package in Amber which contains Classes for generating HTML pages. What you do is to create a subclass of Widget and implement the renderOn: html method. The object passed in as html parameter is of type HTMLCanvas and can be used to create an HTML form like this:

    renderOn: html
        html form with: [
            html input id: 'creator'.
            html input id: 'title'.]
    

    Here is a complete example. Take it as a starting point and be aware that it may not be the most efficient way of doing things

    Widget subclass: #AmberFormExample
        instanceVariableNames: 'dictionary inputs'
        package: 'Examples'
    
    AmberFormExample>>initialize
        dictionary := Dictionary new.
        inputs := Array new.
    
    AmberFormExample>>renderOn: html
        inputs removeAll.
        html form id: 'myForm1'; with: [
            #('Creator' 'Title' 'Description' 'Doctype' 'Tags') do: [ :each |
                self renderInput: each on: html]].
        html button
            with: 'Collect Inputfield Values';
            onClick: [
                self collectValues.
                ]
    
    AmberFormExample>>renderInput: inputName on: html
        html p: [
            html label with: inputName.
                inputs add: (html input id: inputName;
                    name: inputName;
                    yourself)]
    
    AmberFormExample>>collectValues
        inputs do: [ :each |
            dictionary at: (each asJQuery attr: 'name')
                put: (each asJQuery val).
            ].
    

    After implementing this class in a running Amber instance the following code can be used to execute it:

    AmberFormExample new appendToJQuery: 'body' asJQuery