Оборачивание серии замыканий - PullRequest
3 голосов
/ 09 июля 2019

Я унаследовал большой кусок кода, в котором он имеет большой набор массивов DataTable средств визуализации. Я хотел бы вставить некоторые дополнительные данные в объекты данных на передней панели, не переписывая все средства визуализации, только те, которые действительно затронуты.

Поле columnDefs создается как массив объектов с функцией render, а также часто с другими полями (targets, type и т. Д.). Я хотел бы переписать это на лету, чтобы функция render была оберткой, которая вызывает исходную функцию. Я не могу найти правильный код для закрытия исходной функции, чтобы я мог обработать данные по пути и при этом вызвать эту исходную функцию.

Например, если для columnDefs указано:

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  "render": function (data, type, row) {
    return stuff(row[0]);
  },
  "targets": 1
},
// etc.
]

Я пытаюсь сделать что-то вроде этого:

var mapper = function (def) {
    (function (d, old_render) {
        d.render = (data, type, row) => {
            let extra_data = undefined;
            if (row.length > 1 && typeof (row[0]) == 'object') {
                extra_data = row[0];
                row = row.slice(1);
            }
            return old_render(data, type, row, extra_data);
        }
    })(def, def.render);
};
columnDefs.forEach(mapper);

до звонка $("#my-datatable").DataTable({ ..., columnDefs: columnDefs, ... }).

Пока работает то, что вызывается новая функция рендеринга. Тем не менее, old_render постоянно неопределен, когда вызывается render, что, конечно, умирает.

Пример полного кода на JSFiddle для удобства, а также здесь:

function stuff(x) {
  return "<b>" + x + "</b>";
}

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  "render": function (data, type, row) {
    return stuff(row[0]);
  },
  "targets": 1
},
]

var dataSource = [{"a", "b", "c", "d", "e"}, {"f","g","h","i","j"}];
columnDefs.forEach(d => {
  d.render = function(old_render) {
    return (data, type, row) => {
      let extra_data = undefined;
      return old_render(data, type, row.map(, extra_data);
    };
  }(d.render);
});
var table = $("#my-table").DataTable({
processing: true,
data: dataSource,
columnDefs: columnDefs
});

И связанный HTML-код просто:

<link href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>

<p>
hello
</p>
<table id="my-table">
<thead>
  <tr>
    <th>1</th><th>2</th><th>3</th><th>4</th>
  </tr>
</thead>
</table>

Обновление ... JSLint работает, я просто не уверен, почему его нет в моей большой кодовой базе. Вернемся к доске для рисования, чтобы выяснить, почему.

Ответы [ 2 ]

1 голос
/ 10 июля 2019

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

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  //"render": function (data, type, row) {
  //  return stuff(row[0]);
  //},
  "targets": 1
},
]

Теперь, когда код попадает во второй столбец, визуализация не выполняется.функция, и так, конечно, это не определено.Обернув маппер символом if (d.render) {...}, можно избежать этой проблемы.

1 голос
/ 10 июля 2019

Как-то так должно работать ...

function newRender(oldRender, data, type, row) {
    let extra_data = undefined;
    if (row.length > 1 && typeof (row[0]) == 'object') {
        extra_data = row[0];
        row = row.slice(1);
    }
    return oldRender(data, type, row, extra_data);
}

var mapper = function (def) {
    def.render = newRender.bind(null, def.render);
};

columnDefs.forEach(mapper);
...