ایجاد یک برنامه To-do با HTMX و Django، قسمت 8: ویرایش درون خطی و استفاده از Iconify

به مجموعه پست هایی که در آنها روند یادگیری HTMX خود را با جنگو مستند می کنم، خوش آمدید. تا کنون ما قابلیت افزودن موارد انجام کار، حذف آنها، تغییر وضعیت تکمیل آنها و اسکرول بی نهایت را پیاده سازی کرده ایم.
برای دیدن کل مجموعه یا مقالات، می توانید dev.to/rodbv را بررسی کنید. مخزن کد تاکنون در github.com/rodbv/todo-mx است.
هدف بعدی اجرای ویرایش درون خطی مورد todo است: وقتی روی دکمه “ویرایش” در جایی از آیتم لیست کلیک می کنیم، یک متن ورودی با عنوان کار و دکمه های ذخیره/لغو نشان داده می شود.
طبق معمول، چند احتمال در اینجا وجود دارد. یکی این است که هر دو را ارائه کنید با عنوان، و یک فرم با
برای هر ردیف، و از جاوا اسکریپت ساده (یا AlpineJS) برای تغییر حالت ویرایش استفاده کنید.
ترجیح میدهم رویکرد ابررسانهای/سرورمحور را دنبال کنم و زمانی که درخواست ویرایش و آیتم به سرور ارسال میشود، فرم ردیف را برگردانم. به عبارت دیگر، یک دکمه “ویرایش” را روی ردیفی که درخواست ارسال می کند اضافه کنید tasks/:id/edit
که به نوبه خود فرم مورد نظر ما را برمی گرداند و جایگزین کل خط می شود.
ابتدا، اجازه دهید یک دکمه جدید، “ویرایش”، در نزدیکی دکمه “حذف” موجود، که با GET
درخواستی که می خواهیم:
این دکمه به این صورت خواهد بود:
بعداً از Iconify برای اضافه کردن چند آیکون زیبا به دکمههای جدید استفاده خواهیم کرد، اما بیایید اکنون روی کار تمرکز کنیم.
با داشتن دکمه درخواست فرم ویرایش، وقت آن است که آدرس و مشاهده جدید را اضافه کنید. اول، در core/urls.py
:
# core/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("tasks/", views.tasks, name="tasks"),
path("tasks//toggle/ ", views.toggle_todo, name="toggle_todo"),
path("tasks// ", views.task_details, name="task_details"),
# NEW
path("tasks//edit/ ", views.edit_task, name="edit_task"),
]
سپس در core/views.py
:
# core/views.py
...previous code
# NEW
@login_required
@require_http_methods(["GET"])
def edit_task(request, task_id):
todo = request.user.todos.get(id=task_id)
return render(
request,
"tasks.html#todo-item-edit",
{"todo": todo},
)
توجه داشته باشید که url/view جدید یک نام جزئی جدید برمی گرداند، tasks.html#todo-item-edit
. وقت آن رسیده است که این جزئی را تعریف کنیم tasks.html
. از آنجایی که این جزئی فقط در صورت درخواست این نما ارائه می شود، ما آن را به پایین فایل اضافه می کنیم و مقدار را تنظیم نمی کنیم inline
ویژگی، که باعث می شود به طور پیش فرض رندر شود.
در core/templates/tasks.html
، در این تا انتهای فایل:
ما اضافه می کنیم is_completed
چک باکس، برای نشان دادن وضعیت کار، که در صورتی که کاربر تصمیم به تغییر آن داشته باشد، همراه با فرم ارسال خواهد شد. توجه داشته باشید که ما آن را حذف کردیم hx-put
ماشه ما همچنین یک متن ورودی داریم که در صورت نیاز تنظیم شده است، برای عنوان، و دو دکمه:
- دکمه ذخیره فرم را ارسال می کند
/tasks/:id/details
، با مقدار جدید عنوان; - دکمه لغو یک را ارسال می کند
GET
درخواست به همان مسیر، که به سادگی مورد todo را با استفاده از جزئی معمول برای todoها برمی گرداند.tasks.html#todo-items-partial
. ما به زودی به این کد خواهیم رسید، ابتدا اجازه دهید آن را در عمل ببینیم تا آنچه را که توضیح دادیم نشان دهیم.
یکی از عوارض جانبی خوب استفاده از یک فرم برای ویرایش آیتم todo این است که کلید Enter/Return نیز کار می کند.
ما قبلاً آدرس/نمایش را داریم که هم توسط مسیرهای ذخیره و هم لغو استفاده میشود – هر دو در حال تماس هستند task_details
، با روش ها POST
و GET
به ترتیب، بنابراین اجازه دهید فقط تابع view را گسترش دهیم.
# core/views.py
... previous code
@login_required
@require_http_methods(["DELETE", "POST", "GET"])
def task_details(request, task_id):
todo = request.user.todos.get(id=task_id)
if request.method == "DELETE":
todo.delete()
response = HttpResponse(status=HTTPStatus.NO_CONTENT)
response["HX-Trigger"] = "todo-deleted"
return response
if request.method == "POST":
title = request.POST.get("title")
if not title:
raise ValueError("Title is required")
todo.title = title
todo.is_completed = bool(request.POST.get("is_completed"))
todo.save()
# both POST and GET will just return the todo details
return render(
request,
"tasks.html#todo-items-partial",
{"todos": [todo]},
)
این برای تغییرات در نما است.
در حالت ایده آل، ما باید از th استفاده کنیم PUT
روش، نه POST
. در حالی که این امکان وجود دارد، به کد بسیار بیشتری نیاز دارد، ما باید فرم را رها کرده و ارسال کنیم hx-put
مستقیماً از دکمه ذخیره، با استفاده از hx-vals
برای جمع آوری مقادیر is_completed
و title
. ما همچنین دو مزیت فرم را که بومی است از دست خواهیم داد required
اعتبار سنجی ورودی، و autofocus
برای ورودی عنوان، بنابراین من فکر میکنم که این یک معاوضه منطقی با خلوص REST-ful است.
استفاده از Iconify برای آیکون ها
آخرین کاری که می خواهیم انجام دهیم این است که دکمه ها را زیباتر کنیم. من تصمیم گرفته ام از Iconify، یک جایگزین منبع باز و رایگان استفاده کنم. به طور خاص، مجموعه “Ming Cute – Line” آنها.
ما فقط میتوانیم CSS را برای نمادهایی که میخواهیم کپی کنیم، در یک فایل جدید در پروژه خود قرار دهیم، /core/static/css/styles.css
(برای دیدن کد اینجا را کلیک کنید). من یک نام کلاس دوم به هر سبک اضافه می کنم تا مراجعه به نام کلاس ها ساده تر شود. این ایده خوبی است که نام های اصلی را برای مرجع در Iconify نگه دارید.
/*
To get more icons, go to
https://icon-sets.iconify.design/mingcute/page-3.html?suffixes=Fill
*/
.icon-delete,
.mingcute--folder-delete-line {
display: inline-block;
width: 18px;
height: 18px;
...rest of CSS
در core/templates/tasks.html
ما می توانیم یک مرجع به فایل CSS اضافه کنیم و از آنها در هر دکمه استفاده کنیم، به عنوان مثال:
اینطوری به نظر می رسد. کل کد را می توانید در شاخه 8 پیدا کنید. در پست های بعدی هر چه می خواهید بپرسید!