হ্যালো হাসিব! এই লেকচারে আমরা Persons-এর গ্রিডে Sorting Functionality বা ডাটা সাজানোর ফিচার যুক্ত করেছি। ইউজার যখন কলামের হেডিংয়ে (যেমন: Person Name) ক্লিক করবে, তখন ডাটা Ascending (A-Z) বা Descending (Z-A) অর্ডারে সর্ট হবে এবং সাথে Search-এর ডাটাও ঠিক থাকবে।
চলো লেকচারটির একটি কুইক সামারি দেখে নিই।
📌 Quick Summary for Revision
- Default Parameters: Controller-এর
IndexমেথডেsortByএবংsortOrder-এর জন্য ডিফল্ট ভ্যালু সেট করা। - Service Invocation: ফিল্টার করা ডাটা লিস্টটি
GetSortedPersons()সার্ভিসে পাঠিয়ে সর্ট করা ডাটা রিসিভ করা। - State Persistence:
ViewBag-এCurrentSortByএবংCurrentSortOrderসেভ করে View-তে পাঠানো। - Hyperlink & Toggle Logic: View-তে কলাম হেডিংকে Hyperlink-এ কনভার্ট করা।
if-elseলজিক দিয়ে Ascending থাকলে Descending এবং Descending থাকলে Ascending-এর URL তৈরি করা। - Icons: FontAwesome (v6
all.min.css) ব্যবহার করে Ascending-এর জন্যfa-sort-upএবং Descending-এর জন্যfa-sort-downআইকন দেখানো।
🚀 Comprehensive Breakdown & The “Why”
নিচে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিত এবং কারণসহ এক্সপ্লেইন করা হলো:
১. Controller-এ Default Parameters সেট করা [Priority: 9/10]
The “Why”: ইউজার যখন প্রথমবার পেজ লোড করবে, তখন URL-এ কোনো sortBy বা sortOrder থাকবে না। তাই পেজটি ডিফল্টভাবে কিভাবে সর্ট হবে, তা মেথডের প্যারামিটারেই বলে দেওয়া হয়েছে। এখানে হার্ডকোড স্ট্রিংয়ের বদলে nameof অপারেটর ব্যবহার করা হয়েছে, যেন মডেলের প্রপার্টি নাম পরিবর্তন হলে এখানেও অটোমেটিক আপডেট হয়ে যায়।
Implementation:
public IActionResult Index(
string searchBy,
string searchString,
// Default values assigned
string sortBy = nameof(PersonResponse.PersonName),
SortOrderOptions sortOrder = SortOrderOptions.ASC)
{
// ... search logic ...
}
২. Data Sorting এবং ViewBag আপডেট [Priority: 10/10]
The “Why”: আমরা চাই সার্চ এবং সর্ট একসাথে কাজ করুক। তাই ডাটাবেস থেকে সব ডাটা সর্ট করার বদলে, প্রথমে Search দিয়ে ফিল্টার করা ডাটা লিস্ট (persons) বের করা হয়েছে। এরপর সেই ফিল্টার করা লিস্টটিকেই GetSortedPersons-এ পাঠানো হয়েছে। অবশেষে View যেন বুঝতে পারে বর্তমানে কোন কলামে কী অর্ডারে সর্ট হয়ে আছে, সেজন্য স্ট্রিং ফরম্যাটে ডাটাগুলো ViewBag-এ সেভ করা হয়েছে।
Implementation:
// ১. আগে ফিল্টার করা হলো (Previous lecture logic)
List<PersonResponse> persons = _personsService.GetFilteredPersons(searchBy, searchString);
// ২. ফিল্টার করা ডাটাগুলোকে এবার সর্ট করা হলো
List<PersonResponse> sortedPersons = _personsService.GetSortedPersons(persons, sortBy, sortOrder);
// ৩. View-এর জন্য State ধরে রাখা
ViewBag.CurrentSortBy = sortBy;
ViewBag.CurrentSortOrder = sortOrder.ToString();
// ৪. Sorted ডাটা View-তে পাঠানো হচ্ছে
return View(sortedPersons);
৩. View-তে Toggle Logic (if-else) [Priority: 10/10]
The “Why”: কলামের হেডিংয়ে ক্লিক করলে কী হবে, তার তিনটি কন্ডিশন আছে:
- Current is PersonName & ASC: ইউজার ক্লিক করলে URL-এ
sortOrder=DESCপাঠাতে হবে। - Current is PersonName & DESC: ইউজার ক্লিক করলে URL-এ
sortOrder=ASCপাঠাতে হবে। - Other Column: ইউজার অন্য কোনো কলামে থাকা অবস্থায় PersonName-এ ক্লিক করলে, সেটি ডিফল্টভাবে
ASCঅর্ডারে সর্ট হবে।
পাশাপাশি সার্চের ডাটা যেন হারিয়ে না যায়, তাই href-এর Query String-এ searchBy এবং searchString-ও যুক্ত করা হয়েছে।
Implementation (Razor View):
<th>
@if (ViewBag.CurrentSortBy == nameof(PersonResponse.PersonName) && ViewBag.CurrentSortOrder == nameof(SortOrderOptions.ASC))
{
<a href="~/persons/index?searchBy=@ViewBag.CurrentSearchBy&searchString=@ViewBag.CurrentSearchString&sortBy=@nameof(PersonResponse.PersonName)&sortOrder=@nameof(SortOrderOptions.DESC)">
Person Name <i class="fa-solid fa-sort-up"></i>
</a>
}
else if (ViewBag.CurrentSortBy == nameof(PersonResponse.PersonName) && ViewBag.CurrentSortOrder == nameof(SortOrderOptions.DESC))
{
<a href="~/persons/index?searchBy=@ViewBag.CurrentSearchBy&searchString=@ViewBag.CurrentSearchString&sortBy=@nameof(PersonResponse.PersonName)&sortOrder=@nameof(SortOrderOptions.ASC)">
Person Name <i class="fa-solid fa-sort-down"></i>
</a>
}
else
{
<a href="~/persons/index?searchBy=@ViewBag.CurrentSearchBy&searchString=@ViewBag.CurrentSearchString&sortBy=@nameof(PersonResponse.PersonName)&sortOrder=@nameof(SortOrderOptions.ASC)">
Person Name
</a>
}
</th>
৪. FontAwesome Icon Fix [Priority: 5/10]
The “Why”: লেকচারের শুরুতে আইকন ঠিকমতো আসছিলো না কারণ CDN লিংকটি ভুল ছিল। FontAwesome v6 ব্যবহার করলে অবশ্যই all.min.css ফাইলটি লেআউটে অ্যাড করতে হবে।
🆕 .NET 10 & Modern Approaches (Tag Helpers)
লেকচারে href="~/persons/index?searchBy=..." ব্যবহার করে ম্যানুয়ালি Query String তৈরি করা হয়েছে। এটি অনেক পুরনো পদ্ধতি এবং এতে টাইপিং মিস্টেক হওয়ার সম্ভাবনা অনেক বেশি (যেমন & বা ? দিতে ভুলে যাওয়া)।
Modern MVC Approach:
ASP.NET Core-এ সব সময় Tag Helpers (asp-route-{parameterName}) ব্যবহার করা উচিত। এটি অনেক বেশি ক্লিন এবং সেফ।
<a asp-controller="Persons"
asp-action="Index"
asp-route-searchBy="@ViewBag.CurrentSearchBy"
asp-route-searchString="@ViewBag.CurrentSearchString"
asp-route-sortBy="@nameof(PersonResponse.PersonName)"
asp-route-sortOrder="@nameof(SortOrderOptions.DESC)">
Person Name <i class="fa-solid fa-sort-up"></i>
</a>
⌨️ IDE Shortcuts
-
Rename / Refactor (একসাথে সব জায়গায় ভেরিয়েবলের নাম পরিবর্তন): * Visual Studio:
Ctrl+R,Ctrl+R(অথবাF2) -
Visual Studio Code:
F2 -
Comment / Uncomment Code: * Visual Studio & VS Code:
Ctrl+/(অথবাCtrl+K,Ctrl+C)
💡 Best Practices (Sorting Implementation)
১. Use Tag Helpers over Raw URLs: যেমনটি Modern Approach-এ দেখালাম, লিংকের জন্য ম্যানুয়াল href-এর বদলে asp-route ব্যবহার করবে।
২. Avoid Logic Duplication in Views: লেকচারে <th> এর ভেতরে অনেক বড় if-else ব্লক লেখা হয়েছে। যদি টেবিলের ৮টি কলাম থাকে, তবে এই কোড ৮ বার লিখতে হবে যা খুবই জঞ্জাল তৈরি করবে। এর বেস্ট প্র্যাকটিস হলো একটি HTML Helper বা Custom Tag Helper তৈরি করা, অথবা লজিকগুলো একটি Partial View-তে সরিয়ে নেওয়া।
৩. Preserve Search State: সর্ট করার সময় খেয়াল রাখতে হবে সার্চের ফিল্টার যেন মুছে না যায়। লেকচারার এটি খুব সুন্দরভাবে হ্যান্ডেল করেছেন ViewBag.CurrentSearchString পাস করার মাধ্যমে।
Person Name কলামের সর্টিং তো হয়ে গেলো। এখন কি আমরা টেবিলের বাকি কলামগুলোতেও (Email, Date of Birth ইত্যাদি) এই একই লজিক ইমপ্লিমেন্ট করার লেকচারে মুভ করবো?