如何解决有没有办法在没有重定向/重新加载的情况下为 Pardot 提交HTMLFormElement 表单?如果不是,那么 Angular 的模拟方式是什么?
我会尽量让这件事变得简单。我已经尝试了很多东西并且已经研究了一段时间,我想我遗漏了一些小东西。
使用 Angular 12。
示例表格:
<form id="my-form" action="https://example.com" action="post">
<input name="fname">
<button (click)="mySubmitFunction()">SUBMIT</button>
</form>
我在 mySubmitFunction()
中有这样的逻辑:
const myForm = document.querySelector('#my-form') as HTMLFormElement;
myForm.submit();
使用此方法,会发生表单提交,它使用带有 <input>
属性的每个 name
来填充表单数据。您可以在 Chrome 的开发者工具中查看生成的 http 请求,例如在“网络”标签中。
我的问题是数据传给第三方供应商,然后发生重定向,重定向到我们告诉他们的任何内容(在这种情况下,它是同一页面)。因此,用户体验是不仅清除了此表单数据,而且清除了页面上的所有其他内容。
我所看到的大多数示例基本上都是不使用操作/方法/提交方法,而是定义一个按钮单击方法,该方法从头开始创建一个 http 请求(这是我尝试的第一件事实际上)。问题在于,无论在什么环境中,我都会在 http.post
请求中遇到 CORS 问题。这基本上是我在那里做的:
postContactInfoToVendor(requestBody: string): Observable<any> {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
// Where the requestBody is formatted like 'fname=Bob'
return this.http.post(environment.vendorUrl,requestBody,{ headers });
}
所以我有点被困住了,想知道那里的许多伟大的思想是否以前已经解决了这个问题,而我就是找不到它。
我还注意到随着表单的 submit() 请求发送了很多额外的标头,但我不知道它们来自哪里 - 想知道这是否有助于解决 CORS 问题。带有“visitor_id”类型条目的“Cookie”等标题等。
我正在考虑的可能解决方案:
-
在页面上的
iframe
中托管我的联系表单。然后在成功重定向(我们能够在供应商方面进行配置)时,可以转到感谢页面。 -
以某种方式拦截 form.submit() 的请求,取消请求并发送一个使用完全相同标头建模的新请求。不过,我目前无法拦截这些请求。
一如既往,感谢您的帮助。
更新: 我的具体问题是 Pardot 表单提交。在 Angular 中有一个解决方法,但我不确定我对此的感受。
将来自 Simulate a JSONP response with JavaScript URLs 和 How to make a simple JSONP asynchronous request in Angular 2? 的信息拼凑在一起,我能够导入 HttpJsonpModule
并将其用于
http.jsonp(url + urlEncodedString,'callback');
然后,我将成功/错误 URL 配置为静态托管的 json 文件,这些文件将在相应的响应中返回以用于成功/错误回调(据我所知)。我将在接下来的几天内对此进行测试,但只是想提供当前更新。
虽然,一般来说,我知道我的 <iframe>
解决方案也能奏效 :)
更新: 我已经完成了我的解决方案,不是使用 HTMLFormElement.submit(),也不是使用 http.post,而是使用 http.jsonp() 请求,只是因为服务器端支持 JSONP。
我很快会在这里写下我自己的所有信息的答案。
解决方法
Angular 有两种主要的方式来实现表单:
- 模板驱动的表单
- 反应形式
角度documention is very well written,实际上非常有趣。 angular 实现表单的方式非常完整,让您可以对发生的事情进行很多控制。
为了回答您的问题,您的第二个解决方案与 angular 的作用非常接近。 Angular 在表单上使用 (ngSubmit)
输出指令,您可以在 here 以及那里的许多示例中找到它。每当点击带有 (ngSubmit)
的按钮时都会触发 type="submit"
(您也可以以编程方式触发)。
您可以在此处找到模板驱动的表单实现的简单示例:https://angular.io/start/start-forms
,我的第一个问题的简单答案是它无法完成。无论您做什么,您的页面位置都必须更改。如果这是错误的,请有人纠正我。
对我的第二个问题的中等答案是,它可能可以通过 http 请求与 HTMLFormElement 的 .submit() 来完成,如果您可以模仿表单的请求并使用 Angular 的 HttpClient 的 http.post或改为获取请求。但是,这对我不起作用,因为我无法模拟所有标头或/并且表单处理程序端(第 3 方服务器,Pardot)存在 CORS 问题,我无法控制。
一般情况下的解决方法是将表单托管在 <iframe>
中,如果您能说服您的团队,那就没问题了 :)。然后,重定向/重新加载行为只会发生在 <iframe>
内,而不是整个页面。
我的解决方案是通过我们的第 3 方供应商找到另一种支持方法,因为我被告知要避免 <iframe>
。 Angular 和 Pardot 支持一个有点(我觉得)阴暗的协议,称为 JSONP,它可以解决 CORS 问题。但是这个设置对于这项任务来说有点矫枉过正。完整详情如下:
-
在我的模块 app.module.ts 中,我必须从
HttpClientJsonModule
导入@angular/common/http
。 -
我为我们创建了一个包含 Pardot 的所有预期字段的界面。
-
在按下提交按钮时激活的功能中,我从表单字段构建输入到该界面的表单,并从如下服务提交:
postContactInfoToPardot(formData: PardotForm): Observable<any> {
const formParams = parameterize(formData);
/*
Angular adds &callback=ng_jsonp_callback_0 or ng_jsonp_callback_1 etc. to the request,which is the name of
the success callback (will not get hit in this case bc we are not calling it directly)
'callback' is the name of the parameter that Pardot expects
There doesn't seem to be a way for our defined redirected .js to know about the number in ng_jsonp_callback_0,so just eat the error that will say "JSONP injected script did not invoke callback" in caller's error
callback.
*/
return this.http.jsonp(`${environment.pardotUrl}?${formParams}`,'callback');
}
...
// A function we have defined as a utility function
function parameterize(body: any): string {
return new HttpParams({fromObject: body}).toString();
}
-
我托管了两个可用作成功/错误重定向的简单 .js 文件。在
src/assets/pardot
下我有pardot-response-error.js
和pardot-response-success.js
-
那些文件的内容是
// Defined in src/index.html
pardotCallback({ 'result' : 'error' })
和
// Defined in src/index.html
pardotCallback({ 'result' : 'success' })
分别。
- 在
src/index.html
,我有:
<script>
function pardotCallback(response) {
const xhr = new XMLHttpRequest();
if (response.result === 'success') {
xhr.open('POST','#{loggingUrl}#?level=info');
xhr.send('Pardot form submission success');
} else {
xhr.open('POST','#{loggingUrl}#?level=error');
xhr.send('Pardot form submission error');
}
}
</script>
你可以在那里做任何你想做的事情——我们的团队只是想要一个请求去我们的后端服务器来记录成功或错误。 (我们将#{loginUrl}# 替换为特定于环境的值。我无法为此使用我的环境文件,因此这是通过我们的管道完成的)
- 对我而言,最后一件事是处理错误。在我调用我的服务函数将表单数据发送到 Pardot 的地方,如果我们不处理这个错误,最终用户将在他们的控制台中看到它作为每次提交表单的错误:
// Due to the nature of Angular + http.jsonp + Pardot,we will have an error,every time.
this.service.postContactInfoToPardot(pardotForm).subscribe(
() => {},(err: HttpErrorResponse) => {
// ONLY deal with an error here if it is not the one we are expecting every time
if (err.error.toString().indexOf('JSONP injected script did not invoke callback') === -1) {
// TODO: Replace with a call to the logging service,but this block also should never run
console.error(err);
}
}
);
- 现在,最后,在 Pardot 表单处理程序配置方面,我们将成功重定向(当前标签显示“成功位置”)设置为我们的 prod success.js,以及类似的错误重定向(当前标签为标签)是“错误位置”)到我们的 error.js。例如,
Success Location = https://<host>/assets/pardot/pardot-response-success.js
如您所见,此设置非常奇怪,我不认为我会向未来的团队推荐它,但它确实有效。我希望这对任何寻找相同信息的人都有帮助,无论是特定于 Pardot 的信息还是关于我的原始问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。