【问题标题】:How can I get the button that caused the submit from the form submit event?如何从表单提交事件中获取导致提交的按钮?
【发布时间】:2011-01-05 04:30:34
【问题描述】:

我正在尝试查找触发表单提交的提交按钮的值

$("form").submit(function() {

});

我可能会为每个按钮触发 $("input[type=submit]").click() 事件并设置一些变量,但这似乎不如在提交时将按钮从表单中拉出的方式优雅.

【问题讨论】:

  • 请注意,不一定有任何这样的按钮。一个脚本可能会做formobj.submit()。我认为点击事件是要走的路。
  • 对于现代浏览器,现在有event.submitter,它会为您提供被点击的<button><input type="submit">
  • event.originalEvent.submitter
  • 请注意,Apple Safari 也不应该被视为现代浏览器!

标签: jquery webforms


【解决方案1】:

可以获取以下HTML代码的按钮id:

<form id="theForm" action="" method="POST">
  <button name="sbtn" id="sbtn" value="Hey button" type="submit">Submit</button>
</form>

使用以下 JavaScript(利用 .val() 属性):

$('#theForm').on('click', 'button', function (e) {
  e.preventDefault();
  var
    $button = $(e.target),
    $form = $(e.delegateTarget);
  var buttonValue = $button.val();
});

【讨论】:

    【解决方案2】:

    $(document).ready(function() {
        $( "form" ).submit(function (event) {
            // Get the submit button element
            let submit_button =  event.handleObj;
            //submit button has the object of the use clicked button
        });
    }

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案3】:

    在处理表单元素位于 shadowRoot 中的 Web 组件时,我采用了 Tobias Buschor 的优秀 polyfill,如下所示,通过导入的模块以下列方式工作。请注意,这只在常青客户端(edge、safari、chrome、firefox)中提供兼容性。此外,正如 Mikko Rantalainen 所指出的,这并不遵循(我/我们可以在某个时候更新以遵循)https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit

    if( !('SubmitEvent' in self && 'submitter' in SubmitEvent.prototype) ){
    // polyfill SubmitEvent.submitter (a Safari issue as-of 2021)
    // https://developer.mozilla.org/docs/Web/API/SubmitEvent
        const submitter = Symbol.for('submitter');
        Event[ submitter ] = null;
        const submitterSelector = 'input[type=submit], input[type=image], input[type=button], button';
    
        Object.defineProperty(Event.prototype, 'submitter', {
            get: function(){
                if('submit' === this.type){
                    let node = Event[ submitter ];
                    const form = this.target;
                    if(!node || !form.contains(node)){
                        node = form.querySelector(submitterSelector);
                    }
                    // always return a node, default as though form.submit called
                    return node || form;
                }
                return undefined;
            },
            set: function(value){
                if('submit' === this.type){
                    this.submitter = value;
                }
            }
        });
        self.addEventListener('click', function polyfill_SubmitEvent_submitter_click(event){
            const node = event.composedPath()[0];
            const closest = node.closest?.(submitterSelector) ?? null;
            Event[ submitter ] = closest;
        }, true);
    }
    

    【讨论】:

      【解决方案4】:

      从事件对象中获取提交者对象

      您可以在提交表单时简单地获取事件对象。从中获取提交者对象。如下:

      $(".review-form").submit(function (e) {
              e.preventDefault(); // avoid to execute the actual submit of the form.
      
              let submitter_btn = $(e.originalEvent.submitter);
              
              console.log(submitter_btn.attr("name"));
      }
      

      我已经在这里详细解释了:(https://stackoverflow.com/a/66334184/11320178
      如果您有任何疑问,请告诉我。

      【讨论】:

        【解决方案5】:

        现在提交事件中有一个标准的submitter 属性。
        Already implemented in Firefox 75 and Chrome/Edge 81

        document.addEventListener('submit',function(e){
            console.log(e.submitter)
        })
        

        对于不支持它的浏览器,使用这个 polyfill
        注意:如果您针对旧版浏览器,您需要填充其他内容,例如 closestmatches。并确保在添加提交事件之前加载 polyfill。

        !function(){
            var lastBtn = null
            document.addEventListener('click',function(e){
                if (!e.target.closest) return;
                lastBtn = e.target.closest('button, input[type=submit]');
            }, true);
            document.addEventListener('submit',function(e){
                if ('submitter' in e) return;
                var canditates = [document.activeElement, lastBtn];
                lastBtn = null;
                for (var i=0; i < canditates.length; i++) {
                    var candidate = canditates[i];
                    if (!candidate) continue;
                    if (!candidate.form) continue;
                    if (!candidate.matches('button, input[type=button], input[type=image]')) continue;
                    e.submitter = candidate;
                    return;
                }
                e.submitter = e.target.querySelector('button, input[type=button], input[type=image]')
            }, true);
        }();
        

        【讨论】:

        • 请注意 Apple Safari 仍然不支持此功能!
        • 注意上面的polyfill需要UA实现Element.closest()、Element.matches()和Element.querySelector()。还有可能 UA 在 polyfill 中调用 your 'submit' 处理程序 before 'submit' 处理程序,而你看不到 .submitter 值。
        • 感谢 Mikko,我添加了一条说明如何避免这些问题。
        • polyfill 还应该检查按钮是否与要提交的表单实际匹配。如果页面包含例如两种形式,第一种形式的按钮单击可能最终由上述 polyfill 提交给第二种形式。另请注意,根据 WHATWG 规范,提交者可能会丢失,例如form.submit() 已被直接调用。
        • 是的,我现在将 lastBtn 重置为 null。我无法理解规范中 form.submit() 的行为,因为调用 form.submit() 不会触发提交侦听器你能指出规范吗?
        【解决方案6】:

        表单的SubmitEvent 有一个submitter 属性。但是,截至目前,这在 Safari 上不起作用。

        <form id="form">
            <button value="add" type="submit">Add</button>
            <button value="remove" type="submit">Remove</button>
        </form>
        
        let form = document.getElementById('form');
        
        form.onsubmit = (event) => {
            e.preventDefault();
            console.log(e.submitter.type);
        }
        

        适用于不同浏览器的不同方法。但是,您必须依赖 form 元素而不是 event 对象。这基本上在表单元素对象上添加了一个“提交者”属性,稍后可以在表单提交时引用。

        <form id="form">
            <button onclick="this.form.submitter = 'add'" type="submit">Add</button>
            <button onclick="this.form.submitter = 'remove'" type="submit">Remove</button>
        </form>
        
        let form = document.getElementById('form');
        
        form.onsubmit = (event) => {
            e.preventDefault();
            console.log(form.submitter);
        }
        

        【讨论】:

          【解决方案7】:

          我写了这个对我有帮助的函数

          var PupulateFormData= function (elem) {
              var arr = {};
              $(elem).find("input[name],select[name],button[name]:focus,input[type='submit']:focus").each(function () {
                  arr[$(this).attr("name")] = $(this).val();
              });
              return arr;
          
          };
          

          然后使用

          var data= PupulateFormData($("form"));
          

          【讨论】:

            【解决方案8】:

            使用更具体的事件处理程序和 JQuery,您的事件对象就是单击的按钮。如果需要,您还可以从该活动中获取委托表格。

            $('form').on('click', 'button', function (e) {
              e.preventDefault();
              var
                $button = $(e.target),
                $form = $(e.delegateTarget);
              var buttonValue = $button.val();
            });
            

            此文档包含您入门所需的一切。 JQuery Doc.

            【讨论】:

              【解决方案9】:

              (事件)

              function submForm(form,event){
                           var submitButton;
              
                           if(typeof event.explicitOriginalTarget != 'undefined'){  //
                               submitButton = event.explicitOriginalTarget;
                           }else if(typeof document.activeElement.value != 'undefined'){  // IE
                               submitButton = document.activeElement;
                           };
              
                           alert(submitButton.name+' = '+submitButton.value)
              }
              
              
              <form action="" method="post" onSubmit="submForm(this, event); return false;">
              

              【讨论】:

                【解决方案10】:

                我利用了document.activeElement,正如这个答案中所描绘的那样:How to get the focused element with jQuery?

                $form.on('submit', function() {
                    var $btn = $(document.activeElement);
                
                    if (
                        /* there is an activeElement at all */
                        $btn.length &&
                
                        /* it's a child of the form */ 
                        $form.has($btn) &&
                
                        /* it's really a submit element */
                        $btn.is('button[type="submit"], input[type="submit"], input[type="image"]') &&
                
                        /* it has a "name" attribute */
                        $btn.is('[name]')
                    ) {
                        console.log("Seems, that this element was clicked:", $btn);
                        /* access $btn.attr("name") and $btn.val() for data */
                    }
                });
                

                我利用了这样一个事实,即按钮在单击后始终是焦点元素。如果您在点击后立即执行blur(),这不会起作用。

                @Doin 发现了另一个缺点。如果用户在文本字段中通过enter 提交表单,则不会设置document.activeElement。您需要自己注意这一点,方法是处理 input[type="text"] 和类似中的 keypress 事件。

                2017 年 1 月更新: 对于我的库 Hyperform,我选择不使用 activeElement,而是捕获所有导致表单提交的事件。 The code for this 在 Github 上。

                如果您碰巧使用 Hyperform,您可以通过以下方式访问触发提交的按钮:

                $(form).on('submit', function(event) {
                  var button = event.submittedVia;
                });
                

                【讨论】:

                • MDN 说是的。 (FF3、IE4、Chrome 2、Safari 4、Opera 9)
                • 这应该是答案。
                • 嗯...如果通过 [Enter] 提交表单,这是否有效? Spec说这应该等同于单击默认提交按钮,但我不确定它是否将其保留为活动元素。
                • 很遗憾,你不能只依赖activeElement,因为可以定义“提交者”: A. 通过真实点击激活 (直接用鼠标或键盘空格键点击/回车); B. 通过合成点击激活buttonElement.click()buttonElement.dispatch(new MouseEvent(...)),不获取焦点); C. 通过表单隐式提交(键盘与其他表单的字段交互) D. 无,当formElement.submit()
                • 只是一个注释,以保持最新状态。截至目前,Safari 在单击提交按钮时将 activeElement 设置为文档正文。我在 Safari 9.1 上遇到了这个问题
                【解决方案11】:

                只是另一种解决方案,因为没有其他解决方案符合我的要求。优点是可以检测到点击和按键(输入和空格)

                // Detects the Events
                var $form = $('form');
                $form.on('click keypress', 'button[type="submit"]', function (ev) {
                
                    // Get the key (enter, space or mouse) which was pressed.
                    if (ev.which === 13 || ev.which === 32 || ev.type === 'click') {
                
                        // Get the clicked button
                        var caller = ev.currentTarget;
                
                        // Input Validation
                        if (!($form.valid())) {
                            return;
                        }
                
                        // Do whatever you want, e.g. ajax...
                        ev.preventDefault();
                        $.ajax({
                            // ...
                        })
                    }
                }
                

                这对我来说效果最好。

                【讨论】:

                  【解决方案12】:

                  我确实尝试了提供的一些示例,但它们不适合我们的目的。

                  这里有一个小提琴要展示:http://jsfiddle.net/7a8qhofo/1/

                  我遇到了类似的问题,这就是我们在表单中解决问题的方法。

                  $(document).ready(function(){
                  
                      // Set a variable, we will fill later.
                      var value = null;
                  
                      // On submit click, set the value
                      $('input[type="submit"]').click(function(){
                          value = $(this).val();
                      });
                  
                      // On data-type submit click, set the value
                      $('input[type="submit"][data-type]').click(function(){
                          value = $(this).data('type');
                      });
                  
                      // Use the set value in the submit function
                      $('form').submit(function (event){
                          event.preventDefault();
                          alert(value);
                          // do whatever you need to with the content
                      });
                  });
                  

                  【讨论】:

                    【解决方案13】:

                    我创建了一个测试表单并使用 Firebug 找到了这种方式来获取值;

                    $('form').submit(function(event){
                      alert(event.originalEvent.explicitOriginalTarget.value);
                    }); 
                    

                    很遗憾,只有 Firefox 支持此事件。

                    【讨论】:

                    • IE 没有这个属性(explicitOriginalTarget)
                    • 好旧的 IE 把它搞砸了,通过 Firebug 并且看不到任何其他要使用的对象值,但完全忘记了替代浏览器。听到它并不感到惊讶,但必须检查 Chrome。
                    • 只有 Firefox 支持这个事件。
                    • 所以基本上,HTML 中有些东西不能在 JS 中完成……Mozilla 决定实现缺少的功能,nobody 紧随其后适合?这就是为什么我们不能拥有美好的事物
                    【解决方案14】:

                    我搜索并找到了几种使用 jQuery + AJAX 将提交按钮 name + value 发送到服务器的方法。我不是很喜欢他们...

                    最好的方法之一是这里提出的猎人解决方案!

                    但我自己又写了一篇。

                    我想分享,因为它很好,而且根据我的需要,它也适用于通过 ajax 加载的表单(在 document.ready 之后):

                    $(document).on('click', 'form input[type=submit]', function(){
                        $('<input type="hidden" />').appendTo($(this).parents('form').first()).attr('name', $(this).attr('name')).attr('value', $(this).attr('value'));
                    });
                    

                    简单!单击提交按钮时,表单中会添加一个隐藏字段,使用相同的提交按钮namevalue

                    编辑:下面的版本更容易阅读。此外,它还负责删除以前附加的隐藏字段(在两次提交相同表单的情况下,这在使用 AJAX 时是完全可能的)。

                    改进的代码:

                    $(document).on('click', 'form input[type=submit]', function(){
                        var name   = $(this).attr('name');
                        if (typeof name == 'undefined') return;
                        var value  = $(this).attr('value');
                        var $form  = $(this).parents('form').first();
                        var $input = $('<input type="hidden" class="temp-hidden" />').attr('name', name).attr('value', value);
                        $form.find('input.temp-hidden').remove();
                        $form.append($input);
                    });
                    

                    【讨论】:

                    • 1+ 这对我有用。谢谢!
                    • 看起来这依赖于所有&lt;button/&gt;s 共享相同的name 属性。我会使用一个类并在您的.remove() 中引用它。
                    • @binki:不,它没有。无论如何,每个开发人员都可以根据自己的需求调整解决方案。
                    • jsfiddle.net/binki/d8ecv 显示了我对name 属性的意思。如果表单被重用并且包含不同名称的提交输入,那么旧的输入可能会使表单变得混乱。
                    • 现在我明白了……我会更新我的答案。 (其实我并没有太在意你的评论,因为你提到了&lt;button/&gt;元素,而代码中使用了&lt;input type="submit" /&gt;...)
                    【解决方案15】:

                    一种简洁的方法是在每个表单按钮上使用点击事件。 以下是一个带有保存、取消和删除按钮的 html 表单:

                    <form  name="formname" action="/location/form_action" method="POST">
                    <input name="note_id" value="some value"/>
                    <input class="savenote" type="submit" value="Save"/>
                    <input class="cancelnote" type="submit" value="Cancel"/>
                    <input class="deletenote" type="submit" value="Delete" />
                    </form> 
                    

                    以下是jquery。我根据单击的按钮(“保存”或“删除”)将适当的“操作”发送到同一服务器功能。如果点击“取消”,我只是重新加载页面。

                    $('.savenote').click(function(){
                       var options = {
                           data: {'action':'save'}
                       };
                       $(this).parent().ajaxSubmit(options);
                       });
                    
                    
                    $('.deletenote').click(function(){
                       var options = {
                           data: {'action':'delete'}
                       };
                       $(this).parent().ajaxSubmit(options);
                       });
                    
                    
                    $('.cancelnote').click(function(){
                       window.location.reload(true);
                       return false;
                       });
                    

                    【讨论】:

                      【解决方案16】:

                      对于我的目的来说,这是一种看起来更简洁的方法。

                      首先,对于任何和所有形式:

                      $('form').click(function(event) {
                        $(this).data('clicked',$(event.target))
                      });
                      

                      当这个点击事件被一个表单触发时,它只是简单地记录了原始目标(在事件对象中可用)以供以后访问。这是一个相当广泛的笔触,因为它会在表单上的任何位置单击。欢迎优化 cmets,但我怀疑它永远不会引起明显的问题。

                      然后,在 $('form').submit() 中,您可以查询上次点击的内容,例如

                      if ($(this).data('clicked').is('[name=no_ajax]')) xhr.abort();
                      

                      【讨论】:

                        【解决方案17】:

                        你可以用“event.originalEvent.x”和“event.originalEvent.y”试试这个方法:

                        <!DOCTYPE html>
                        <html>
                        <head>
                            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
                            <title>test</title>
                        </head>
                        <body>
                        
                            <form id="is_a_form">
                                <input id="is_a_input_1" type="submit"><br />
                                <input id="is_a_input_2" type="submit"><br />
                                <input id="is_a_input_3" type="submit"><br />
                                <input id="is_a_input_4" type="submit"><br />
                                <input id="is_a_input_5" type="submit"><br />
                            </form>
                        
                        </body>
                        </html>
                        <script>
                        $(function(){
                        
                            $.fn.extend({
                              inPosition: function(x, y) {
                        
                                return this.each(function() {
                        
                                    try{
                                        var offset = $(this).offset();
                        
                                        if ( (x >= offset.left) &&
                                             (x <= (offset.left+$(this).width())) &&
                                             (y >= offset.top) &&
                                             (y <= (offset.top+$(this).height())) )
                                        {
                                            $(this).css("background-color", "red");
                                        }
                                        else
                                        {
                                                $(this).css("background-color", "#d4d0c8");
                                        }
                                        }
                                        catch(ex)
                                        {
                                        }
                        
                                });
                              }
                            }); 
                        
                            $("form").submit(function(ev) {
                        
                                $("input[type='submit']").inPosition(ev.originalEvent.x ,ev.originalEvent.y);
                                return false;
                        
                            });
                        
                        });
                        </script>
                        

                        【讨论】:

                        • "yikes"?,有效,无效,有用,没用,...? , 我英语不好
                        • @hunter 我如何多次为您的评论点赞?
                        【解决方案18】:

                        我实现了这个,我想它会做的。

                        $(document).ready(function() {
                            $("form").submit(function() { 
                        
                            var val = $("input[type=submit][clicked=true]").val()
                        
                            // DO WORK
                        
                        });
                        

                        这是设置它的提交按钮事件

                        $("form input[type=submit]").click(function() {
                            $("input[type=submit]", $(this).parents("form")).removeAttr("clicked");
                            $(this).attr("clicked", "true");
                        });
                        

                        感谢您的回复,但这并不是非常不雅......

                        【讨论】:

                        • 不支持跨浏览器/多个提交按钮。
                        • 是否保证在表单提交事件之前触发点击事件?我建议给表单一个doNotSubmit 类,在提交函数中检查该类是否不存在(否则不要提交),在点击事件中删除表单类doNotSubmit 并执行 $('' .myForm').trigger('提交');将提交按钮值添加为隐藏字段后
                        • @Hafenkranich 在 Chrome 上的一些极少数情况下,点击事件会在提交事件之后触发。
                        • @roamnoza 这正是我遇到的。
                        • @j4k3 有更好的解决方案吗?这个答案8岁了
                        【解决方案19】:

                        根据this link,Event 对象包含一个字段Event.target,其中:

                        返回一个字符串,表示启动事件的对象。

                        我刚刚创建了一个页面来测试该值是什么,并且该表示似乎是针对表单本身,而不是针对单击的按钮。换句话说,Javascript 不提供确定点击按钮的功能。

                        就 Dave Anderson 的 solution 而言,在使用之前在多个浏览器中测试它可能是个好主意。有可能它可以正常工作,但我不能说任何一种方式。

                        【讨论】:

                        • target 返回整个表单。因此不幸的是,检测正确的提交按钮没有帮助。
                        • @Hafenkranich 在我的回答中说了这么多。
                        • Event.target 不是字符串。这是一个EventTarget 对象,在本例中就是提交的表单本身。
                        【解决方案20】:

                        jQuery 似乎没有在提交事件中提供该数据。看起来你提出的方法是你最好的选择。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2019-12-11
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多