maxatwork / form2js

Javascript library for collecting form data
http://maxatwork.github.com/form2js/
MIT License
640 stars 137 forks source link

js2Form? #10

Closed lookfirst closed 13 years ago

lookfirst commented 13 years ago

This little library is great. It is exactly what I'm looking for.

That said, I'd love the opposite direction as well.

I'd love to be able to take a chunk of json and have it apply to all of the input/textarea's on a page.

The usecase for this is handling of the 'cancel' button. I'd love to just reset everything to its prior values.

Thanks,

jon

lookfirst commented 13 years ago

I've written this and will be contributing it back soon. Its done with CoffeeScript and JQuery. It works with all of the examples for this project except the Ruby one. I don't care about Ruby, so someone else can figure out that logic. ;-)

maxatwork commented 13 years ago

Check out develop branch (9d7ca0afd4029940e7e091b62b9775eb8e1cf4a2)

lookfirst commented 13 years ago

Here is mine (in coffeescript + jquery). I went a different direction...

flattenData = (json, elem=[], frag) ->
        for key, value of json
            if $.type(value) == "object"
                complete = if !frag then key else "#{frag}.#{key}"
                flattenData(value, elem, complete)
            else if $.type(value) == "array"
                if value[0] && $.type(value[0]) == "object"
                    cnt = 0
                    for valObj in value
                        for kval, vval of valObj
                            elem.push({key: "#{frag}.#{key}[#{cnt}].#{kval}", value: vval})
                        cnt++
                else
                    complete = if !frag then "#{key}[]" else "#{frag}.#{key}[]"
                    flattenData(value, elem, complete)
            else
                # necessary for person.favFood test
                if $.type(json) == "array"
                    complete = if !frag then key else "#{frag}"
                else
                    complete = if !frag then key else "#{frag}.#{key}"
                elem.push({key: complete, value: value})
        return elem

json2Form = (@data, @form) ->
        flattened = flattenData(@data)
        for flat in flattened
            @key = flat.key
            @value = flat.value
            @flds = $('[name^="' + @key + '"]', @form)
            for fld in @flds
                @jfld = $(fld) # convert to jquery
                switch fld.type
                    when "textarea", "hidden", "text"
                        @jfld.val(@value).change()
                    when "select-one", "select-multiple"
                        $('select[name="' + fld.name + '"] option', @form).each (i, e) =>
                            e = $(e)
                            if e.val() == "#{@value}"
                                e.attr('selected', true)
                            else
                                e.removeAttr('selected')
                            e.change()
                    when "checkbox", "radio"
                        if @jfld.val() == "#{@value}"
                            @jfld.attr('checked', true)
                        else
                            @jfld.removeAttr('checked')
                        @jfld.change()
maxatwork commented 13 years ago

Most complex thing in my implementation of deserialization is arrays. Array index in field name should be unique, but it's not necessary to have index 0 'zero' at first element, or to have consecutive indexes (order of appearance in document used instead). This is useful for dynamic form elements creation, because we have to increment index and insert form fields in proper place to add item, and just remove form fields to remove item.

So if we have this form:

<form>
    <input type="text" name="array[10000].name" value="val1">
    <input type="text" name="array[5].name" value="val2">
</form>

form2js will return this data:

{
    "array" : [ 
        { "name" : "val1" }, 
        { "name" : "val2" } 
    ]
}

and it seems like your implementation will not populate original form with it, but sure it's enough in some cases.

lookfirst commented 13 years ago

Ah, I didn't realize that was part of the criteria. I'll gladly switch to your code! Thanks for creating this great tool.

That said, I'd appreciate it if you'd write it in coffeescript/jquery. Much easier to read!

boxxxie commented 13 years ago

i'm trying to use js2form. i'm not sure what i need to put in as the first argument for the function: rootNode.

it would be great if you guys could give me an example of how to use it. thank you.

boxxxie commented 13 years ago

to use this am i supposed to have my form already set up so that it conforms to the JS object? i guess i expected it to make my webpage for me, via 300 lines of magic javascript :)

maxatwork commented 13 years ago

Correct, it doesn't create a form =)

boxxxie commented 13 years ago

I'm using form2js and it's working great for me. now i'm trying to take the data i get out of form2js and put it back in the same form via js2form. i'm not really sure what object to pass into it as the root node. i guessed that it would be a jQuery object. code below

                 var rootNode = $("#testForm");
                 js2form(rootNode, data, '.', true);

I see that getFields() needs rootNode to have a firstchild object. the object i get from jQuery doesn't have that field. what object should i use?

boxxxie commented 13 years ago

i found out how to do this document.getElementById('testForm');

via the example html code

boxxxie commented 13 years ago

i made a js2form repo. at first it was based off of your code, but then i just rewrote it all after i found that underscore .toArray() and jQuery did almost all of the work for me.

i don't think it's as complete as yours, but it's much smaller and easier to extend, which i will be doing soon.

https://github.com/boxxxie/js2form

lookfirst commented 12 years ago

max: Thanks for doing this. I noticed this issue in the code for js2form, you are missing this line:

    rootNode = typeof rootNode == 'string' ? document.getElementById(rootNode) : rootNode;