Javascript не запускается при нажатии кнопки «Назад» или пункта меню в моем приложении rails

У меня есть следующий код Javascript, содержащийся в моем файле profile.js в Rails 7:

window.addEventListener('load', function () {
  updateProfile();
})


window.onpageshow = function(event) {
  if (event.persisted) {
    window.location.reload();
  }
};

window.addEventListener('popstate', function() {
  updateProfile();
});

window.addEventListener( "pageshow", function ( event ) {
  var historyTraversal = event.persisted || 
                         ( typeof window.performance != "undefined" && 
                              window.performance.navigation.type === 2 );
  if ( historyTraversal ) {
    // Handle page restore.
    window.location.reload();
  }
});


function fileSelected() {
  // Get the selected file
  const file = document.querySelector('#fileInput').files[0];
  if (file == null){
    return 
  }

  // Create a new FileReader object
  const reader = new FileReader();

  // Set the onload event handler for the FileReader object
  reader.onload = function(event) {
    // Update the src attribute of the profile image
    document.querySelector('#profile-image').src = event.target.result;
  };

  // Read the selected file as a DataURL
  reader.readAsDataURL(file);
}

function updateProfile(){
  var toggle_switch = document.getElementById('toggle');
  var save_button = document.getElementById('save-button');

  let nameInput = document.getElementById('name');

  nameInput.addEventListener('input', function(event) {
    let error_element = document.getElementById('error-message-name');
    let regex = /^.{3,}$/; // Regex that requires at least 3 characters
  
    if (regex.test(value)) {
      // Value is valid
      error_element.classList.remove("visible-error")
      error_element.classList.add("invisible-error")
    } else {
      // Value is invalid
      error_element.classList.remove("invisible-error")
      error_element.classList.add('visible-error');
    }
  });

  toggle_switch.addEventListener('click', function() {
    if (this.getAttribute('data-type') == "influencer"){
      this.setAttribute('data-type', "vender");
      document.getElementById('profile_type').value = "vender";
    }else{
      this.setAttribute('data-type', "influencer");
      document.getElementById('profile_type').value = "influencer";
    }
  });

  save_button.addEventListener('click', function() {
    let new_name = document.getElementById('name').value;
    let new_headline = document.getElementById('headline').value;
    let new_country = document.getElementById('country').value;
    let new_city = document.getElementById('city').value;
    let new_about = document.getElementById("about").value;
    let new_profile_type = document.getElementById('toggle').getAttribute('data-type');
    let div = document.getElementById('user_id');
    let user_id = div.getAttribute('data');
    var fileInput = document.getElementById("fileInput");
    var file = fileInput.files[0];
    
    if (file == null) {
      $.ajax({ //A new image was not uploaded for change
        type: "PATCH",
        url: encodeURI('/users/' + user_id),
        beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name = "csrf-token"]').attr('content'))},
        data: { user: { profile_type: new_profile_type, name: new_name, headline: new_headline, country: new_country, city: new_city, about: new_about} },
        success: function(response) {
          console.info("Update success.")
        }
      });
    } else {
        const formData = new FormData();
        formData.append("avatar", file);

        $.ajax({
          url: encodeURI('/users/' + user_id),
          type: "PUT",
          beforeSend(xhr, options) {
            xhr.setRequestHeader('X-CSRF-Token', $('meta[name = "csrf-token"]').attr('content'));
            xhr.setRequestHeader('image-change', true);
            options.data = formData;
          },
          success: function(response) {
            console.info("Image Update success.")
          },
          error: () => {
            alert("An issue occured. Please try again.");
          }
        });

    }
  });

}

Этот код следует запускать, когда пользователь переходит на страницу моего профиля со следующим html.erb:

<head>
  <%= stylesheet_link_tag 'linked_card', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= stylesheet_link_tag 'profile_card', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= stylesheet_link_tag 'alert', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag "profile", "data": { "turbolinks-track": "reload" } %>
</head>

<header>
  <%= render partial: "layouts/header" %> 
</header>

