Почему нельзя подписать метод на событие click для таблицы данных с помощью лямбда-конструкции? - PullRequest
0 голосов
/ 18 сентября 2018

Я работаю с datatables (datatables.net) в angular 5, и я подписывался на метод для ответа на событие нажатия на tr, например, так:

const tableRef = this.table;    // bound datatable and router to scope 
const routerRef = this.router;  // so I can use them inside the callBack
this.table.on('click', 'tbody tr', function (e) {
    const $tr = $(this).closest('tr');
    const data = tableRef.row($tr).data();
    if (data !== undefined) {
        routerRef.navigateByUrl(`/some/url/details/${data.id}`);
    }
});

Это почти идентично образцу на datatables.net Веб-сайт. Дело в том, что позже я решил изменить свой код, как показано ниже:

this.table.on('click', 'tbody  tr', this.rowClicked(this.table, this.router));

//...

private rowClicked(table, router: Router) {
    return (e) => {
        const $tr = $(this).closest('tr');
        const data = table.row($tr).data();
        if (data !== undefined) {
            router.navigateByUrl('/some/url/details/`${data.id}`');
        }
    }
}

и ... к моему удивлению, он ничего не сделал, даже не моргнул! Тогда я пошел вперед и поместите console.log('row clicked'); внутри лямбды (если можно так назвать, Я действительно новичок в машинописи), и он печатался каждый раз, когда я нажимал на tr, но data был всегда undefined. Я даже изменил table переменную для $("#my-datatable-id").DataTable() и до сих пор не повезло. Через несколько минут я решил git diff файл и понял, что единственный Разница заключалась в том, как создавался callBack (с использованием ключевого слова function), поэтому я сделал это и изменил лямбду на:

private rowClicked(table, router: Router) {
    return function (e) {
        // same as before
    }
}

Угадай что, это сработало! Он извлек данные tr как заклинание. Так что, может кто-нибудь объясните мне, почему при использовании лямбды я не смог извлечь data из строки и при использовании конструкции function я должен был. Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Если я не ошибаюсь, это из-за Javascript Closures вокруг this.

Эти два не производят одинаковые this:

this.table.on('click', 'tbody tr', function (e) {
  // "this" is what you think it is
});

против

this.table.on('click', 'tbody  tr', this.rowClicked(this.table, this.router));

private rowClicked(table, router: Router) {
  // "this" should be window
  return (e) => {
    const $tr = $(this).closest('tr');
    const data = table.row($tr).data();
    if (data !== undefined) {
        router.navigateByUrl('/some/url/details/`${data.id}`');
    }
  }
}

Вы должны быть в состоянии исправить это просто как:

this.table.on('click', 'tbody  tr', () => this.rowClicked(this.table, this.router));

или

this.table.on('click', 'tbody  tr', () => { return this.rowClicked(this.table, this.router); });

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

0 голосов
/ 18 сентября 2018

Я не знаю Angular, но я предполагаю, что this.table.on передает пользовательский this контекст в обратный вызов, который необходим для $(this), чтобы работать так, как вы собираетесь.Когда вы используете функцию стрелки, контекст, передаваемый this.table.on, игнорируется, а this вместо этого ссылается на объект, для которого был вызван rowClicked, поэтому вы получаете другой результат.

...