Атрибут data-id не отображается при добавлении на экран: элемент отсутствует - PullRequest
0 голосов
/ 11 апреля 2020

Я создаю всплывающее уведомление с bootstrap popover. Всплывающее окно имеет div для каждого уведомления, каждый из которых имеет одинаковые классы (идентичные, кроме текстового содержимого).

<% notifs.each do |notif| %>
  <div class="media n-media notif-popup-container notif-display" data-id=<%= notif.id %> >
    Content
  </div>
<% end %>

Что приводит к этому:

notif-popup

Однако, когда я нажимаю на любой из div уведомлений (на рисунке), $ (this) моего слушателя клика всегда будет ссылаться на первый div. Я знаю это, потому что, когда я печатаю идентификатор, он будет печатать идентификатор первого уведомления div, даже когда третий нажата.

Не удалось найти подобный вопрос в другом месте. Вот соответствующий код jquery. Я использую $ (body) .on ("click") вместо $ (". ClassName"). Click, так как последний не будет прикреплен к желаемому div, так как div имеет display: none, пока не появится.

$('body').on("click", ".popover-body .notif-popup-container", function() {
    console.log("notif popup container clicked");

    // prints <div class="media n-media notif-popup-container notif-display"></div> 
    console.log($(this)[0]);

    // prints {}
    console.log($(this).data());

    // prints first element's id
    console.log($('.notif-popup-container').data("id"));

    // prints undefined
    console.log($(this).data("id"));
 })

Вот код поповера. Я заметил, что атрибут data-id не отображался в chrome инструментах dev только для моего стиля = "display: none" divs. Эти элементы вставляются в параметры заголовка и содержимого всплывающего окна, поэтому их необходимо скрыть.

$(document).ready(function(){
  $("#notificationsBell").popover({
    'title' : $('.notifications-title-header').html(), // display:none for html div
    'html' : true,
    'placement' : 'left',
    'content' : $(".notifications-list").html() // display:none for this as well
  });
});

JS может дать некоторые подсказки. Сборка с Rails, но это кажется неактуальным. Любое понимание приветствуется.

Редактировать: оно не получало первый div, оно получало правильный. Он просто не сохранил атрибут data-id. Так что теперь я буду хранить его в атрибуте "id", который будет отображаться на chrome инструментах разработки. Я все еще хотел бы знать, почему data-id не отображается, а атрибут id.

Edit 2: Вот соответствующий html код:

  <%= link_to "javascript:void(0);", class: "dropdown-toggle", id: "notificationsBell" do %>
    <i class="fa fa-bell dropdown-toggle" aria-hidden="true"></i>
    <span id="notifUnreadCount">
      <%= Notification.unread_count(current_user) %>
    </span>
  <% end %>

  <div style="display:none" class="notifications-title-header" data-id="sup">
    <p class="notifications-title">
      Notifications
      <span class="see-all-notifs"><u><%= link_to "See all", notifications_path %></u></span>
    </p>
  </div>

  <div style="display:none" class="notifications-list">

    <% unread_notifications = Notification.unread_count(current_user) %>
    <% if unread_notifications === 0 %>

      No notifications to display! You are up to date.

    <% else %>
      <% notifs = current_user.notifications.where(read_at: nil).order("created_at DESC") %>
      <% notifs.each do |notif| %>

        <div class="media n-media notif-popup-container notif-display" id=<%= notif.id %> >

          <%= image_tag "bell.svg", class: "notification-icon-small mr-3" %>

          <div class="media-body noti-info">
            <b><p><%= notif.notify_type %></p></b>
            <span class="n-date trans-timestamp dateTime" data-momentiz="(<%= notif.momentize %>)"></span>
            <p><%= notif.message %></p>
          </div>

          <div class="actions">
            <% if notif.status == 'pending' && notif.target.present? %>
              <%= link_to update_request_wager_path(notif.target.try(:wager), member_id: notif.target_id, type: "accept", notif_id: notif.id), method: :put, class: "btn table-link acceptBtn red-btn-small", data: { confirm: 'Are you sure you want to accept?' } do %>
                <i class="fa fa-check" aria-hidden="true"></i>
              <% end %>
              <%= link_to update_request_wager_path(notif.target.wager, member_id: notif.target_id, type: "reject", notif_id: notif.id), method: :put,class: "btn table-link rejectBtn red-btn-small", data: { confirm: 'Are you sure you want to reject?' } do %>
                <i class="fa fa-times" aria-hidden="true"></i>
              <% end %>
            <% end %>
            <%= link_to get_notification_url(notif) + "#" + notif.notify_type.downcase + "Notif", class: "btn red-btn-small" do %>
                <i class="fa fa-eye" aria-hidden="true"></i>
            <% end %>
          </div>


        </div>


      <% end %>

    <% end %>

  </div>

Ответы [ 2 ]

0 голосов
/ 11 апреля 2020

Делегирование событий

Делегирование событий - это программный шаблон, который позволяет нам прослушивать события для нескольких (неограниченное количество) целевых тегов (например, buttons, inputs и т. Д.). c.) Путем привязки (или регистрового) события к одному тегу, который все целевые теги имеют в качестве предка. Я называю его «общим предком» - window, document и body всегда действительны, но в большинстве случаев это не лучший выбор.

