feat: dropdown Kelas dependen berdasarkan Jurusan & Tingkat
Saat user pilih Jurusan dan/atau Tingkat Kelas, dropdown Kelas otomatis terfilter hanya menampilkan kelas yang cocok. Menggunakan JS client-side dengan data options dari backend.
This commit is contained in:
@@ -53,7 +53,20 @@ class StudentReportController extends Controller
|
||||
->sortBy('department_name')
|
||||
->pluck('department_name', 'department_code');
|
||||
|
||||
return view('students.index', compact('students', 'classLevels', 'classNames', 'departments'));
|
||||
// Data kelas dengan level & jurusan untuk filter dependen
|
||||
$classOptions = Student::where('is_active', true)
|
||||
->selectRaw('DISTINCT class_name, class_level, department_code')
|
||||
->whereNotNull('class_name')
|
||||
->where('class_name', '!=', '')
|
||||
->orderBy('class_name')
|
||||
->get()
|
||||
->map(fn($c) => [
|
||||
'name' => $c->class_name,
|
||||
'level' => $c->class_level,
|
||||
'dept' => $c->department_code,
|
||||
]);
|
||||
|
||||
return view('students.index', compact('students', 'classLevels', 'classNames', 'departments', 'classOptions'));
|
||||
}
|
||||
|
||||
public function show(Student $student): View
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-1.5">Kelas</label>
|
||||
<select name="class_name"
|
||||
<select name="class_name" id="filter-class-name"
|
||||
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
|
||||
<option value="">Semua Kelas</option>
|
||||
@foreach($classNames as $cn)
|
||||
@@ -192,4 +192,47 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
// Data kelas untuk filter dependen
|
||||
const classOptions = @json($classOptions);
|
||||
|
||||
function filterKelas() {
|
||||
const dept = document.querySelector('select[name="department"]').value;
|
||||
const level = document.querySelector('select[name="class_level"]').value;
|
||||
const kelasSelect = document.getElementById('filter-class-name');
|
||||
const currentVal = kelasSelect.value;
|
||||
|
||||
// Filter
|
||||
let filtered = classOptions;
|
||||
if (dept) filtered = filtered.filter(c => c.dept === dept);
|
||||
if (level) filtered = filtered.filter(c => c.level === level);
|
||||
|
||||
// Sort unique names
|
||||
const names = [...new Set(filtered.map(c => c.name))].sort();
|
||||
|
||||
// Rebuild options
|
||||
kelasSelect.innerHTML = '<option value="">Semua Kelas</option>';
|
||||
names.forEach(n => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = n;
|
||||
opt.textContent = n;
|
||||
if (n === currentVal) opt.selected = true;
|
||||
kelasSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const deptSelect = document.querySelector('select[name="department"]');
|
||||
const levelSelect = document.querySelector('select[name="class_level"]');
|
||||
|
||||
deptSelect.addEventListener('change', filterKelas);
|
||||
levelSelect.addEventListener('change', filterKelas);
|
||||
|
||||
// Apply initial filter if level/dept pre-selected
|
||||
if (deptSelect.value || levelSelect.value) filterKelas();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user