Почему я не могу получить атрибут выбранного элемента с помощью этой функции стрелки JavaScript?

#javascript #html #dom-events #arrow-functions

#javascript #HTML #dom-события #функции со стрелками

Вопрос:

Я заполняю таблицу HTML данными, «извлеченными» из массива объектов:

 let cars = [{
    licensee: '23456 NY',
    arrival: new Date(2020, 9, 16, 11, 34, 30),
    leave: new Date(),
    isParked: true
  },
  {
    licensee: '56456 NY',
    arrival: new Date(2020, 8, 24, 10, 33, 30),
    leave: new Date(2020, 8, 24, 13, 50, 35),
    isParked: false

  },
  {
    licensee: '56780 NY',
    arrival: new Date(2020, 5, 12, 20, 33, 30),
    leave: new Date(2020, 5, 12, 21, 33, 30),
    isParked: false
  }
];

const formatDate = (date) => {
  var hours = date.getHours();
  var minutes = date.getMinutes();
  var ampm = hours >= 12 ? 'PM' : 'AM';
  hours = hours % 12;
  hours = hours ? hours : 12;
  minutes = minutes < 10 ? '0'   minutes : minutes;
  var strTime = hours   ':'   minutes   ' '   ampm;
  return date.getDate()   "/"   (date.getMonth()   1)   "/"   date.getFullYear()   " "   strTime;
}

const secondsToHours = (d) => {
  d = Number(d);
  let h = Math.ceil(d / 3600);
  return h;
}

const makeBill = (car) => {
  let arrivedAt = new Date(car.arrival).getTime();
  let leftAt = new Date(car.leave).getTime();
  //duration in seconds
  let duration = (leftAt - arrivedAt) / 1000;
  let hoursBilled = secondsToHours(duration);
  let billValue = car.isParked ? "-" : 10   (hoursBilled - 1) * 5   " LEI";
  return billValue;
}

const renterTable = () => {
  // Show new on top
  cars.reverse();

  let results = '';
  for (var i = 0; i < cars.length; i  ) {
    results  = `<tr>
          <td>${cars[i].licensee}</td>
          <td>${formatDate(cars[i].arrival)}</td>
          <td>${formatDate(cars[i].leave)}</td>
          <td class="text-center">${showStatus(cars[i])}</td>
          <td class="text-right">${makeBill(cars[i])}</td>
          <td class="text-right">
            <button data-row="${i}" onclick="changeStatus(e)" class="btn btn-sm btn-success">Summary</button>
             </td>
      </tr>`;
  }
  document.querySelector("#parking tbody").innerHTML = results;
}

const showStatus = (car) => {
  return car.isParked ? "In" : "Out";
}

const changeStatus = (e) => {
  let car = cars[e.target.dataset.row];
  console.log(car);
}

renterTable();  
 #parking th,
#parking td {
  white-space: nowrap;
  font-size: 14px;
}  
 <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />

<div class="table-responsive">
  <table id="parking" class="table table-striped m-0">
    <thead>
      <tr>
        <th>Registration plate</th>
        <th>Arrived</th>
        <th>Deaparted</th>
        <th>Status</th>
        <th class="text-right">Pay</th>
        <th class="text-right">Actions</th>
      </tr>
    </thead>
    <tbody></tbody>
  </table>
</div>  

Эта небольшая функция предназначена для регистрации car, соответствующего нажатой кнопке «Сводка», в консоли:

 const changeStatus = (e) => {
  let car = cars[e.target.dataset.row];
  console.log(car);
}
  

Тем не менее, вместо желаемого результата я получаю Cannot read property 'target' of undefined" .

В чем моя ошибка?

Комментарии:

1. onclick="changeStatus()" — вы явно не передаете никаких аргументов, так e и есть undefined . Есть несколько способов исправить это, но я настоятельно рекомендую не использовать встроенные onclick атрибуты, а использовать addEventListener вместо этого.

Ответ №1:

 const changeStatus = (e) => {
 let car = cars[e.target.dataset.row];
  

Он говорит, что не может прочитать target of undefined .

Следовательно, e есть undefined .

Итак, посмотрите, где вызывается функция:

 onclick="changeStatus()"
  

Вы не передаете никаких аргументов, поэтому e получает значение по умолчанию undefined .


Не используйте встроенные атрибуты события. У них множество проблем.

Если вы добавите обработчик событий с addEventListener помощью then, он получит объект события в качестве первого аргумента.

 const buttons = document.querySelector(".btn-success");
for (let i = 0; i < buttons.length; i  ) {
    buttons[i].addEventListener("click", changeStatus);
}
  

Рассмотрите возможность использования делегирования событий вместо привязки обработчика событий к каждой кнопке по отдельности.

Ответ №2:

Вы получаете undefined, потому что вы не передали объект события. изменить:

 onclick="changeStatus()"
  

Для:

 onclick="changeStatus(event)"
  

Также обратите внимание, что использование встроенных обработчиков не является хорошей практикой. если вы заботитесь о хороших практиках, не используйте встроенные обработчики событий. Вместо этого выберите элемент в javascript и прикрепите к нему прослушиватель событий щелчка:

 const btns = document.querySelectorAll('.btn')
btns.forEach(btn => btn.addEventListener("click", e => {
  let car = cars[btn.dataset.row];
  console.log(car);
}));
  

Комментарии:

1. Также возможно сделать changeStatus(this) , который передаст сам элемент, и тогда обработчик может быть el => { let car = cars[el.dataset.row]; console.log(car); }

2. Если я изменю функцию на changeStatus(e) я получаю e is not defined . Спасибо за помощь! 🙂

3. @RazvanZamfir нет changeStatus(e) . используйте: changeStatus(event) . ( event это ключевое слово)

4. Ура, это может сработать, но использование event глобального ужасно, и это поверх встроенных обработчиков событий. К OP: пожалуйста, следуйте ответу @Quentin, а не этому, если вы заботитесь о хорошей практике кодирования.

Ответ №3:

прежде всего, вы должны передать что-то в функцию:

 onclick="changeStatus(this)"
  

в данный момент ЭТО означает «этот элемент» (в этом ответе так много «этого»!).

Это означает, что у вас нет event.target , но element:

 const changeStatus = (element) => {
  let car = cars[element.dataset.row];
  console.log(car);
}
  

рабочий код на:

https://jsfiddle.net/jmz37261/

кстати. лучшим выбором является addEventListener вместо onclick.

@редактировать:

может быть, лучше использовать это решение (в данном указанном случае):

 <button data-row="${i}" onclick="changeStatus(${i})" class="btn btn-sm btn-success">Summary</button>
  

и затем:

 const changeStatus = (row) => {
  let car = cars[row];
  console.log(car);
}
  

Ответ №4:

проблема в вашем теге button: попробуйте заменить onclick="changeStatus()" на onclick="changeStatus"

вы должны передать ссылку на вашу функцию кнопке, поэтому событие (ваша переменная e ) не задано

Комментарии:

1. Значение an onclick является телом функции. Упоминание переменной (даже если переменная содержит функцию) ничего с ней не сделает.