Перехватывать изменение массива с помощью proxy
Есть таблица в которую выводятся объекты из массива. Пользователь может добавлять, удалять, изменять, сортировать объекты в массиве. Как можно отслеживать изменение массива(по типу push,slice и т.д.) с помощью proxy? Нашел несколько решений, но не могу разобраться с моим случаем.
<body>
<div class="main">
<header>
<button class="btn" id="seeButton">Просмотр таблицы</button>
<button class="btn" id="addButton">Добавить запись</button>
<button class="btn" id="deleteButton">Удалить запись</button>
<button class="btn" id="updateButton">Обновить запись</button>
<button class="btn" id="searcheButton">Поиск записей</button>
<button class="btn" id="logButton">Просмотреть лог</button>
</header>
<div>
<table class="table" id="table_id">
<thead>
<tr>
<th>№</th>
<th>Фамилия</th>
<th>Должность</th>
<th>Год рождения</th>
<th>Оклад(грн)</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<script>
var seeButton = document.getElementById("seeButton");
var addButton = document.getElementById("addButton");
var deleteButton = document.getElementById("deleteButton");
var updateButton = document.getElementById("updateButton");
var searcheButton = document.getElementById("searcheButton");
var logButton = document.getElementById("logButton");
var tbody = document.querySelector("#table_id tbody");
let arr = []
addButton.addEventListener('click', () => {
let user = add();
});
function add() {
let fam = prompt("введите фамилию", "");
let dol = prompt("введите должность", "");
let date = prompt("введите год рождения", "");
let salary = +prompt("введите оклад", "");
function User(fam, dol, date, salary) {
this.fam = fam;
this.dol = dol;
this.date = date;
this.salary = salary;
}
var user = new User(fam, dol, date, salary)
arr.push(user)
return user;
}
arr = new Proxy(arr, {
set(arr){
if (arr.push, arr.slice, arr.sort, arr.unshift){
function addObj(arr){
for(i=0; i<arr.length; i++){
arr[i] = /// user.fam = this.fam???
var tr = `<tr>
<td>${arr.length}</td><td>${user.fam}</td><td>${user.dol}</td><td>${user.date}</td><td>${user.salary}</td>
</td>`;
tbody.insertAdjacentHTML('beforeend', tr);
}}
}
}
});
</script>
</body>
Ответы (1 шт):
При обращении к свойствам proxy-объекта вызывается хук get, которому в параметры передаются целевой объект, в данном случае массив с данными, имя получаемого свойства, и непосредственно объект proxy.
get: function(target, propName, proxy) {
Таким образом, для перехвата push, splice и т.д. методов достаточно добавить условие, проверяющее имя требуемого поля. Если ожидаемое свойство - можно вернуть свою собственную функцию, в противном случае возвращать значение напрямую из целевого объекта:
if (propName == 'push' || propName == ...) {
return function(...args){ ... }
}
return target[propName];
Возвращаемая функция должна
- принимать параметры
- вызывать исходную функцию с переданными параметрами
- вызывать метод отрисовки
- возвращать результат исходной функции
Например:
function (...args) { // собираем все принимаемые параметры в массив args
const res = target[propName](...args); // вызываем метод у целевого объекта, с переданными параметрами, результат сохраняем в `res`
render(target); // вызываем метод отрисовки, передавая в качестве параметра обновленный массив
return res; // возвращаем результат вызова целевого метода
}
Метод отрисовки может быть простым проходом по всему массиву, собиранием одной большой html строки и присваиванием ее в свойство innerHTML элемента tbody.
например:
tbody.innerHTML = users.map(renderRow).join('');
где renderRow по элементу из объекта получает соответствующую html строку.
Пример в сборе:
var addButton = document.getElementById("addButton");
var tbody = document.querySelector("#table_id tbody");
function render(users) {
tbody.innerHTML = users.map(renderRow).join('');
}
function renderRow(user, index) {
return (
`<tr>
<td>${index}</td>
<td>${user.fam}</td>
<td>${user.dol}</td>
<td>${user.date}</td>
<td>${user.salary}</td>
</tr>`
);
}
let arr = new Proxy([], {
get: function(target, prop) {
if (prop == 'push') {
return function(...args) {
const res = target[prop](...args);
render(target);
return res;
}
}
return target[prop];
}
});
addButton.addEventListener('click', () => {
let user = add();
arr.push(user);
});
function add() {
/*
let fam = prompt("введите фамилию", "");
let dol = prompt("введите должность", "");
let date = prompt("введите год рождения", "");
let salary = +prompt("введите оклад", "");
*/
function User(fam, dol, date, salary) {
this.fam = fam;
this.dol = dol;
this.date = date;
this.salary = salary;
}
// var user = new User(fam, dol, date, salary)
var user = new User(1, 2, 3, 4)
return user;
}
<div class="main">
<header>
<button class="btn" id="addButton">Добавить запись</button>
</header>
<div>
<table class="table" id="table_id">
<thead>
<tr>
<th>№</th>
<th>Фамилия</th>
<th>Должность</th>
<th>Год рождения</th>
<th>Оклад(грн)</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>