برنامه نویسی

ایجاد یک برنامه 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 را به صورت درون خطی ویرایش کنید

یکی از عوارض جانبی خوب استفاده از یک فرم برای ویرایش آیتم 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” آنها.

نحوه استفاده از Iconify

ما فقط می‌توانیم 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 پیدا کنید. در پست های بعدی هر چه می خواهید بپرسید!

ویرایش فرم در عمل

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا