3

Original Post

My custom dashboard has buttons that contain both a Font Awesome icon and a text description of the button or form action. I have a problem with my forms and buttons that a form doesn't submit upon clicking on a font awesome icon within a button that has a jQuery click event. I could use some help figuring out what I'm doing incorrectly.

In this image example, there is a font awesome magnifying glass "search" icon, followed by the text "Search".

In this image example, there is a font awesome magnifying glass "search" icon, followed by the text "Search".

If I click anywhere on the button, my jQuery works correctly by replacing the inner HTML of the button with the font awesome icon spinner icon and with text "Searching ...". If I click directly on the font awesome icon, the form does not submit. If I click anywhere else on the button aside from the font awesome icon, the form submits properly. If I remove my jQuery click() functions that replace the innerHTML when buttons are clicked, the form submits properly even when the font awesome icon is directly clicked. It has something to do with the jquery click html code but I'm not sure what I'm doing incorrectly.

What am I doing wrong with my jQuery that's causing the form to not submit when the font awesome icon is clicked within the button?

This image shows that the jQuery correctly replaced the inner HTML of the button, but the form doesn't submit when the font awesome icon is clicked on directly. The form only submits when the button is clicked anywhere else except for directly on the font awesome icon.

This image shows that the jQuery correctly replaced the inner HTML of the button, but the form doesn't submit when the font awesome icon is clicked on directly. The form only submits when the button is clicked anywhere else except for directly on the font awesome icon.

Here's my jQuery and HTML for this Search button

$(document).ready(function() {
  $('#search-btn').click(function() { 
    $(this).html('<i class="fas fa-spinner fa-spin gap-right"></i> Searching ...'); 
  });
  //$('#search-btn').click(function() { $('#search-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Searching ...'); });
});
<link href="https://fontawesome.com/v4.7.0/assets/font-awesome/css/font-awesome.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="submit" id="search-btn" name="search" value="Search" class="btn btn-primary gap-right"><i class="fas fa-search gap-right"></i> Search</button>

Any advice would be greatly appreciated. If more information or clarification is needed, please let me know and I will update. Thanks.

Update 1/6/2020

Example: https://www.seibertron.com/dashboard/test/button-problem-public.php

The issue in the above example is with the "search" button. If you click on the right side of the button, it works as expected (with a spinner icon and changing the text from "Search" to "Searching ..."). If you click on the font-awesome magnifying glass icon on the left side of the Search button, it does not submit. The reset button works in the example because it's just using traditional javascript to redirect the user and is not submitting a form. Thank you in advance for taking a look at this issue!


Update and Resolution 1/6/2020

Thanks to fyrye, I took his suggestion and modified my buttons.js jQuery file to the following, which worked for my custom Inspinia dashboard. In addition, while I was researching this issue last night, I came across an alternate solution that is built into Bootstrap which might work for other users wishing to add this functionality to their code: How to add a spinner icon to button when it's in the Loading state?

Happy coding!

$(document).ready(function(){
  $('form').on('submit', function(e) {
    $(this).find('#test-search-btn').html('<i class="fa fas fa-spinner fa-spin gap-right"/> Searching...');
    $(this).find('#search-btn').html('<i class="fa fas fa-spinner fa-spin gap-right"/> Searching...');
    $(this).find('#add-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Adding ...');
    $(this).find('#approve-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Saving ...');
    $(this).find('#save-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Saving ...');
    $(this).find('#copy-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Copying ...');
    $(this).find('#move-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Moving ...');
    $(this).find('#upload-btn').html('<i class="fas fa-spinner fa-spin gap-right"></i> Uploading ...');
    $(this).find('#nav-refresh-btn').html('<i class="fas fa-refresh fa-lg fa-spin gap-right"></i>');
    $(this).find('#load-btn').html('<i class="fas fa-spinner fa-lg fa-spin gap-right"></i> Loading ...');
    $(this).find('#generate-btn').html('<i class="fas fa-spinner fa-lg fa-spin gap-right"></i> Generating ...');
  });

  $('#cancel-btn').click(function() { $(this).html('<i class="fas fa-spinner fa-spin gap-right"></i> Canceling ...'); });
  $('#reset-btn').click(function() { $(this).html('<i class="fas fa-spinner fa-spin gap-right"></i> Resetting ...'); });

  $('.button-save').click(function() { $(this).html('<i class="fas fa-spinner fa-spin gap-right"></i> Saving ...'); });
  $('.button-go-back').click(function() { $(this).html('<i class="fas fa-spinner fa-spin gap-right"></i> Loading ...'); });
  $('.button-sm-edit').click(function() { $(this).html('<i class="fas fa-spinner fa-spin fa-lg" title="Loading ..."></i>'); });
  $('.button-sm-delete').click(function() { $(this).html('<i class="fas fa-spinner fa-spin fa-lg" title="Deleting ..."></i>'); });
  $('.button-sm-build').click(function() { $(this).html('<i class="fas fa-spinner fa-spin fa-lg" title="Building ..."></i>'); });
  $('.button-sm-code').click(function() { $(this).html('<i class="fas fa-spinner fa-spin fa-lg" title="Generating ..."></i>'); });

  $('#navbar-toggle-btn').click(function(e) {
    $(this).html('<i class="fas fa-spinner fa-spin" title="Loading ..."></i>');
    setTimeout(
        function () {
          $('#navbar-toggle-btn').html('<i class="fas fa-bars"></i>');
        }, 500);
  });
});
Seibertron
  • 33
  • 1
  • 6
  • 2
    What are the styles for "gap-right". Could this be the issue? – Richard Lovell Jan 05 '20 at 23:35
  • I'm fairly certain this is not a CSS issue, but rather a jQuery issue, though I could be completely wrong! Either way, here is the CSS for "gap-right" per your request. .gap-right { margin-right:10px; } – Seibertron Jan 05 '20 at 23:42
  • Could you try ```.gap-right { padding-right:10px; }``` instead? – Richard Lovell Jan 05 '20 at 23:46
  • 1
    It just changed how the spinner looks because the margin is gone. The CSS shouldn't have anything to do with whether or not the form submits, which I can isolate has to do with the jQuery code if I comment out the line for this button. – Seibertron Jan 06 '20 at 00:01

2 Answers2

3

The issue is caused by the propagation of the click event being stopped, before the submit event can be dispatched. Since the source of the click event (<i class="fas fa-search">) is no longer valid, when it is removed from the DOM by using $(this).html(),

To resolve the issue you can simply change the class names of the icon element. Then wrap your text in a span to allow you to change only the text within the span.

jQuery(function($) {
    $('#search-btn').on('click', function() {
        $(this).find('.fas')
            //add the spinner icon
            .addClass('fa-spinner fa-spin')
            //remove the search icon
            .removeClass('fa-search')
            //update the text
            .next().text('Searching...');
    });
    
    /* DEMO PURPOSES ONLY - do not use below */
    $('#search-form').on('submit', function(e) {
       e.preventDefault();
       window.alert('Form submitted successfully.');
    });
    /* END DEMO PURPOSES ONLY */
});
.gap-right {
   margin-right: 10px;
}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>

<form id="search-form" action="about:blank">
  <button type="submit" id="search-btn" name="search" value="Search" class="btn btn-primary gap-right">
    <i class="fas fa fa-search gap-right"></i> 
    <span>Search</span>
  </button>
</form>

Alternatively you can monitor the submit event of the form and change the button entirely instead.

jQuery(function($) {
    $('#search-form').on('submit', function(e) {
       $(this).find('#search-btn')
           .html('<i class="fa fas fa-spinner fa-spin gap-right"/> Searching...');
       
       /* DEMO PURPOSES ONLY - do not use below */
       e.preventDefault();
       window.alert('Form submitted successfully.');
       /* END DEMO PURPOSES ONLY */
    });
});
.gap-right {
   margin-right: 10px;
}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>

<form id="search-form" action="about:blank">
  <button type="submit" id="search-btn" name="search" value="Search" class="btn btn-primary gap-right">
    <i class="fas fa fa-search gap-right"></i> Search
  </button>
</form>

