如何将 Polymer 表单提交到 PHP 并显示响应

How to submit Polymer forms to PHP and display response

使用 Polymer 1.0,我设置了铁表单来提交简单的联系表单。这个想法是使用 PHP 将表单提交到数据库 table,然后在不刷新的情况下将来自 PHP 端的响应显示到浏览器中 - 典型的 AJAX。不过,我对 Polymer 环境很着迷 - 似乎应该有一个正确的方法来做到这一点,但数小时的搜索和修补并没有取得成果。

我确实使用 Polymer Starter Kit (lite) 启动了这个项目,它使用脚本 (app.js) 添加事件侦听器等。到目前为止,我还没有破坏这个功能,尽管文档中的所有示例都没有这样做,所以这让事情变得有点复杂,因为我仍然习惯于一般的 Polymer。

这是我目前所知道的。非常感谢您提供的任何建议。

index.html

<!-- this is where the output should be displayed -->
<div id="output"></div>

<!-- this is the web form -->
<form is="iron-form" id="contactus-form" method="post" action="/">
<input type="hidden" name="action" value="contactus-form">
<paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
<paper-button onclick="submitHandler(event)">Send</paper-button>
</form>

...

<script src="script/app.js"></script>
<script>
function submitHandler(event) {
    Polymer.dom(event).localTarget.parentElement.submit();
    }
</script>

app.js

