Рельсы с турбинками Javascript корректно загружается только при обновлении страницы

После освоения Michael Hartls Rails Tutorial я пытаюсь написать свое первое приложение ROR 5. Прямо сейчас я пытаюсь реализовать JavaScript на странице внутри моего приложения. Javascript отображает время внутри html и отображает коэффициент (в зависимости от времени) внутри формы, который вычисляет инсулин для заданного (съеденного) количества углеводов, когда он загружен.

Это файл Javascript bolus_rechner.js:

//Standard Data for a 3 Year old child
let dFakTni = 0.5; 
let faKtmor = 1.3;
let faKtnoon = 0.8;
let fakTeven = 0.5;

let d = new Date();
let h = d.getHours();
let m = d.getMinutes();

let uhrZeit = function zeit() {
    if (h < 10) { h = '0' + h; }
    if (m < 10) { m = '0' + m; }
    return (h + ":" + m + " Uhr");
}

function time(){
    let uHr = document.getElementById("Uhrzeit");
    uHr.innerHTML = "Es ist " + uhrZeit() + ".";
}
// Displaying the Timebased carbohydrate Faktor (BE-Faktor) and the actual time inside the form and htmluhrzeit document.addEventListener("turbolinks:load", 
function timeFakt() {

    time();

    let beFaktor = document.getElementById("faktor");
    if (h > 20 || h < 6) {
     beFaktor.value = dFakTni;

    }
    else if (h >= 6 && h < 11) {
     beFaktor.value = faKtmor;

    }

    else if (h >= 11 && h < 18) {
     beFaktor.value = faKtnoon;

    }
    else if (h >= 18 && h <= 20) {
        beFaktor.value = fakTeven;

 }

};
document.addEventListener("turbolinks:load", timeFakt);

// Possibiltiy to change the carbohydrate factor (BE Faktor)

function faktorAendern() {
    let beFaktor = document.getElementById("faktor");

    if (h > 20 || h < 6) {

     dFakTni = beFaktor.value;
    }
    else if (h >= 6 && h < 11) {

        faKtmor = beFaktor.value;
    }

    else if (h >= 11 && h < 18) {

        faKtnoon = beFaktor.value;
    }
    else if (h >= 18 && h <= 20) {

        fakTeven = beFaktor.value;
    };


};

// Calculation of the needed insulin for the amount of carbohydrates eaten

function insulinBerechnen() {

    let eat = document.getElementById("be").value;
    let uLin = document.getElementById("insulin");
    let prod1 = (eat * dFakTni).toFixed(2);
    let prod2 = (eat * faKtmor).toFixed(2);
    let prod3 = (eat * faKtnoon).toFixed(2);
    let prod4 = (eat * fakTeven).toFixed(2);

    if (h > 20 || h < 6) {

        uLin.innerHTML = prod1.toString();
    }
    else if (h >= 6 && h < 11) {

        uLin.innerHTML = prod2.toString();
    }

    else if (h >= 11 && h < 18) {

        uLin.innerHTML = prod3.toString();
    }
    else if (h >= 18 && h <= 20) {

        uLin.innerHTML = prod4.toString();
    };

};

Это HTML: application.html.erb:

<html>
  <head>
   <title><%= full_title(yield(:title)) %></title>
    <%= render 'layouts/rails_default' %>
    <%= render 'layouts/shim' %>
  </head>
  <body>
  <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= render 'layouts/footer' %> 
      <%= debug(params) if Rails.env.development? %>     
    </div>
  </body>
</html>

bolus.html.erb:

<% provide(:title, "Bolus Rechner") %>



<body>

            <h1 class="text-center">My Diabetes Diary</h1>



            <h2 class="text-center">Bolus Rechner</h1>
            <h4 class="text-center text-muted" id="Uhrzeit"></h4>





      <div class="container">
  <form>
    <div class="form-group row top buffer">

      <label for="be" class="offset-sm-4 col-sm-2 col-form-label text-left">gegessene BE</label>
      <div class="col-sm-1">
        <input type="number" class="form-control" id="be" name="be">
        <!--<small id="be-info" class="form-text text-muted">
              (Hier können Sie die gegessenen Kohlenhydrate in Broteinheiten eingeben.) 
        </small>-->
      </div>
    </div>
    <div class="form-group row">
      <label for="faktor" class="offset-sm-4 col-sm-2 col-form-label">BE-Faktor</label>
      <div class="col-sm-1">
        <input type="number" class="form-control" id="faktor" name="faktor" value="">
        <!--<small id="faktor" class="form-text text-muted">
                (Hier können Sie den aktuellen BE-Faktor ändern, wenn nötig.) 
        </small>-->
        </div>
        <div class="col-sm-1">
              <button class="btn btn-sm btn-danger" type="button" onclick="faktorAendern()">ändern</button>

      </div>
    </div>
    <div class="row">
      <div class= "offset-sm-5 col-sm2 ">
        <button type="button" class="btn btn-primary btn-md" onclick="insulinBerechnen()">Insulin berechnen</button>
      </div>
      </div>
     <div class="row top-buffer"> 
      <div class="offset-sm-4 col-sm-4 lead bg-warning">

              Sie müssen <strong id="insulin"></strong> U (Insulineinheiten) spritzen

      </div>
      </div>
      </div>
  </form>
  </body>
  <head><%= javascript_include_tag "Bolus_Rechner"%></head>

Это заголовок _header.html.erb:

<header>
      <nav class="navbar navbar-toggleable-sm navbar-inverse bg-inverse fixed-top">

      <a class="navbar-brand" href="#">My Diabetes Diary</a>


        <ul class="navbar-nav navbar-right">
          <li class="nav-item">
            <%= link_to "Home",   root_path, :class => "nav-link" %>
          </li>
          <li class="nav-item">
            <%= link_to "Help",   static_pages_help_path, :class => "nav-link"%>
          </li>
          <li class="nav-item">
            <%= link_to "About",  static_pages_about_path, :class => "nav-link"  %>
          </li>
          <li class="nav-item">
            <%= link_to "Bolus Rechner",  static_pages_bolus_path, :class => "nav-link" %>
          </li>
        </ul>

     </nav>
</header>

Это частичное _rails_default.html.erb rails_default:

<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all',
                                          'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'%>
<%= render 'layouts/shim' %>

Моя проблема (ы):

1) При использовании турболинков: загрузка в качестве триггера событий, когда я обновляю страницу, все работает нормально. Когда я нажимаю ссылку "Болюс" внутри заголовка, она работает нормально в первый раз. Каждый раз, когда я нажимаю на ссылку болюса, ноль (0) добавляется к innerhtml "Uhrzeit" из-за моей функции zeit(). Я понимаю, что это потому, что turbolinks обналичивает первый обработанный файл bolus.html и просто добавляет дополнительный ноль к уже рассчитанному времени каждый раз, когда я нажимаю на ссылку. Кто-нибудь знает, как я могу помешать турболинкам делать это.

2) Ноль (0) добавляется к дисплею времени каждый раз, когда я загружаю другую страницу / действие из моего приложения. Как сделать так, чтобы рельсы / турболинки не делали этого, и убедитесь, что файл bolus_rechner.js загружается только тогда, когда я нажимаю ссылку на путь болюса.

Заранее благодарю за помощь

1 ответ

Решение

Я нашел решение. Проблемой был JavaScript(bolus_rechner.js), в частности, назначение функции для отображения времени в глобальной переменной. При использовании turbolinks JS кэшируется в глобальном пространстве имен веб-сайта / приложения, и каждый раз, когда другой сайт приложения загружает, сценарий выполняется из-за прослушивателя событий с turbolinks:load. Функция zeit() и ее возвращаемое значение присваиваются uhrZeit. uhrZeit() выполняется time(), а timefakt().

let uhrZeit = function zeit() {
    if (h < 10) { h = '0' + h; }
    if (m < 10) { m = '0' + m; }
    return (h + ":" + m + " Uhr");
}

