gitana / alpaca

Alpaca provides the easiest way to generate interactive HTML5 forms for web and mobile applications. It uses JSON Schema and simple Handlebars templates to generate great looking, dynamic user interfaces on top of Twitter Bootstrap, jQuery UI, jQuery Mobile and HTML5.
http://www.alpacajs.org
Other
1.29k stars 370 forks source link

Improper output format for array field form when using AJAX to POST JSON data #605

Open seanvree opened 6 years ago

seanvree commented 6 years ago

When using an ajax post to write to a json file, the below form appends unneeded text to the output json string.

The below form will output this to the json file:

{"data":[{"type":"Curl","check url":"afd","link url":"afa"}]}

Why is it appending the " {"data":{ " to the start?

it should look like this:

{"type":"Curl","check url":"afd","link url":"afa"}

I've used this on other forms, and for some reason, particular form appends the unnecessary text.

here is my form:

<div id="field7"></div>

    <script type="text/javascript">
        $(document).ready(function() {

            $("#field7").alpaca({
                "schema": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "type": {
                                "enum": ["Curl", "Ping"]
                            },
                            "check url": {
                                "type": "string",
                                "format": "uri"
                            },
                            "link url": {
                                "type": "string",
                                "format": "uri"
                            }
                        }
                    }
                },
                "options": {
                    "toolbarSticky": true,
                    "items": {
                        "fields": {
                            "type": {
                                "label": "Type",
                                "optionLabels": ["Curl", "Ping"]
                            },
                            "check url": {
                                "label": "Check URL"
                            },
                            "link url": {
                                "label": "Link URL"
                            }
                        }
                    },
                    "form": {
                        "attributes": {
                            "action": "post_receiver.php",
                            "method": "post",
                        },

                        "buttons": {
                            "submit": {
                                type: 'button',
                                "label": "submit",
                                click: function(){

                                    var data = $('#field7').alpaca().getValue();

                                    $.post('post_receiver.php', {
                                        data
                                     })

                                    alert(JSON.stringify(this.getValue(), null, "  "))

                                }
                            },

                            "view": {
                                "label": "View JSON",
                                "click": function() {
                                    alert(JSON.stringify(this.getValue(), null, "  "));
                                }
                            }
                        }
                    }
                }
            });

        });
    </script>

Thanks!

ambischof commented 6 years ago

It is not a bug with alpaca but with your code

$.post('post_receiver.php', {
                                        data <--- wrapped in brackets
                                     })

you should have $.post('post_receiver.php', data)

seanvree commented 6 years ago

@ambischof interesting, because I tried exactly what you suggested changing ONLY that bit of code, it writes to the .json file, but this is all I get:

{"undefined":""}
                            "submit": {
                                type: 'button',
                                "label": "submit",
                                click: function(){

                                    var data = $('#field7').alpaca().getValue();

                                     $.post('post_receiver.php', data)

                                    alert(JSON.stringify(this.getValue(), null, "  "))

                                }
                            },

image

seanvree commented 6 years ago

@ambischof I hate to keep bother you Sir, but this is one of the last bugs I can't get past before integrating this into my project.

Do you have any other ideas?

I've tried the following with many different variations:

$.post('post_receiver.php', data)

which returns " {"undefined":""} "

and I've also tried removing the variable

$.post('post_receiver-services.php', $('#servicesettings').alpaca().getValue())

That also returns " {"undefined":""} "

It's weird because it works on some forms, and other not, and I can't find a pattern. They are all using the same backend php script:

<?php
    $fp = fopen('../data/services_settings-data.json', 'w');
        fwrite($fp, json_encode($_POST));
    fclose($fp);
?>

so I don't get why it's appending the extra " {data} " tag to the JSON output? Even when I try and load that exact same json data source that the form creates, it doesn't load it until I remove that data tag.

ambischof commented 6 years ago

Don't just try to tweak the code when you have an issue, you need to figure out what your code is actually doing so you can fix it.

Do you know how to use the developer tools in your browser? Specifically the network monitoring where you can view the exact request your browser sends and how it is encoded. It will help you see exactly what your browser is sending to the server, so you can easily identify if the issue is on the front end or the server.

Here is a link of how to do so in Chrome: https://developers.google.com/web/tools/chrome-devtools/network-performance/reference

Also, on your server route, log exactly what it is receiving.

seanvree commented 6 years ago