<body class = "profile_main_body">
    <%= render partial: "layouts/profile_card", locals: { user: @user } %> 
    <br>
    <br>
    <div class = "col-md-6 mx-auto text-center">
      <h3 class = "heading-black">Link Accounts</h3>
      <p class = "text-muted lead">Click the button below to link an account to your profile. You will be redirected to the chosen service.</p>
      <a href = "<%= user_profile_path(@user.username)%>" class = "border px-3 p-1 add-experience"><i class = "fa fa-link"></i>&nbsp;Link Account</a>
    </div>
    <br>
    <br>
    <div class = "container">
        <div class = "row">
            <%= render partial: "layouts/linked_card" %>
            <%= render partial: "layouts/linked_card" %> 
        </div>
    </div>

  <br>
</body>

<footer>
  <%= render partial: "layouts/footer" %> 
</footer>

Я добавил следующую строку:

<%= javascript_include_tag "profile", "data": { "turbolinks-track": "reload" } %>

Потому что я думал, что это проблема турболинков. Ничего не изменилось, хотя с строкой выше. Могу ли я в любом случае повторно запустить мой javascript, когда пользователь нажимает на турбо-ссылку? JavaScript работает нормально при полной перезагрузке страницы. Любая помощь будет большим спасибо!

Я не использовал его много, но читая о Rails 7 при подготовке к нему, я подумал, что турболинки были заменены на Turbo и Stimulus.

Beartech 08.01.2023 21:36
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Turbolinks заменен на Turbo в Rails 7. Однако есть много совпадений в том, как вы должны думать о JS.

Turbolinks/Turbo (или почти любой фреймворк SPA в этом отношении) создает постоянный сеанс браузера между страницами. Думать в терминах «когда страница загружается, я хочу прикрепить обработчик события к X, который делает Y», возможно, было бы нормально в базовом руководстве по JS десять лет назад, но на самом деле это контрпродуктивно:

  • Это не работает, когда элементы динамически вставляются в DOM. Например, когда Turbo Drive или Turbolinks заменяют содержимое страницы. Или всякий раз, когда люди пытаются вставить контент, загруженный с помощью AJAX, в первый раз.
  • Добавление обработчиков событий непосредственно к группе элементов добавляет много накладных расходов.
  • Если вы подключитесь к такому событию, как turbolinks:change, вы можете добавить обработчик события несколько раз к одному и тому же элементу. Простое отключение события load/ready для эквивалента Turbo/Turbolinks не обязательно исправит вонючий код и может просто вызвать новые проблемы.
  • Это сломанная ментальная модель, поскольку вы строите свой JS просто «frobnob X на странице Y», вместо того, чтобы думать с точки зрения многократно используемых компонентов пользовательского интерфейса или расширять поведение элементов повторно используемым способом.

Что тогда?

Прекратите назначать идентификаторы и обработчики событий напрямую всему. Вы просто получите дублирующиеся идентификаторы и мусорный JS.

Вместо этого используйте делегирование, чтобы поймать событие, когда оно всплывет в верхней части DOM:

// Do something awesome when the user clicks buttons with class = "foo"
document.addEventHandler('click', function(event){
  let el = event.target;
  if (!el.matches('.foo')) return;

  // ...
});

Используйте классы и атрибуты для целевых элементов. Не удостоверения личности. Это не 2010 год, и запросы к DOM намного быстрее.

Используйте обход DOM и API формы для получения элементов относительно элемента, который был нажат/изменен/и т. д. Помните, что в JS функции могут принимать аргументы. Используйте атрибуты данных, если вам нужно передать дополнительную информацию из бэкэнда в ваш JS.

Это в основном то, что делает Stimulus:

<div data-controller = "hello">
  <input type = "text">
  <button>Greet</button>
</div>
// src/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    console.info("Hello, Stimulus!", this.element)
  }
}

Я знаю, что этот ответ на самом деле не касается кода в вопросе. Но вам, скорее всего, даже не нужен этот код. ActiveStorage имеет компонент JS для загрузки файлов, что намного лучше. Вы можете справиться с отправкой формы с помощью Turbo гораздо менее запутанным способом.

max 09.01.2023 11:03

Спасибо за подробный ответ. Как именно я могу отправить форму с турбо/обработкой ошибок, как указано выше. Не могли бы вы предложить обернуть его так, чтобы он пузырился из дома, как вы упомянули выше?

James 09.01.2023 23:58

Я бы предложил отказаться от этого кода. Вам потребуется больше усилий, чтобы спасти его, чем оно того стоит.

max 10.01.2023 03:44

Смотрите hotrails.dev/turbo-rails для обучения.

max 10.01.2023 03:46

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