Помимо наличия только одного обработчика событий в стеке вызовов, любой целевой тег, динамически добавляемый на страницу после его загрузки, будет реагировать на зарегистрированные инициированные события - нет способа привязать события к тегам, созданным после загрузки страницы. .

jQuery .on() метод делегирует события, когда предоставляется фактический селектор:

$('.btn-group').on('click',...

.btn-group - это тег (общий предок), связанный с события (ы) и будет прослушивать эти события при запуске на любом из его тегов-потомков (целевых тегов). Существует множество способов сослаться на .btn-group в обработчике:

$('.btn-group')

this                   // Used with plain JavaScript properties and methods
$(this)[0]             // As above
$(this).get()          // As above
event.currentTarget    // As above*
$(this)                // Used with jQuery properties and methods
$(event.currentTarget) // As above*

*event.currentTarget всегда будет ссылаться тег привязан к событию, но это не всегда верно для this. Если второй параметр, называемый event.data, определен как селектор, то this будет ссылаться на event.data.

$('.btn-group').on('click', '.btn-modal', openModal);

$(.btn-modal) и теперь $(this), а не $('.btn-group'). Любой тег-потомок $('.btn-group'), по которому щелкают, вызывает событие click, вызывая функцию обработчика openModal(). Именно обработчик будет определять, какой тег инициирует поведение или игнорируется. На теги, которые являются триггерами при нажатии, можно ссылаться следующим образом:

Источник события - Тег, на который пользователь щелкнул, изменил, наведен курсор и т. Д. c.

event.target    // Used with plain JavaScript properties and methods
this            // As above if `event.data` is defined
$(this)[0]      // As above
$(this).get()   // As above
$(event.target) // Used with jQuery properties and methods
$(this)         // As above if `event.data` is defined

event.target всегда будет ссылаться на тег, с которым пользователь взаимодействовал (например, нажал).


Демо

Примечание : Подробности прокомментированы в демоверсии

/*
If there are multiple tags to target

  ex. 3 button.btn-modal
  
Determine the closest parent tag that the target tags have in common. 

  ex. fieldset.btn-group
  
Delegate the event to the "common ancestor". Add the handler function 
(ie `openModal()`) without the parenthesis.

  ex. $('.btn-group').on('click', openModal);
  
*/
$('.btn-group').on('click', openModal);

/*
Pass thru the event object
Use the event object property .target to determine which tag the user clicked. 
Make it into a jQuery object by wrapping it into $(...)

  ex. let clicked = $(event.target);
  
If the clicked tag has a .btn-modal class...

  ex. if (clicked.hasClass('btn-modal')) {...
  
...get the clicked tag data-open value...

  ex. let ID = clicked.data('open');
  
...Finally, use previous value, ID, as a reference to a modal using the Bootstrap 
method .modal() to open said modal.*

  ex. $('#'+ID).modal();
  
*/
function openModal(event) {
  let clicked = $(event.target);
  if (clicked.hasClass('btn-modal')) {
    let ID = clicked.data('open');
    $('#' + ID).modal();
  }
  return false;
}

/*
*Note: Patterns involving .btn-modal classes and data-open attributes 
are of my own design
*/
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" 
rel="stylesheet">
</head>

<body>
  <main class="container">
    <section class='row'>

      <fieldset class='btn-group btn-group-lg mx-auto mt-5'>
        <button class="btn btn-primary btn-modal" data-open="noticeA" type="button">
          Notice A
        </button>
        <button class="btn btn-warning btn-modal" data-open="noticeB" type="button">
          Notice B
        </button>
        <button class="btn btn-danger btn-modal" data-open="noticeC" type="button">
          Notice C
        </button>
      </fieldset>

      <dialog id="noticeA" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-lg">
          <div class="modal-content">
            <header class="modal-header bg-primary">
              <h4 class="modal-title text-white">Notice A</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-primary p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

      <dialog id="noticeB" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-sm">
          <div class="modal-content">
            <header class="modal-header bg-warning">
              <h4 class="modal-title">Notice B</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-warning p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

      <dialog id="noticeC" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-lx">
          <div class="modal-content">
            <header class="modal-header bg-danger">
              <h4 class="modal-title text-white">Notice C</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-danger p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

    </section>
  </main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js">
  </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0
/umd/popper.min.js">
  </script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js">
  </script>
</body>

</html>
0 голосов
/ 11 апреля 2020

Вы имеете в виду, что ваш сгенерированный HTML будет выглядеть следующим образом ... Все div содержат один и тот же множественный класс, что и "media n-media notif-popup-container notif-display". При событии щелчка необходимо использовать любой из классов как «.notif-popup-container» или «.notif-display», и этот код будет работать правильно.

   <div class="media n-media notif-popup-container notif-display" data-id="1">
        Content 1
    </div>
    <div class="media n-media notif-popup-container notif-display" data-id="2">
        Content 2
    </div>
    <div class="media n-media notif-popup-container notif-display" data-id="3">
        Content 3
    </div>

Пример кода отрывается как

    <script>

        $(function () {
            $('body').on("click", ".notif-popup-container", function () {
               console.log($(this).data("id"));
            });
        });

    </script>

Или это может быть так ...

    <script>
    $(function () {
        $('body').on("click", ".notif-display", function () {
            console.log($(this).data("id"));
        });
     });
    </script>

Я надеюсь, что это будет работать нормально ... ура

...