In all of the snippets, I disabled the actual form submission, otherwise you would not see the button change. Be sure to not use the JavaScript below DEMO PURPOSES ONLY
Since a CDN of fontawesome 5 is not available without registering, I used the fontawesome 4 CDN and the fa class name to generate the icons.

Will B.
  • 17,883
  • 4
  • 67
  • 69
  • I think this is heading in the right direction, fyrye. I'll look into this more tomorrow to see if I can devise a solution from what you posted. Your post resolved the "why" the button isn't working when you click on the font awesome icon (i think). Will look into it further tomorrow. – Seibertron Jan 06 '20 at 06:35
  • Tried this out and ended up with the same problem. Icon and text (wrapped with a span) worked just fine, just like it was before, but the same problem persists where the form doesn't submit when the icon is clicked, only when the button is clicked. I'm currently working on providing an example for you guys to see the code in full. – Seibertron Jan 06 '20 at 15:35
  • @Seibertron Please update your question with the javascript you used or provide me with a https://jsfiddle.net link with it. – Will B. Jan 06 '20 at 15:38
  • Here's a test page: https://www.seibertron.com/dashboard/test/button-problem-public.php Please note that the issue in the example I provided is with the "search" button. If you click on the right side of the button, it works. If you click on the font-awesome magnifying glass icon on the left side of the Search button, it does not submit. The reset button works because it's just using traditional javascript to redirect the user. Thank you in advance for your help. I appreciate it. – Seibertron Jan 06 '20 at 16:16
  • 1
    @Seibertron I took the liberty of injecting a script on to your site https://pastebin.com/MdDf3gCF, and my code appears to resolve the issue. [Watch Video](https://drive.google.com/file/d/1FCibPhLrFDl6qghqYQwV8bf145loTwTF/view) To use it open dev tools in your browser F12 click Console. then paste `var script = document.createElement('script'); script.type='text/javascript'; script.async=true; script.onload=function(){ window.alert('Loaded') }; script.src="https://pastebin.com/raw/MdDf3gCF"; document.body.appendChild(script);` press enter to execute. – Will B. Jan 06 '20 at 18:28
  • I was able to get your 2nd alternative method to work. Maybe I did something incorrect with your first method. Working on testing and cleaning up my code to work with my system and all of the other instances that use this code in my dashboard. Will post back momentarily. I will also take a look at the example you provided to see how you implemented it. – Seibertron Jan 06 '20 at 19:15
  • Ok, I got it working! Thanks fyrye. How do I accept your answer as the one that worked for me? – Seibertron Jan 06 '20 at 19:50
  • You can accept answers on stack overflow by clicking the check box at the top left of the answer and optional also up vote to award additional points. – Will B. Jan 06 '20 at 19:51
  • I ended up using a combination of fyrye's solution with my original code in my actual file. In some instances of my dashboard, I needed to add or change the button type to "button" in order for it to work properly (which was suggested elsewhere in the comments). – Seibertron Jan 06 '20 at 19:53
  • Great. Thanks for your help. This problem has plagued my dashboard for the past couple of years. I appreciate your assistance, fyrye. Should I update my initial post to include the code that I ended up using so that it stays here for public viewing after I delete my test code example? – Seibertron Jan 06 '20 at 19:55
  • @Seibertron I am still curious as to how you adapted the first method I provided and if the icon clicking issue was affecting other buttons. As that approach should work in all instances as I demonstrated in the video. But yes, you can optionally edit your question to reflect what you ended up using. – Will B. Jan 06 '20 at 19:59
2

So basically you need

  1. Change the type from submit to button.
  2. Change the icon by adding and removing class.
  3. Submit the form programmatically after a while.

So your code can be something like that:

$(document).ready(function(){
 $('#search-btn').on('click', function() {
     $(this).find('.fa').addClass('fa-spinner fa-spin').removeClass('fa-search'); // change icon
        setInterval(function(){ document.querySelector('#demo').submit(); }, 2000); // submit the form after two seconds
   });    
});
.gap-right {margin-right: 10px;}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form id="demo">
  <button type="button" id="search-btn" name="search" value="Search" class="btn btn-primary gap-right"><i class="fa fa-search gap-right"></i> Search</button>
