А так же о всякой фигне
Недавно один мой знакомый вайтишник спросил как запилить редактирование данных в бд, ну Вы знаете, так чтобы и страница на каждый чих не перезагружалась и чтобы формочка редактирования объекта появлялась итд. Ну вот этим мы сейчас и займёмся.
[ { "id": 1, "name": "Барсик", "breed": "Persian", "age": 12, "sex": "male" }, ... ]и по каждому котику будет ещё дополнительная апи, с дополнительной информацией: GET /api/cats/1.json
{ "id": 1, "name": "Барсик", "breed": "Persian", "age": 12, "sex": "male", "owner": { "phone": "+7888999000", "name": "Сычёв", "city": "Мухосранск" } }
Нам нужно написать веб страничку, которая ассинхронно загрузит табличку с котиками, и дополнительно, тыкнув по кнопке, будет показывать формочку с расширенной информацией. А тыкнув по другой кнопке, появится форма редактирования, или добавления котика.
Итак, нам нужно подключить, стили, jquery, main.js в который положим весь наш код и зафигачить минимальную index.html:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru"> <head> <title>JQUERY interactive example</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" crossorigin="anonymous"> <link href="./css/main.css" type="text/css" rel="stylesheet"> </head> <body> <div class="container"> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">JQUERY example</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavAltMarkup"> <div class="navbar-nav"> <!-- какие-то элементы меню --> </div> </div> </nav> <br/> </div> <div class="container"> ... content </div> <script src="https://code.jquery.com/jquery-3.4.1.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" crossorigin="anonymous"></script> <script src="./js/main.js"></script> </body> </html>
<table class="table table-hover"> <thead> <tr> <th>id</th> <th>Имя</th> <th>Порода</th> <th>Возраст</th> <th>Пол</th> <th></th> </tr> </thead> <tbody id="cats_table_body"></tbody> </table>
id="cats_table_body" нам нужен для лёгкого поиска тела таблицы по ID. Ну и да, делаем нашу первую js функцию, которая будет загружать список котиков с сервера:
function loadCatsList(url) { $.get(url) .then( data=> { console.log('* data', data); }) }
Функция получает url по которому лежат котики, и если сервер отдаёт правильные заголовки, то jquery автоматически распарсит json в объект.
Теперь нам надо написать функцию, которая сгенерирует тело таблицы, по полученным данным:
function genTableBody(data) { let result = ''; for(let item of data) { result += '<tr>'; for(let index in item) result += `<td>${item[ index ]}</td>`; result += `<td><a class="btn btn-primary" href="">Owner info</a></td>`; result += '</tr>'; } return result; }
Теперь мы можем вставить сгенерированные строки в таблицу:
function loadCatsList(url) { $.get(url) .then( data=> { $('#cats_table_body').html(genTableBody(data)); }); }
Сейчас если мы кликнем по кнопке "Owner info", то ничего не произойдёт, нужно это исправить. Для этого, вешаем на кнопку вызов функции- обработчика события:
result += `<td><a class="btn btn-primary" href="javascript:catClick(${item.id})">Owner info</a></td>`;
И пишем тестовую функцию- обработчик:
function catClick(id) { alert('on catClick ' + id); }
Если сейчас всё у нас без ошибок, то по клику на кнопку должен появляться алерт:
В первую очередь нужно написать стандартную bootstrap формочку, которую нужно положить, опять ж, в стандартное bootstrap всплывающее окошко:
<div class="modal fade" id="ownerform" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLongTitle">Cat owner</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <div class="col-sm-12"> <div class="form-group row"> <label class="col-sm-2 col-form-label">Phone:</label> <div class="col-sm-10"> <input type="text" readonly class="form-control-plaintext" id="ownerform_phone" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Name:</label> <div class="col-sm-10"> <input type="text" readonly class="form-control-plaintext" id="ownerform_name" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">City:</label> <div class="col-sm-10"> <input type="text" readonly class="form-control-plaintext" id="ownerform_city" value=""> </div> </div> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div>
Да, чтобы всё работало красиво, приходится копипастить могабукаф. Но благо, для этого есть типовые примеры на сайте с документацией.
Ок, теперь у нас есть форма, есть кнопка с обработчиком события, давайте навесим на неё активацию bootstrap modal:
function catClick(id) { //alert('on catClick ' + id); $("#ownerform").modal() }
И cделаем api запрос за расширенной информацией по котику:
function catClick(id) { $.get(`./api/cats/${id}.json`) .then( data => { console.log('* DATA:', data); $("#ownerform").modal() }); }
Теперь мы сперва получаем данные с помощью $.get(`./api/cats/${id}.json`), и уже только после этого, показываем формочку. Остался последний этап, закинуть данные полученные по апи, в саму форму:
function catClick(id) { $.get(`./api/cats/${id}.json`) .then( data => { $('#ownerform_phone').val(data.owner.phone); $('#ownerform_name').val(data.owner.name); $('#ownerform_city').val(data.owner.city); $("#ownerform").modal(); }); }
На этом этапе, если у нас всё ок, то увидим следующее:
Ну и для закрепления, давайте создадим форму редактирования и добавления данных. Это будет ода форма, сразу на 2 действия, чтобы не создавать 2 отдельные формы. Как обычно, копипастим шаблон модального окошка с getbootstrap и в нём фигачим форму:
<div class="modal fade" id="editform" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLongTitle">Cat</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <div class="col-sm-6"> <h3>Cat</h3> <div class="form-group row"> <label class="col-sm-2 col-form-label">Name:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="editform_name" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Breed:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="editform_breed" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Age:</label> <div class="col-sm-10"> <input type="number" class="form-control" id="editform_age" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Sex:</label> <div class="col-sm-10"> <select class="form-control" id="editform_sex"> <option value="male">male</option> <option value="female">female</option> <option value="no">not sure</option> </select> </div> </div> </div> <div class="col-sm-6"> <h3>Owner</h3> <div class="form-group row"> <label class="col-sm-2 col-form-label">Phone:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="editform_phone" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">Name:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="editform_owner_name" value=""> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label">City:</label> <div class="col-sm-10"> <input type="text" class="form-control" id="editform_city" value=""> </div> </div> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary" data-dismiss="modal">Save</button> </div> </div> </div> </div>
Подправляем табличку, в неё нужно добавить кнопку активации редактирования:
result += `<td><a class="btn btn-primary" href="javascript:catClick(${item.id})">Owner info</a> `; result += `<a class="btn btn-primary" href="javascript:catEdit(${item.id})">Edit</a></td>`;
И фигачим функцию catEdit, которая далет почти то же самое что и catClick, только будет активировать другую форму, и данные будет запихивать в другие эдиты:
function catEdit(id) { $.get(`./api/cats/${id}.json`) .then( data => { addEditAction = 'edit'; $('#editform_phone').val(data.owner.phone); $('#editform_owner_name').val(data.owner.name); $('#editform_city').val(data.owner.city); $('#editform_name').val(data.name); $('#editform_breed').val(data.breed); $('#editform_age').val(data.age); $('#editform_sex').val(data.sex); $("#editform").modal(); }); }
И ещё нужно добавить глобальную переменную, в которой будет лежать инструкция, что нам делать с данными в форме:
var addEditAction = 'none';Сейчас, если кликнуть по кнопке "edit", то будет следующая картина:
Осталось повесить обработчик нажатия кнопки "save":
function saveEditClick() { let formData = { owner: {} }; formData.owner.phone = $('#editform_phone').val(); formData.owner.name = $('#editform_owner_name').val(); formData.owner.city = $('#editform_city').val(); formData.name = $('#editform_name').val(); formData.breed = $('#editform_breed').val(); formData.age = $('#editform_age').val(); formData.sex = $('#editform_sex').val(); if( addEditAction == 'edit' ) $.ajax({ type: "PUT", url: './api/cats', data: formData }); if( addEditAction == 'add' ) $.ajax({ type: "POST", url: './api/cats', data: formData }); addEditAction = 'none'; $('#editform').modal('hide'); }А ещё нам не хватает кнопки "создать котика". Давайте зафигачим её в пустой хедер таблички:
<button class="btn btn-primary" onClick="addCat();">Add cat</button>
И функция addCat:
function addCat() { addEditAction = 'add'; $('#editform_phone').val(''); $('#editform_owner_name').val(''); $('#editform_city').val(''); $('#editform_name').val(''); $('#editform_breed').val(''); $('#editform_age').val(0); $('#editform_sex').val('no'); $("#editform").modal(); }
Готовый пример можно посмотреть тут: https://allwebstuff.info/examples/jquery_interactive_example/, архив в исходниками на гите. Единственно, так как я ленивая жопа, я не сделал на сервере обработчики пост и пут запросов, по этому, они будут отваливаться. Но посмотреть, работают они или нет, можно в дев консоли браузера:
Если вся наша приложунька- это действительно только одна табличка и пара не сложных формочек, то минусов тут и нет. Весь код понятен, лишних зависимостей нет. Но, если приложунька выростает до хотя бы нескольких страниц, со сложной логикой, кучей элементов, то мы сталкиваемся с проблемами:
Вот чтобы решить все эти проблемы, ну и дать, ещё немного плюшек сверху, напридумывали всякие vue/react/angular итд. Но про них как-нибудь попозже.
Антироссийские протесты в Грузии
Второй деть в Грузии идут антироссийские протесты. Если Вы ещё не в курсе, меня ситуация в Грузии касается самым непосредственным образом. У меня там ип и счета в банке. Но я не паникую и вот почему.
Впечатление от windows 10 после >10 лет жизни на linux
Я очень, очень давно живу только на линупсе. Последняя винда, которая стояла у меня на компе- это первые версии windows 7. И тут меня приспичило погамать в старкрафт 2, который под вайном ваще никак не хотел стартовать. ИИИиииии, внезапно винда стала почти нормальной! Уже догнала по возможностям кеды 15 летней давности))