有没有办法在没有重定向/重新加载的情况下为 Pardot 提交HTMLFormElement 表单?如果不是,那么 Angular 的模拟方式是什么?

如何解决有没有办法在没有重定向/重新加载的情况下为 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”等标题等。


我正在考虑的可能解决方案:

  1. 在页面上的 iframe 中托管我的联系表单。然后在成功重定向(我们能够在供应商方面进行配置)时,可以转到感谢页面。

  2. 以某种方式拦截 form.submit() 的请求,取消请求并发送一个使用完全相同标头建模的新请求。不过,我目前无法拦截这些请求。

一如既往,感谢您的帮助。


更新: 我的具体问题是 Pardot 表单提交。在 Angular 中有一个解决方法,但我不确定我对此的感受。

将来自 Simulate a JSONP response with JavaScript URLsHow 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 问题。但是这个设置对于这项任务来说有点矫枉过正。完整详情如下:

  1. 在我的模块 app.module.ts 中,我必须从 HttpClientJsonModule 导入 @angular/common/http

  2. 我为我们创建了一个包含 Pardot 的所有预期字段的界面。

  3. 在按下提交按钮时激活的功能中,我从表单字段构建输入到该界面的表单,并从如下服务提交:

    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();
}
  1. 我托管了两个可用作成功/错误重定向的简单 .js 文件。在 src/assets/pardot 下我有 pardot-response-error.jspardot-response-success.js

  2. 那些文件的内容是

// Defined in src/index.html
pardotCallback({ 'result' : 'error' })

// Defined in src/index.html
pardotCallback({ 'result' : 'success' })

分别。

  1. 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}# 替换为特定于环境的值。我无法为此使用我的环境文件,因此这是通过我们的管道完成的)

  1. 对我而言,最后一件事是处理错误。在我调用我的服务函数将表单数据发送到 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);
          }
        }
      );
  1. 现在,最后,在 Pardot 表单处理程序配置方面,我们将成功重定向(当前标签显示“成功位置”)设置为我们的 prod success.js,以及类似的错误重定向(当前标签为标签)是“错误位置”)到我们的 error.js。例如,

Success Location = https://<host>/assets/pardot/pardot-response-success.js


如您所见,此设置非常奇怪,我不认为我会向未来的团队推荐它,但它确实有效。我希望这对任何寻找相同信息的人都有帮助,无论是特定于 Pardot 的信息还是关于我的原始问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res