</form>

Note: this demo usets FA v4* so i changed .fas to .fa in order for it to work.

Note 2: Many thanks to @fyrye.


This is the old answer that works BUT effects html5 validation since it use preventDefault() method. You can read more about it here - basically you should avoid prevent the default behavior of the browser unless it a must.

$(document).ready(function(){
  $('#search-btn').click(function(e) { 
    e.preventDefault();   //  cancel submit action
    $(this).html('<i class="fa fa-spinner fa-spin gap-right"></i> Searching ...');  // change text
    setInterval(function(){ document.forms[0].submit(); }, 2000); // submit after two seconds
  });    
});
.gap-right {margin-right: 10px;}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form name="demo">
  <button type="submit" id="search-btn" name="search" value="Search" class="btn btn-primary gap-right"><i class="fa fa-search gap-right"></i> Search</button>
</form>
isherwood
  • 58,414
  • 16
  • 114
  • 157
A. Meshu
  • 4,053
  • 2
  • 20
  • 34
  • 1
    This is needed because the `click` event is fired prior to the `submit` event. Once the html is replaced, the propagation to the `submit` event is stopped, as the source of the `click` event is no longer valid You can also circumvent this by using `$(this).find('.fas').addClass('fa-spinner fa-spn').removeClass('fa-search');` instead of `e.preventDefault` and `$(this).html()`, and removing the `setInterval()`. – Will B. Jan 06 '20 at 00:15
  • @fyrye if you don't prevent the default behavior the form will actually submit.. – A. Meshu Jan 06 '20 at 00:18
  • I'm sorry but i can't see any difference on your fiddle. i guess it's my bed time... – A. Meshu Jan 06 '20 at 00:38
  • You are right!! thank you for that. Please answer this cause it will be plagiarism if i would edit with your code (: – A. Meshu Jan 06 '20 at 01:04
  • @fyrye i guess since i do my Validation server-side i never thought that it effects the html5 validation... – A. Meshu Jan 06 '20 at 01:06
  • 1
    Sorry misunderstanding, using `setInterval( element.submit() )` or otherwise using javascript to submit the form will prevent the HTML5 validation from occurring, unless it is invoked manually, and introduces some strange side-effects. Also it is not needed when just changing the class names of the element which resolves the issue So all that is needed in the click event is one line `$(this).find('.fa').addClass('fa-spinner fa-spin').removeClass('fa-search'); // change icon` or `$(this).find('.fas')` for the OPs fontawesome 5 code. – Will B. Jan 06 '20 at 01:49
  • I'm not sure which of these answers, if any, are correct. I will probably set up a demo outside of my dashboard so that all of you can actually see it. It'd be less work than figuring out how to setup a snippet without my various jquery files. I see what all of you are getting at, and since my original post, I found that bootstrap has something a little less elegant (or at least it is for the system that I built) already built into it via "data-loading-text". – Seibertron Jan 06 '20 at 06:30
  • What I don't understand is why it works when button is clicked anywhere other than directly on font awesome icon. If you click anywhere else on the button, the icon and text changes to show to the user that something is happening, and then the form submits, exactly as I want it to work. However, if you click on the font awesome icon, the form doesn't submit, but the icon and text does change. I would really like to understand why that is the case, but I'm assuming I will need to provide a fully working example that demonstrates this issue to help everyone better understand what's going on. – Seibertron Jan 06 '20 at 06:31
  • I updated my original post to provide an example of the problem. Thanks in advance for your help. – Seibertron Jan 06 '20 at 16:19
  • Just wanted to thank A. Meshu for suggesting that I change the button type from "submit" to "button". The button for the search button actually needed to stay as a type="submit", but changing it to "button" was helpful in other areas in my dashboard (such as the edit and delete buttons for pages with multiple records). This was the solution in the case of the edit and delete buttons whereas fyrye's solution resolved the problem with the buttons in other forms. – Seibertron Jan 06 '20 at 20:06
  • @Seibertron glad i could help! (: – A. Meshu Jan 06 '20 at 23:30