Ensure jquery is activated

In your function that hooks “wp_enqueue_scripts”, add this:

//********** ENSURE jQuery IS ALWAYS LOADED ON PAGES **********
//(we use in our custom code)
add_action( 'wp_enqueue_scripts', 'MyThemeEnqueueScripts' );
function MyThemeEnqueueScripts()
{
  wp_enqueue_script( 'jquery' );
}
add_action( 'admin_enqueue_scripts', 'MyAdminEnqueueScripts' );
function MyAdminEnqueueScripts( $hook )
{
  wp_enqueue_script( 'jquery' );
}

A working example

In functions.php
//**************************************************
//**************************************************
//********** AJAX CALLBACK - MY TEST PAGE **********
//**************************************************
//**************************************************
add_action ( 'wp_ajax_my_test_page_ajax_action_callback', 'my_test_page_ajax_action_callback' );        //For AJAX calls made for logged in users  <<<For namespaces use: '\MyNamespaceName\my_test_page_ajax_action_callback
add_action ( 'wp_ajax_nopriv_my_test_page_ajax_action_callback', 'my_test_page_ajax_action_callback' ); //For AJAX calls made from non logged in users   (include both if both logged in and not logged in users will trigger this)<<<For namespaces use: '\MyNamespaceName\my_test_page_ajax_action_callback
function my_test_page_ajax_action_callback()
{  
  
  //Check the nonce
  check_ajax_referer('my-nonce-special-string', 'security');      //This will die(); if the nonce check fails
  
  //if (!is_user_logged_in())
  //  die();
  
  $MyRequestField1 = '';
  if (isset($_POST['MyRequestField1']))
    $MyRequestField1 = sanitize_text_field($_POST['MyRequestField1']);
  
  $MyRequestField2 = '';
  if (isset($_POST['MyRequestField2']))
    $MyRequestField2 = sanitize_text_field($_POST['MyRequestField2']);

  //<<<Do your handling of the request here...
  
  $MyReturnField1 = "Hi there ($MyRequestField1-$MyRequestField2)";  
  
  $ReturnArray = array(
                  "MyReturnField1" => $MyReturnField1
                  );
  echo json_encode($ReturnArray);

  wp_die();     //Terminate immediately and return a proper response
}
In your HTML
  //----- DO THE AJAX BACKGROUND CHECK -----
  //Ajax call is handled in: functions.php
  $AjaxUrlHtml = "var ajaxurl = '" . admin_url('admin-ajax.php') . "';";
  $AjaxNonce = wp_create_nonce( 'my-nonce-special-string' );
  
  $MyField1Value = "Test string";
  
  $MaxPageAgeMs = (60 * 1000);
    
  $HtmlOutput .= <<<_END
  <script>
    $AjaxUrlHtml

    const PAGE_ACTIVE_DO_AJAX_CHECK_EVERY_SECS = 3;   //<<<How often to fire an ajax check
    
    var DoAjaxCheckEverySecs = PAGE_ACTIVE_DO_AJAX_CHECK_EVERY_SECS;
    var DoAjaxCheckEveryCounter = 0;
    var NumOfChecksCounter = 0;
    var PageFirstLoaded = new Date().getTime();
    
    var MyField2Value = 123;  //<< A JS variable you can pass example

    //----- DO AJAX CALL -----
    setInterval(function()
    {
      //Here every 1000mS      
      DoAjaxCheckEveryCounter++;
      if (DoAjaxCheckEveryCounter >= DoAjaxCheckEverySecs)
      {
        DoAjaxCheckEveryCounter = 0;
        
        var post_data = {
                   'action': 'my_test_page_ajax_action_callback',   //<<The name of the ajax callback action in functions.php
                   'security': '$AjaxNonce',                        //<<<<DELETE LINE IF NOT USING NONCE
                   'MyRequestField1': '$MyField1Value',
                   'MyRequestField2': MyField2Value
        };
        jQuery.post(ajaxurl, post_data, function(response) {
          //----- CALLBACK SUCCESS - RESPONSE RECEVIED -----
          response = jQuery.parseJSON(response);     //Decode the json response
          
          var MyReturnField1 = response.MyReturnField1;
          
          NumOfChecksCounter++;
          
          
          document.getElementById( 'ajax_value1' ).innerHTML = 'Response: ' + MyReturnField1 + ', number of checks made: ' + NumOfChecksCounter;
          
        });
        
      }
    }, 1000);		 //<<<<Call every time in mS
  </script>
  
  <style>
  #MyWaitingAnimatedIcon {
    border: 6px solid #f3f3f3;
    border-radius: 50%;
    border-top: 6px solid #777777;
    width: 40px;
    height: 40px;
    -webkit-animation: animated_icon_spin 2s linear infinite; /* Safari */
    animation: animated_icon_spin 2s linear infinite;

    margin-top: 10px;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 10px;
  }
  @-webkit-keyframes animated_icon_spin {
    0% { -webkit-transform: rotate(0deg); }
    100% { -webkit-transform: rotate(360deg); }
  }
  @keyframes animated_icon_spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  </style>

  <div id="MyWaitingAnimatedIcon"></div>
  <p style="text-align:center;"><span id='ajax_value1'>Connecting...</span></p>
  
_END;