Это означает, что когда сценарий выполняется в первый раз, а фактическое время составляет 8 ч 7 м, время отображается как 08:07. При следующем вызове сайта приложения 8 и 7 соответственно снова сравниваются с десятью, и он все равно меньше десяти. Затем к возвращаемой строке добавляется еще один ноль и так далее. Также есть многочисленные ошибки, потому что на сайтах, отличных от bolus.html.erb, html-элементы с соответствующими идентификаторами не существуют, что приводит к многочисленным ошибкам ссылок и типов.

Решение состоит в том, чтобы исключить глобальные переменные и создать время с помощью вспомогательных функций и использовать их внутри других функций.

Новый скрипт выглядит так:

function currentMinutes(){
    let date = new Date();
    return date.getMinutes();
}
function currentHours(){
    let date = new Date();
    return date.getHours();
}
function time() {
    let hours = currentHours()
    let minutes = currentMinutes()
    if (hours < 10) { hours = '0' + hours; }
    if (minutes < 10) { minutes = '0' + minutes; }
    return (hours + ":" + minutes + "Uhr");
}

function showTime(){
    let uHr = document.getElementById("Uhrzeit");
    //checking if the id exists on the page
    if (uHr === null){return}
    uHr.innerHTML = "Es ist " + time() + ".";
}
// Displaying the Timebased carbohydrate Faktor (BE-Faktor) and the actual time inside the form and html
function timeFakt() {
    showTime();
    let hours = currentHours()
    let beFactorNight = 0.5; 
    let beFactorMorning = 1.3;
    let beFactorNoon = 0.8;
    let beFactorEvening = 0.5;

    let beFactor = document.getElementById("faktor");
    //checking if the id exists on the page
    if (beFactor === null){return}
    if (hours > 20 || hours < 6) {
     beFactor.value = beFactorNight;

    }
    else if (hours >= 6 && hours < 11) {
     beFactor.value = beFactorMorning;

    }

    else if (hours >= 11 && hours < 18) {
     beFactor.value = beFactorNoon;

    }
    else if (hours >= 18 && hours <= 20) {
        beFactor.value = beFactorEvening;

 }

};
document.addEventListener("turbolinks:load", timeFakt);

// Calculation of the needed insulin for the amount of carbohydrates eaten

function insulinBerechnen() {
    //Form validation and checking if the ids exist on the page
    let eat = document.getElementById("be").value;
    if( eat <= 0){
        alert("If the carbs you ate are zero or below you don't need any insulin"); 
        return};
    let beFaktor = document.getElementById("faktor");
    if (beFaktor === null){return};
    if( beFaktor.value <= 0){
        alert("Enter a Valid factor bigger than 0"); 
        return};

    let uLin = document.getElementById("insulin");

    //calculating the Insulin according to the time of day
    let hours = currentHours()
    if (hours > 20 || hours < 6) {
        if (beFaktor.value === ""){beFactorNight = 0.5}
        else {beFactorNight = beFaktor.value};
        uLin.innerHTML = (eat * beFactorNight).toFixed(2).toString();
    }
    else if (hours >= 6 && hours < 11) {
        if (beFaktor.value === ""){beFactorMorning = 1.3}
        else {beFactorMorning = beFaktor.value};
        uLin.innerHTML = (eat * beFactorMorning).toFixed(2).toString();
    }

    else if (hours >= 11 && hours < 18) {
        if (beFaktor.value === ""){beFactorNoon = 0.8}
        else {beFactorNoon = beFaktor.value};
        uLin.innerHTML = (eat * beFactorNoon).toFixed(2).toString();
    }
    else if (hours >= 18 && hours <= 20) {
        if (beFaktor.value === ""){beFactorEvening = 0.8}
        else {beFactorEvening = beFaktor.value};
        uLin.innerHTML = (eat * beFactorEvening).toFixed(2).toString();
    };

};

Я также добавил вид проверки формы для проверки значений 0 и ниже. Это была тяжелая работа, но я извлек из нее важный урок.
Возможно, этот пост может помочь другим начинающим программистам решить их проблемы с Javascript с помощью turbolinks и лучше понять, как JavaScript работает в контексте приложения RoR5.
Ура Себастьян

Другие вопросы по тегам