Почему моя логика с использованием наиболее близкого не работает?

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

$(function(){
  $('#firstName').on('blur', function(e){
    // I tried to get the closest first name to the input
    var $firstNameLabel = $(e.target).closest('.firstName');
    
    if (e.target.value.trim() === '') {
      $firstNameLabel.addClass('error');
    } else {
      $firstNameLabel.removeClass('error');
    }
  });

  $('#lastName').on('blur', function(e){
    // I also tried to use the parent get the closest last name to the input
    var $lastNameLabel = $(e.target).closest('.form-group .lastName');
    
    if (e.target.value.trim() === '') {
      $lastNameLabel.addClass('error');
    } else {
      $lastNameLabel.removeClass('error');
    }
  });
});
.form-group label { display: inline-block; min-width: 80px; }
.error { color: rgb(240, 0, 0); }
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class = "form-group">
  <label for = "firstName" class = "firstName">First Name:</label>
  <input type = "text" name = "firstName" value = "" id = "firstName">
</div>

<div class = "form-group">
  <label for = "lastName" class = "lastName">Last Name:</label>
  <input type = "text" name = "lastName" value = "" id = "lastName">
</div>
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
0
0
322
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Основная проблема заключается в непонимании того, как работает jQuery ближайший(). Как указано в API...

For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.

Важная часть, связанная с нашей проблемой, это "его предки". Что это значит? предок по отношению к DOM является (n косвенным) родителем элемента. Например, давайте посмотрим на следующий пример HTML...

<html>
    <head>
    </head>
    <body>
        <div id = "header">
            Welcome to my Site!
        </div>
        <div id = "content">
            <p>Hope you like it!</p>
            <p>More to come later!</p>
        </div>
    </body>
</html>

Если мы посмотрим на теги абзаца, то увидим, что они окружены (или «инкапсулированы») тегом div. Форматирование абзацев таким образом обозначает их как дочерние элементы этого div, таким образом, этот div является родителем этих абзацев. Абзацы, принадлежащие одному и тому же родителю div, считаются братья и сестры.

Кроме того, тег div инкапсулируется тегом body, поэтому тело является родителем div. Поскольку тело является прямым родителем div, а div — прямым родителем абзацев; это означает, что тело является родителем косвенный абзацев.


Итак, теперь давайте посмотрим, как это относится к нашей проблеме. В первом прослушивателе событий мы пытаемся получить метку firstName до ввода firstName с помощью closest('.firstName'). Однако, как мы теперь знаем, closest ищет только прямых или косвенных родителей. Ссылаясь на нашу структуру HTML, является ли метка родителем ввода? Нет. Это предшествующий брат или сестра.

А как насчет второй попытки, пытаясь получить метку secondName до ввода secondName? Этот селектор использует '.form-group .lastName', поэтому он ищет родителя form-group, у которого есть дочерний элемент lastName, верно? Так должно работать?

Нет. Причина, по которой вторая попытка не удалась, заключается в том, что селектор, который вы даете closest, предназначен для сопоставления Только родительского элемента. Он не выполняет никаких обходов вложенности, чтобы увидеть, соответствует ли селектор элементу немного. Это должен соответствует родителю. И поскольку один элемент не может соответствовать селектору, который включает в себя вложенность, он не найдет элемент для выполнения ваших действий.


Теперь, когда мы знаем проблемы, как мы можем их исправить? Что ж, давайте посмотрим на firstName one...

$(function(){
  $('#firstName').on('blur', function(e){
    var $firstNameLabel = $(e.target).prev('.firstName');
    
    if (e.target.value.trim() === '') {
      $firstNameLabel.addClass('error');
    } else {
      $firstNameLabel.removeClass('error');
    }
  });
});
.form-group label { display: inline-block; min-width: 80px; }
.error { color: rgb(240, 0, 0); }
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class = "form-group">
  <label for = "firstName" class = "firstName">First Name:</label>
  <input type = "text" name = "firstName" value = "" id = "firstName">
</div>

В этом конкретном случае мы знаем, что метка непосредственно предшествует входным данным. Учитывая этот факт, мы могли бы использовать метод jQuery предыд.() для получения предыдущего родственного элемента для нашего элемента. В приведенном выше примере я дал ему необязательный селектор для фильтрации, но в данном случае это не обязательно. Используя prev(), мы можем захватить элемент перед вводом, который является меткой, а затем сделать с ним все, что захотим.

Но что, если вы хотите использовать closest(), чтобы избежать изначально хрупкой позиционной логики, которую включает prev()? Мы все еще могли бы использовать его, немного изменив нашу логику.

$(function(){
  $('#firstName').on('blur', function(e){
    var $firstNameLabel = $(e.target).closest('.form-group').find('.firstName');
    
    if (e.target.value.trim() === '') {
      $firstNameLabel.addClass('error');
    } else {
      $firstNameLabel.removeClass('error');
    }
  });
});
.form-group label { display: inline-block; min-width: 80px; }
.error { color: rgb(240, 0, 0); }
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class = "form-group">
  <label for = "firstName" class = "firstName">First Name:</label>
  <input type = "text" name = "firstName" value = "" id = "firstName">
</div>

Теперь мы изменили ближайший, чтобы найти общий родительский div как для метки, так и для ввода. Как только мы найдем родителя, мы можем выполнить поиск, чтобы получить вложенную метку. При таком подходе не имеет значения, где находится метка в div, лишь бы она была дочерней. Таким образом, используя эту логику, если бы у вас была метка перед вводом сегодня и когда-нибудь в будущем вы решили переместить ее (или, возможно, вложить ее в какую-то другую структуру в div), она все равно нашла бы ее.

Этот второй подход также работает для нашей проблемы с фамилией. Вместо того, чтобы пытаться поместить весь селектор в closest(), ближайшим становится поиск родительского div, за которым следует find() для метки.

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