Student attendance tool with additional filters have trouble rendering student checkboxes HTML

Good Day Everyone. I met with a requirement of adding additional filtering options for Attendance Tool in School module, based on Program Filter, and I worked out the UI components pretty well.

I modified the based_on method in student_attendance_tool.js to the following for my requirement:

    based_on: function(frm) {
        if (frm.doc.based_on == "Student Batch") {
            frm.set_value("course_schedule", "");
            frm.set_value("program", "");
        } else if (frm.doc.based_on == "Student Batch") {
            frm.set_value("student_batch", "");
            frm.set_value("program", "");
        } else if (frm.doc.based_on == "Program Enrollment") {
            frm.set_value("student_batch", "");
            frm.set_value("course_schedule", "");
        }
    },

And then added a program function to trigger student_batch which in-turn calls the API method get_student_attendance_records, so I added an additional argument program: frm.doc.program to the args object. Everything is pretty well.

To make changes to the API call, I also made the following changes to the method:

def get_student_attendance_records(based_on, date=None, student_batch=None, course_schedule=None, program=None):
	student_list = []
	student_attendance_list = []

	if based_on=="Course Schedule":
		student_group = frappe.db.get_value("Course Schedule", course_schedule, "student_group")
		if student_group:
			student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "idx"] , \
			filters={"parent": student_group}, order_by= "idx")
		else:
			student_batch = frappe.db.get_value("Course Schedule", course_schedule, "student_batch")
	if not student_list and based_on == "Student Batch":
		student_list = frappe.get_list("Student Batch Student", fields=["student", "student_name", "idx"] , filters={"parent": student_batch}, order_by= "idx")

	if based_on == "Program Enrollment":
		student_list = frappe.get_list("Program Enrollment", fields=["student", "student_name", "idx"] , filters={"program": program, "docstatus": 1}, order_by= "idx")

	if course_schedule:
		student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \
			course_schedule= %s and docstatus=1""", (course_schedule), as_dict=1)
	elif student_batch:
		student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \
			student_batch= %s and date= %s and docstatus=1 and \
			(course_schedule is Null or course_schedule='')""",
			(student_batch, date), as_dict=1)
	elif program:
		student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \
			date= %s and program= %s and docstatus=1 and \
			(course_schedule is Null or course_schedule='')""",
			(date, program), as_dict=1)

	for attendance in student_attendance_list:
		for student in student_list:
			if student.student == attendance.student:
				s = frappe.get_doc("Student", student.student)
				student.status = attendance.status
				student.student_mobile_number = s.student_mobile_number
	return student_list

And this works great. Now to make the final call works well to check mandatory, I modified the validate_mandatory method from student_attendance.py to the following:

def validate_mandatory(self):
		if not (self.student_batch or self.course_schedule or self.program):
			frappe.throw(_("""Student Batch or Course Schedule or Program is mandatory"""))

And ofcourse modified the api.py function to make changes to the mark_attendance call while clicking the Mark Attendance button. I just added a new arg program and populated it - and ofcourse I modified the Attendance doctype to add the field program, so the sql above will work. Now it looks like the following:

def mark_attendance(students_present, students_absent, course_schedule=None, student_batch=None, program=None, date=None):
	present = json.loads(students_present)
	absent = json.loads(students_absent)
	for d in present:
		make_attendance_records(d["student"], d["student_name"], "Present", course_schedule, student_batch, program, date)

	for d in absent:
		make_attendance_records(d["student"], d["student_name"], "Absent", course_schedule, student_batch, program, date)

	frappe.db.commit()
	frappe.msgprint(_("Attendance has been marked successfully."))

def make_attendance_records(student, student_name, status, course_schedule=None, student_batch=None, program=None, date=None):
	student_attendance = frappe.new_doc("Student Attendance")
	student_attendance.student = student
	student_attendance.student_name = student_name
	student_attendance.course_schedule = course_schedule
	student_attendance.student_batch = student_batch
	student_attendance.program = program
	student_attendance.date = date
	student_attendance.status = status
	student_attendance.submit()

To my knowledge, everything is set perfect, API is returning data properly. On the file student_attendance_tool.js the last line of the code is $(htmls.join("")).appendTo(me.wrapper) which is responsible for rendering the HTML into DOM, which was working well for Student Batch and not for my custom filter, even though I didn’t miss anything I believe.

I analyzed the HTML DOM and found that it is being rendered, but the section of the HTML has hide-control class which is not displaying the rendered grid with student data.

So I did changed the last line of the code to the following:

$(htmls.join("")).appendTo(me.wrapper).parent().parent().parent().parent().parent().parent().removeClass('hide-control');

Now everything, from API call to returning data to marking attendance works cool.

But I am not convinced with this behaviour, that made me chain .parent() and then remove a HTML class using jQuery. I know I did a workaround, but what is the proper way to achieve this? Why was the section not rendering for my custom filter but works fine with Student Batch filter?