#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
является телом функции. Упоминание переменной (даже если переменная содержит функцию) ничего с ней не сделает.