@ambischof thanks for that tip, I am familiare with dev tools and monitoring what's being posted. This is my first project using these types of forms. So, I'm assuming this what I'm looking for:

decoded looks like this: image

Encoded looks likes this: image

ambischof commented 6 years ago

Looks fine there, so your issue is something in your server.

seanvree commented 6 years ago

huh? no that's not fine, that's the wrong format. Here's a comparison with another form that's using the exact same php post script.

The one on the left is in the correct format, no [data] appended. You'll see that the form on the left IS in the correct format, but the form on the right is appending "data[0]" to each of the strings.

image

ambischof commented 6 years ago

I don't have your code, nor do I have what you're trying to achieve, so if you want me to help you, you'll need to post that.

seanvree commented 6 years ago

@ambischof dude, really?! it's in the first post man.

ambischof commented 6 years ago

I assumed you tried to fix it, and you posted so many different fixes I don't know which one you're referring to any more.

Your previous post has two different form data values, and I don't know which code maps to which.

Are you trying to get the form to send JSON? because if you are, you can't just the $.post(url, data) signature, as that will encode it as application/x-www-form-urlencoded. You will need to use the object signature:

`$.post({url: 'post_receiver-services.php', data: JSON.stringify(data), contentType: 'application/json'})

I'm guessing the reason that 'data' is being added is because it can't encode an array in application/x-www-form-urlencoded as the base, it can only encode objects, so it adds the data key. Making sure it uses json will fix that.

seanvree commented 6 years ago

@ambischof I've only posted two different variations of the code man, which you suggested. Nothing has changed on server side or data. Only the form options.

YES. I"m trying to get the form to send JSON data, which it IS doing, it's just in the wrong format.

1.

$.post('post_receiver-services.php', data)

json data result: " {"undefined":""} "

2.

  $.post('post_receiver-services.php', {
      data
    }) 

json data result: " data[0][serviceTitle]:test "

And here is the 3rd option which you just suggested:

$.post({url: 'post_receiver-services.php', data: JSON.stringify(data), contentType: 'application/json'})

json data result: " [] "

ambischof commented 6 years ago

When you say that is the json data result, is that the what the browser is sending, what the server is receiving, or what is being written to file?

seanvree commented 6 years ago

@ambischof Both. The snippets above are copied and pasted from the actual json file, but the browser console is almost identical to those strings. Example:

$.post({url: 'post_receiver-services.php', data: JSON.stringify(data), contentType: 'application/json'})

image

ambischof commented 6 years ago

If that's the case, check what's in your 'data' variable. I just tried that same snippet in my console except replacing data with {foo: 'bar'} and it did exactly what I expected.

EDIT: Please post the entire request page above the 'Form Data' section. Unless your chrome is very different from mine, it should not show 'Form Data' if the encoding is 'application/json', but rather 'Request Payload'.

seanvree commented 6 years ago

@ambischof

 var data = $('#servicesettings').alpaca().getValue();
ambischof commented 6 years ago

That doesn't really help me. I asked what the value of the data variable is and to post the entire network details of the request. If you can't do that, at least post a fiddle or something if you want me to help you debug this.

seanvree commented 6 years ago

@ambischof Appricate your help man. Sorry to get a little testy with ya. Been working on this for a couple days now. I'm sure you know how that is. Also, can't really do a jfiddle with PHP.

Here's the full network output:

You'll notice that the "parent" array that the actual data string is in is BLANK with just a " [ ] " which is why I'm assuming that's all I'm setting in the JSON output?

image

image

image

again, here's the complete form options:

    "submit": {
        type: "button",
        "label": "Submit",
        click: function(){
            var data = $('#servicesettings').alpaca().getValue();

            $.post({
                url: 'post_receiver-services.php', 
                data: JSON.stringify(data), 
                contentType: 'application/json',
                    success: function(data) {
                        alert(JSON.stringify(data));
                        alert("settings saved");
                    },
                error: function(errorThrown){
                    console.log(errorThrown); 
                } 
            });                                        
        }
    },

Here's the back-end PHP code, also, this DOES work on a couple of the other forms from this same site.

<?php
    $fp = fopen('../data/services_settings-data.json', 'w');
        fwrite($fp, json_encode($_POST));
    fclose($fp);
?>
ambischof commented 6 years ago

If the jsfiddle is only the javascript side, that's fine, I just wanted to see what it was sending.

Okay It looks like the client side is sending the data correctly. That's good. Now we know that the issue is in the php side.

When I said log the server side data, I meant log it in the php function. I don't remember how to do logging in PHP, so you'll have to figure that out.

Before you write to the file, log the contents of $_POST, then log json_encode($_POST) so you can verify that it has the input you think it has.

seanvree commented 6 years ago

@ambischof

I'm somewhat disagreeing with you when you said "client side is sending data correctly" Because I don't think it is. Again, if you see my screenshot, it's putting the data from the form in a "child" array. The other three forms don't have that first array that I marked in red in the screenshot. Also, it MAY be something we need to add to the PHP script because of the way the the alpaca form is sending the data, because like I said, the other 4 forms work fine and are using the exact same php file to get the AJAX post.

So the browser output is like this:

[,…]  <- shouldn't be there
0 : {serviceTitle: "test1", image: "../img/monitorr.png", type: "Both", checkurl: "http://localhost:80",…}
     checkurl :"http://localhost:80"
     image : "../img/monitorr.png"
     linkur :  "http://localhost:80"
     serviceTitle  :   "test1"
     type  :  "Both"

Also, the alert is NOT showing any json data, all it shows is "/r/n"

I know how to write to a log file, I'll get that set up and send you the results.

ambischof commented 6 years ago

Ahh, I didn't realize you didn't want it to be in an array. It is an array because you told it to be when you set the schema to be type: 'array'.

If that is not what you want, then why did you make it that way?

seanvree commented 6 years ago

@ambischof no, I DO want it to be in an array, it needs to be in an array, all the other forms are in an array as well. The problem here is that it IS sending the json data in array format, but it's adding a "top level/ parent" array that's blank, which is why the json output is simply" [ ] "

This is the schema for that form:

{   
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "serviceTitle": {
                "type": "string",
                "title": "Service Title",
                "default": "Service Title"
            },
            "image": {
                "type": "string",
                "title": "Serivce Image",
                "format": "uri",
                "default": "../img/monitorr.png"
            },
            "type": {
                "type": "radio",
                "title": "Check Type",
                "enum": ["Both", "Curl Only", "Ping Only"],
                "default": "Both"
            },
            "checkurl": {
                "type": "string",
                "format": "uri",
                "default":"http://localhost:80"
            },
            "linkurl": {
                "type": "string",
                "format": "uri",
                "default":"http://localhost:80"
            }
        }
    }
}
ambischof commented 6 years ago

Ahh, no, it's not sending a top level blank array, that's just how the console shows the parent array. Paste in [{a: '1'}] to the console and hit enter and you'll find it displays it in the same way.

seanvree commented 6 years ago

@ambischof humm. okay, I see...

Well, I don't get it then.

So I set up logging on the server site as well as on the form.

so in the form I simply added this after the click: function()

console.log(data);

and I changed the .post to send the entire form's data without json.

    $.post({
        url: 'post_receiver-services.php', 
        data: data, 
        success: function(data) {
            alert(data);
            alert("settings saved");
        },
        error: function(errorThrown){
            console.log(errorThrown); 
        } 
    });

and that logs this into the browser:

image

and on the server side I changed the php script to this:

<?php
    $fp = fopen('../data/log.txt', 'w');
        fwrite($fp, $_POST);
    fclose($fp);
?>

And it does write to the file, but it's blank. It's not receiving ANY data it appears?

ambischof commented 6 years ago

You're still not logging it on the server side. I want you to actually use logging in your php code. That's the only way to know for sure

seanvree commented 6 years ago

@ambischof Yes, I had verbose logging turned on for the entire PHP runtime application for the webserver. Again, it logs that there is a POST, but NO data with the POST.

However, if you want to see it in the actual PHP script, this is what I'm using:

<?php

    ini_set('display_errors', 'On');
    error_reporting(E_ALL);
    var_dump($_POST);
    $fp = fopen('../data/services_settings-data.txt', 'w');
        fwrite($fp, var_dump($_POST));
    fclose($fp);

    echo '<pre>'; var_dump($_POST); echo '</pre>'

?>

var_dump($_POST); will write the entire contents of the post to services_settings-data.txt as well as log it to the browser.

The browser alert comes back blank, the file is changed on the server, but it only has " [] "

ambischof commented 6 years ago

I can't really help you with that then, since I don't know all that much about php servers. My advice is to check if your server will automatically parse the request based on the ContentType header.

seanvree commented 6 years ago

It's not a "PHP" server man. It's MS IIS. It's a pretty standard rig.

I understand you're trying to prove that it's my server. I think I've proven that it's not. I run 20+ applications from this same server half of which parse json data just fine using PHP and various other frameworks.

If you want FURTHER proof, I put together this VERY simple form that uses the SAME php script. It posts JUST fine as you can see.

https://seanvree.com/dev/monitorr-settings-alpaca/ajax.php

There is obviously a bug or something we are BOTH missing with the alpaca script that is not posting proper json data.

image

ambischof commented 6 years ago

PHP or MS IIS, I know even less of that.

Bottom line is that the developer network tab doesn't lie. If there is a problem in the request being sent, you will find it there. It could be that there was an issue there I missed since it is just an image and I can't interact with it.

The example you sent encodes the data as application/x-www-form-urlencoded so I can't verify that the server does in fact correctly parse JSON. To be brutally honest, I'm half doubting that any of those applications actually do send data encoded as 'application/json', seeing as you couldn't figure out how get that form to work until just recently.

If you do have one that already sends data encoded as 'application/json', do send it along.

seanvree commented 6 years ago

@ambischof If you don't' know the basics about server side scripting, or webservers in general, then maybe you could point me to someone from Alpaca who does? Like I said in the other thread - displaying data from a pretty form is nice, but all that matters is what you do with that data.

If you look at the screenshot above you can plainly see that it did in fact parse the data correctly.

Figure out how to get what form working until recently? Dude, this is NOT rocket science man. Seriously, it's not. PHP is NOT complicated, ajax is NOT complicated. There's no reason that a simple web form should be this problematic. Maybe you should tell the developers to merge some of their pull requests to fix some bugs. There's some pretty good ones in there...umm...like this one maybe?

https://github.com/gitana/alpaca/issues/221

I appreciate you taking the time to discuss this, but it's obvious that you're trying to give me the whole line "it works on My machine" silver bullet. We haven't' even "de-bugged" anything, all you've had me do was post re-post a bunch of data to try and prove it's the webserver.

So, with all do respect, do you know anyone who might be knowledgeable of how to make these forms work on an actual webserver?

Thanks,

ambischof commented 6 years ago

I do know how create servers, but my experience is mostly in Node. If you think you know more than I do on the subject, whatever. I'm not going to argue credentials on the internet.

And no, I can't point you to anyone here who would know more about your specific server framework. But this isn't a place to talk about server frameworks, and it's certainly not stack overflow. It is the alpaca issues channel made to fix issues with the Alpaca and I'm just some random person trying to help you debug your own code when alpaca is working just fine.

Good luck.

seanvree commented 6 years ago

dude, it's not "my" specific framework. It's PHP! PHP has the native ability to decode json data. I'ts not my server, it's not PHP, it is in fact alpaca.

Nj0376 commented 6 years ago

Not sure if you sorted this out but you should change the following lines:

                            $.post('post_receiver.php', {
                                data
                            })

to

                            $.post('post_receiver.php', 
                                "=" + JSON.stringify(data, null, "  ")

                            )

placing the "=" prior to because you are posting an object. Give that a try. I haven't got php running on my test server but I changed your code and ran it on my server posting to a web api backend and it fixes the error as you can see below. I was getting your error but not after the fix.

form

Web traffic to and from server web traffic

Data received at server server

seanvree commented 6 years ago

@Nj0376

Thanks so much for your reply. Yeah, I know this has something to do with it.

Although, I changed my code, but the from data still shows empty for me. All I get back in the json file is " [] "

image

image

image

Now if I remove the " "=" + " I get better results in the browser, but still same results in the json file.

image

Were you using PHP to parse the data by chance? I'd really like to know if this works with PHP. I know there's a bug in the alpaca code as explained in this pull request (https://github.com/gitana/alpaca/pull/228) as I can get this working on my other forms that don't use an array.

<?php

    $json = json_encode( $_POST, true);
    $fp = fopen('../data/services_settings-data.json', 'w');
        fwrite( $fp, $json);
    fclose($fp);
?>
Nj0376 commented 6 years ago

No I was using Microsoft Web Api and C# to process the server request. Can you install Fiddler and see what's getting sent to your server and more importantly what's coming back from the server. It should give you a detailed response.