Occasionally, altering the visibility of an element right before submitting a form in Safari may not be effective

Below is the HTML element I'm using to show a loading spinner in my app, with mostly Bootstrap classes:

<div id="loadSpinner" class="overlay d-flex justify-content-center invisible">
  ...
</div>

Here is the form on view (Rails 6):

  <%= form_with(url: result_path, 
      method: "patch", local: true) do |f| %>

    ...

    <%= f.submit "Finish", class: "btn btn-success btn-lg my-3",
        onclick: "finish();" %>

  <% end %>

Here's the JavaScript function 'finish()' where we display the loading spinner:

function finish() {
  ...
  document.querySelector('#loadSpinner').classList.remove('invisible');
}

Everything works smoothly in Chrome and Firefox, but sometimes the spinner fails to appear in Safari.

I've checked with console logs (

console.log(document.querySelector('#loadSpinner'))
) and confirmed that the 'invisible' class is indeed removed before submission. The JavaScript is functioning correctly, yet the spinner is not visible in Safari.

I even tried adding a 'visible' class after removing 'invisible', but the issue persists.

Does anyone have insight into why this might be happening specifically in Safari?

My theory is that perhaps the submission occurs before the 'invisible' class is fully removed, but I'm unsure how to verify and address it.

Answer №1

When utilizing Rails UJS, you have the option to leverage the ajax:beforeSend and ajax:complete events for toggling a spinner:

<%= form_with(url: result_path, method: "patch", remote: true, class: 'spinner-form') do |f| %>
let form = document.querySelector('#myForm');
let spinner = document.querySelector('#loadSpinner');