(function(document) {
  'use strict';

  addEventListener('iron-form-submit', function(e) {

    // this works and displays the POSTed values in the browser
    document.querySelector('#output').innerHTML = JSON.stringify(e.detail);

    // I'm looking for a way to first submit this data through PHP and 
    // display the output of that process in the #output div rather than the 
    // raw form input itself.

    }
})(document);

失败的方法 1

我尝试在 index.html 中添加一个 iron-ajax 元素并从 app.js[=143 引用它=] 如下所示。不幸的是,当它尝试添加事件监听器时,整个应用程序崩溃了。这看起来很奇怪,因为 app.js 中还有许多其他片段以相同的方式添加事件侦听器。

index.html

<iron-ajax id="contactus-output" url="/form/contact.php" params="" handle-as="json"></iron-ajax>
<!-- same form as before goes here -->

app.js

var coutput = document.querySelector('#contactus-output');
coutput.addEventListener('response', function() {
    // nothing fancy here yet, just trying to see if I can do this
    document.querySelector('#output').innerHTML = 'hello world';
    }

失败的方法 2

我找到 This Answer on SO 并决定尝试 iron-form-response 活动。我现在收到的输出是 [object HTMLElement],这至少是一些东西,但我不确定它是否真的有效。

其他一切保持不变,我将表单的目标更改为指向我的 php 脚本,然后将 app.js 中的内容替换为以下内容:

app.js

addEventListener('iron-form-response', function(e) {
  document.querySelector('#output').innerHTML = e.detail;
});

我离得更近了吗?

不放弃

使用我上面第二个失败的方法,铁形式似乎在发出请求,因为当我监听 'iron-form-response' 事件时,它确实触发了。

然而,唯一得到 returned 的是 [object HTMLElement] - 不知道如何处理它。我尝试吐出它的一些属性(如 developer.mozilla.org - .title.properties.style 等记录的那样),但它们似乎是空的。 iron-form 真的是 return 一个 HTMLElement 对象还是这是一个错误?我认为它会 return 来自 PHP 脚本的结果,我将表单提交给它,就像正常的 XMLHttpRequest 一样。如果铁型以某种方式将其压缩成物体,有没有办法将其再次拉出?

TL;DR

我认为这整件事归结为:当我的 iron-form 处于 index.html 和 [=183= 时,如何正确添加事件监听器(对于 iron-form-request) ] 由 app.js 引导,就像 Polymer 1.0 入门套件中默认发生的那样?

进一步简化:当我不创建元素(只是使用它)时,如何将事件侦听器正确添加到 Polymer 的影子DOM?

BUG?

在下面user2422321的精彩回答的帮助下,正在执行iron-request并收到成功的iron-request响应。然而,它的 "response" 属性 returns NULL 即使 ​​"succeeded" returns 为真,也没有错误,并且 XHR 完全解析。 "get" 和 "post" 方法都使用相同的 NULL 结果进行了测试。

我看到 10 天前在 GitHub 中精确记录了一个与这些症状相匹配的错误,尽管它没有引起太多关注:Issue 83。这很不幸,但它似乎是一个错误。在修复元素本身之前,我不相信会有任何方法可以使它正常工作。

IRON-REQUEST 想看什么?!

随着我进一步探索,我发现即使 XHR 直接 returning "null",即使它具有正确的 responseURL 和 "OK" 的 statusText。我开始怀疑我正在尝试 运行 的实际 PHP 脚本(目前只输出 "Hello World")是否有问题。

iron-form-request 是否需要结果中的特定格式或数据类型?我尝试将 header('Content-Type: text/plain'); 添加到我的 PHP 文件,然后我尝试将其格式化为经过验证的 JSON 字符串,但响应仍然是 null。好像没什么效果。

Old school direct XMLHttpRequest 工作正常...甚至在提交请求之前铁形式是否畸形?

我确实设置了一个处理程序来捕获 iron-form-error 但收到了 none。根据回复中的每一条信息,世界上的一切都是完美的。只是...空响应。一遍又一遍……这真是令人难以置信的沮丧。

解决方案!(有点)

好吧,我实在是太绝望了,开始翻阅 iron 源代码本身。看起来 iron-form 目前仍然有些问题,如果响应格式正确 json 只有 return 的内容。在iron-request.html中,似乎允许以下类型,但不要上当。我只能让 json 工作——我想剩下的最终会落到实处。

  • json (application/json)
  • 正文 (text/plain)
  • html (text/html)
  • xml (application/xml)
  • 数组缓冲区 (application/octet-stream)

因此,目前,我们需要将响应格式设置为 JSON 并包含一个 DOCTYPE 声明以匹配。

就我而言,这看起来是这样(感谢 user2422321 对我的帮助):

index.php

<div id="output">{{myOutput}}</div>

<form is="iron-form" id="contactUsForm" method="get" action="/contactus.php" on-iron-form-response="_onResponseRetrieved">
<paper-input id="Name" name="Name" value="text" label="Name"></paper-input>
<paper-button id="contactSubmitButton" on-tap="_submitHandler">Submit</paper-button>
</form>

app.js

(function(document) {
...
app._onResponseRetrieved = function(e) {
  this.myOutput = e.detail;
  console.log(e);
};
app._submitHandler = function(e) {
  this.$.contactUsForm.submit();
});
...
})(document);

最后,这是最后一块重要的拼图。我以前没有考虑过这个文件输出的内容会非常重要,因为直接 XMLHttpRequests return 无论文件输出什么

contactus.php

<?php
// This is the line I added
header('Content-Type: application/json');
// Actual Code goes here
// Then make sure to wrap your final output in JSON
echo '{"test":"this is some test json to try"}';

有了所有这些部分,它就可以工作了,e.detail.response 包含我们从 contactus.php.[=35 回显的 JSON 响应=]

不太确定我明白什么不起作用,但我认为应该这样做 "pure" 聚合物方式(我的意思是尽可能少 Javascript ).

<div id="output">{{myOutput}}</div>

<!-- this is the web form -->
<form is="iron-form" id="contactUsForm" method="post" action="/" on-iron-form-response="_onResponseRetrieved">
   <input type="hidden" name="action" value="contactUsForm">
   <paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
   <paper-button on-tap="_submitHandler">Send</paper-button>
</form>


_onResponseRetrieved: function(e)
{
    //I'm not 100% sure what e.detail actually contain, but the value your looking for should be inside there somewhere
    this.myOutput = e.detail; 
}
_submitHandler: function(e)
{
    //Note that I renamed the id of your form :)
    this.$.contactUsForm.submit();
}

我也看到建议 onclick 应该是 on-tap 以便它在移动设备上正常工作,因此我更改了它。

UI 现在应该在您收到服务器响应后立即更新!

-

编辑:

因为您使用的是 Polymer Starter Kit,它在 index.html 中执行一些主要逻辑,所以有些事情有点不同。在 Polymer 文档中,通常会给出一些示例,其中它们显示元素内的一些代码,而 index.html 看起来或功能并不完全像一个元素,这确实会造成混淆。在我自己的项目中,我实际上跳过了 index.html 中的所有逻辑,因为我认为它看起来很混乱和复杂,但是当回头看时,它并没有那么奇怪(在我看来仍然不漂亮)。我不确定这一点,但是 index.html 的设置方式可能是设置 custom-elements 的方式,如果你想分开代码 (javascript) 和外观 (html/css).

所以为了让你的代码工作: 在 app.js 中,您会看到这一行:

var app = document.querySelector('#app');

您可以将 app 变量视为 custom-element。 在 index.html 中,您可以看到这一行,有点像:"if you click on me I will call the method onDataRouteClick in the element app":

<a data-route="home" href="/" on-click="onDataRouteClick">

那么,为什么会调用元素app上的方法呢?那是因为上面的行是 child 的:<template is="dom-bind" id="app">(注意 id 与此无关,除了我们通过该 id 将它定位在 Javascript 之外,所以当我说话时关于 app object 我说的是 Javascript).

app.js 中,我们可以通过执行以下操作来定义调用 onDataRouteClick 时会发生什么:

   app.onDataRouteClick = function() {
      var drawerPanel = document.querySelector('#paperDrawerPanel');
      if (drawerPanel.narrow) {
         drawerPanel.closeDrawer();
      }
   };

我不知道为什么,但他们一直使用这条线来查找 objects:

var drawerPanel = document.querySelector('#paperDrawerPanel');

但是当你在 app 的范围内时,你实际上可以使用它来代替,我认为它更像是 Polymerish:

var drawerPanel = this.$.paperDrawerPanel;

-

抱歉,如果您已经知道所有这些,现在我们如何让您的代码工作?

app.js 中添加:

app._onResponseRetrieved = function(e)
{
    //I'm not 100% sure what e.detail actually contain, but the value your looking for should be inside there somewhere
    this.myOutput = e.detail;
    console.log(e); //Check the console to see exactly where the data is
};
app._submitHandler = function(e)
{
    //Note that I renamed the id of your form :)
    //We are in the scope of 'app' therefore we can write this
    this.$.contactUsForm.submit();
};

index.html 中你会得到类似的东西(显然它应该在 template 元素中):

<div id="output">{{myOutput}}</div>

<!-- this is the web form -->
<form is="iron-form" id="contactUsForm" method="post" action="/" on-iron-form-response="_onResponseRetrieved">
   <input type="hidden" name="action" value="contactUsForm">
   <paper-input id="contactus-field-Name" name="Name" label="Name" value="test"></paper-input>
   <paper-button on-tap="_submitHandler">Send</paper-button>
</form>

我正在使用 Polymer 2,我遇到了类似的问题。

这是我的元素文件:

<template is="dom-bind">

    <iron-ajax
            auto
            id="ajax"
            url="test.php"
            handle-as="json"
            method="POST"
            body='{"email":"ankita@gmail.com", "lastlogin":"Feb 21st 2016", "notifications":6}'
            content-type = "application/json"
            last-response="{{responseObject}}" >
    </iron-ajax>

    <login-element details="[[responseObject]]"></login-element>
</template>

而登录-element.html 看起来像这样:

<dom-module id="login-element" >
<template>

    <!--<form action="test1.php" method="post"  enctype='application/json'>-->
        <!--Name: <input type="text" name="name"><br>-->
        <!--E-mail: <input type="text" name="email"><br>-->
        <!--<input type="submit" onclick="submitForm()">-->
    <!--</form>-->

    <h2>{{details.email}}</h2>

</template>

<script>
    Polymer({
        is:"login-element",
        properties:{
            details:Object
        }
    });

</script>

和test.php

<?php
$data = json_decode(file_get_contents('php://input'), true);
echo json_encode($data);
exit;