document.addEventListener('ajax:beforeSend', (event)=>{
  if (!event.target.matches('.spinner-form)) return;
  spinner.classList.remove('invisible');
});

document.addEventListener('ajax:complete', (event)=>{
  if (!event.target.matches('.spinner-form)) return;
  spinner.classList.add('invisible');
});

If you're customizing it yourself, make sure to prevent the default event handler:

<%= f.submit "Finish", class: "btn btn-success btn-lg my-3",
        id: "myButton" %>
let btn = document.querySelector('#myButton');
let spinner = document.querySelector('#loadSpinner');

btn.addEventListener('click', (event)=>{
  let form = event.target.form;
  event.preventDefault();
  spinner.classList.add('invisible');

  fetch(form.action)
    .then((response)=>{
       spinner.classList.remove('invisible');
     });
});

In case this is not an XHR (ajax) request, remember that script execution stops upon page reload.

Answer №2

It appears that Safari requires a slight delay before submitting a form.

To address this issue, try the following solution:

  1. Modify the submit button to a simple button within the form:
<%= form_with(url: result_path, 
    method: "patch", local: true) do |f| %>

...
    
<%= button_tag "Finish", type: "button",
          class: "btn btn-success btn-lg my-3",
          onclick: "finish();" %>

<% end %>
  1. Introduce a slight delay when submitting the data:
function finish() {
  ...
  document.querySelector('#loadSpinner').classList.remove('invisible');
  
  // submit form
  setTimeout(function() {
    document.querySelector('form').submit();
  }, 300);  
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you retrieve command line variables within your code by utilizing npm script in webpack?

I'm trying to access command line parameters from an npm script in my "constants.js" file. While I have been able to access parameters in the webpack.config.js file using process.env, it seems to be undefined in my app source files. The scenario con ...

Using Selenium to trigger a click event on an ng-click directive in AngularJS is not functioning properly

I am currently trying to confirm that a specific external function is being called when an ng-click event occurs. The code for the input declaration is shown below. While everything seems to be functioning properly in browsers, I am encountering issues dur ...

What is the best way to ensure a jQuery function runs on duplicated elements?

I have been attempting to construct a webpage featuring cascading dropdowns using jQuery. The goal is to generate a duplicate set of dropdowns when the last dropdown in the current set is altered. I aim for this process to repeat up to 10 times, but I cons ...

How can I efficiently map an array based on multiple other arrays in JavaScript/TypeScript using ES6(7) without nested loops?

I am dealing with 2 arrays: const history = [ { type: 'change', old: 1, new: 2 }, { type: 'change', old: 3, new: 4 }, ]; const contents = [ { id: 1, info: 'infor1' }, { id: 2, info: 'infor2' }, { id: ...

Apply a Fade In transition to the ul li elements following a JavaScript toggle

I'm currently experimenting with implementing a Fade in from the right animation for the links displayed in the menu after toggling the menu body in the browser. Despite my efforts, I am unable to determine why the animation is not functioning as expe ...

Trigger a child-mounted event and retrieve it from the parent component

Imagine I have a component named child. There is some data stored there that I need to retrieve in the parent component. To accomplish this, I plan to emit an event in the childs mount using this.$emit('get-data', this.data), and then receive it ...

The :before element is not displaying when using jQuery's slideToggle() method

When using only CSS, the .nav-main:before{} element is displayed, but with jQuery, it does not toggle that element and always keeps it hidden. Disclaimer: This issue has been observed on mobile devices (tested in Android Chrome). jQuery $('.menu-to ...

Using R plotly to show an image when hovering over a location on a map

After successfully implementing the technique of displaying an image on hover in a regular R plotly chart, I encountered issues when trying to apply the same method to a plotly map. Specifically, the approach broke down and failed to display the image. Can ...

Strings holding special arrangements of breaks in between

Currently, I am developing a portal that enables examiners to provide a problem statement, sample input, and sample output. However, I am facing an issue where the sample input/output values are stored as complete strings, causing line breaks to not render ...

Tracking progress for uploading big files

I've implemented a unique progress "Donut" for tracking uploads. It functions similarly to a horizontal progress bar, but in a circular format. While it works well for most file sizes, I have noticed that when uploading larger files, such as 200GB, th ...

What is preventing Angular's $scope from being modified?

Recently, I decided to delve into the world of AngularJS. During my first tutorial sessions, I attempted to rename the $scope variable and quickly realized that it caused everything to break. phonecatApp.controller('PhoneListCtrl', function($sco ...

(Angular) Employing *ngFor directive for populating a table

I am in need of a table structure that resembles the following: https://i.sstatic.net/rB2C6.png To achieve this, I am utilizing a basic Bootstrap table along with Angular's *ngFor. Each cell in the table should display a different name from an array ...

Searching for substrings in NodeJS using Express

In this code snippet, I am using Express JS and AES256 encryption to encode and decode simple text strings with a predefined key. The Express JS web server is set up to display specific elements based on the URL content. For instance, if the URL was abc. ...

Error encountered: Unable to access the 'Lastname' property as it is undefined

Even though the console displays the value of $("#surname").val(), I am still encountering an error. Could it be that the script is executing before the form is dynamically built? $(function () { $("#addEmployeForm").submit(function (event) { ...

When accessing tagName in Internet Explorer 11, the name will be returned in uppercase with the namespace included. However, in Internet Explorer 7,

My goal is to extract all child elements within a DOM element with a specific tag name and store them in an array. <xs:menu> <xs:submenu> </xs:submenu> </xs:menu> var item=menu.children.tags("XS:SUBMENU") ; Internet Explorer 7 ...

How to eliminate certain elements from the DOM in Angular 5

I'm facing a minor issue in my Angular/Typescript project that I can't seem to resolve. I am still new to these technologies and struggling with removing certain DOM elements. The content is auto-generated with specific CSS classes, and unfortuna ...

Comparison between WAMP and Live server integration with Facebook for connecting applications

I've been facing some challenges while integrating my website with Facebook Connect. I have been following the instructions provided in this guide. When attempting to run the following code from localhost, please note that for security reasons, my ap ...

Tips for partitioning an element using Selenium and Appium when it lacks a distinctive ID, class, package, or resource identifier:

I am currently trying to determine if I am receiving the expected response from a text message. In order to do this, I need to access the text view of the incoming message. The challenge I am facing is how to distinguish between the received text and the s ...

Dependency management in ReactJS components

I am grappling with the optimal structure for a React component that is composed of other components. Let's look at the first example: <ColorSelect id="color" label={this.state.selectLabel} trigger={{ color: "lime", text: "Lime"}} onPropagateCli ...

Discover results while inputting in the search box

Can anyone assist me? I'm looking to enhance my current code by adding a search functionality to the ul list. I want users to be able to type in a search term and have the matches automatically highlighted as they type, similar to a "find-as-you-type ...