0

I'm building a dynamic form

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="/struts-tags" prefix="s" %>
<%@ taglib uri="/struts-dojo-tags" prefix="sx"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>

<html>
<head>
<script language="javascript" src="js/jquery-1.9.1.min.js"></script>
<script language="javascript" src="js/common.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Education List</title>
</head>
<body>
<s:form action="/save" method="POST">   
    <div class="educationForm">
        <c:if test="${ (not empty educations) }"> 
            <c:if test="${ fn:length(educations) ge 1 }">
                <c:forEach items="${educations}" var="edu" varStatus="status">
                    <div class="educations">                    
                        <label>Position</label><input type="text" name="educations[${ status.index }].index" value="${ educations[status.index].index }" /> <a href="" class="delete">Delete</a><br/>
                        <label>School</label><input type="text" name="educations[${ status.index }].school" value="${ educations[status.index ].school }" /><br/>
                        <label>Degree</label><input type="text" name="educations[${ status.index }].degree" value="${ educations[status.index ].degree }" /><br/>
                        <label>GPA</label><input type="text" name="educations[${ status.index }].scored" value="${ educations[status.index ].scored }" /><br/>
                        <label>Start Date</label><input type="text" name="educations[${ status.index }].startDate" value="${ educations[status.index].startDate }" /><br/>
                        <label>End Date</label><input type="text" name="educations[${ status.index }].endDate" value="${ educations[status.index].endDate }" /><br/>
                    </div>
                </c:forEach>        
            </c:if>         
        </c:if>
        <div class="educations">
            <label>Position</label><input type="text" name="educations[${fn:length(educations)}].index" value="${fn:length(educations) + 1}" /><a href="" class="delete">Delete</a><br/>
            <label>School</label><input type="text" name="educations[${fn:length(educations)}].school" /><br/>
            <label>Degree</label><input type="text" name="educations[${fn:length(educations)}].degree" /><br/>
            <label>GPA</label><input type="text" name="educations[${fn:length(educations)}].scored" /><br/>
            <label>Start Date</label><input type="text" name="educations[${fn:length(educations)}].startDate" /><br/>
            <label>End Date</label><input type="text" name="educations[${fn:length(educations)}].endDate" /><br/>
        </div>
    </div>  
    <a href="" id="addButton">Add new Edu</a>
    <input type="submit" value="Save" />        
</s:form>

<div class="template_educations" style="display:none">
    <div class="educations">
        <label>Position</label><input type="text" name="educations[_X_].index" value="_Y_" /><a href="" class="delete">Delete</a><br/>
        <label>School</label><input type="text" name="educations[_X_].school" /><br/>
        <label>Degree</label><input type="text" name="educations[_X_].degree" /><br/>
        <label>GPA</label><input type="text" name="educations[_X_].scored" /><br/>
        <label>Start Date</label><input type="text" name="educations[_X_].startDate" /><br/>
        <label>End Date</label><input type="text" name="educations[_X_].endDate" /><br/>
    </div>
</div>
</body>
</html>

For each educations div, there'll be a .delete link to delete the whole div. And user can add more educations div using #addButton link.

With my current jquery function, I'm able to handle delete feature, but it leads me to code duplication. My code duplicated in 2 place:

  • On page load: If remove these code, onClick event in .delete link won't be registered unless user click #addButton. In other word, clicked event in .delete link will not fire if user didn't click #addButton beforehand

  • On add button clicked event: if remove these code, newly add .delete link won't be registered

Any suggest how to get rid of code duplication on my situation? Sorry if this were a dumb question. I'm new to jQuery

$(document).ready(function(){

    //handle add new education
    $("#addButton").click(function(event){
        event.preventDefault();

        //append html inside template_educations div into educationForm div
        $(".educationForm").append($(".template_educations").html());

        //regist click event handle for button delete
        $(".delete").click(function(event){
            event.preventDefault();

            //delete parent tag with class = educations
            var parent = $(this).parents(".educations");
            parent.remove();
        });

        //loop through input tag inside educations div
        $(".educationForm").children(".educations").last().children("input").each(function(){           
            var count = $(".educationForm").children(".educations").length;

            //replace value of position textfield with current position
            var value = $(this).attr("value");
            if(typeof value !== 'undefined' && value !== false)
            {
                value = value.replace("_Y_", count);
                $(this).attr("value", value);
            }

            //replace educations list index in textfield
            var name = $(this).attr("name");
            name = name.replace("_X_", count);
            $(this).attr("name", name);

        });         
    });

    //handle delete education
    $(".delete").click(function(event){
        event.preventDefault();

        //delete parent tag with class = educations
        var parent = $(this).parents(".educations");
        parent.remove();
    });
});
Doan Cuong
  • 2,594
  • 4
  • 22
  • 39

1 Answers1

1

You can use the delegate() jquery method, which attaches a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements..

Your code then could be:

$(document).ready(function(){

//handle add new education
$("#addButton").click(function(event){
    event.preventDefault();

    //append html inside template_educations div into educationForm div
    $(".educationForm").append($(".template_educations").html());

    //loop through input tag inside educations div
    $(".educationForm").children(".educations").last().children("input").each(function(){           
        var count = $(".educationForm").children(".educations").length;

        //replace value of position textfield with current position
        var value = $(this).attr("value");
        if(typeof value !== 'undefined' && value !== false)
        {
            value = value.replace("_Y_", count);
            $(this).attr("value", value);
        }

        //replace educations list index in textfield
        var name = $(this).attr("name");
        name = name.replace("_X_", count);
        $(this).attr("name", name);

    });         
});

//handle delete education
$("body").delegate('.delete', 'click', function(event){
    event.preventDefault();

    //delete parent tag with class = educations
    var parent = $(this).parents(".educations");
    parent.remove();
});
});
Maria Ioannidou
  • 1,544
  • 1
  • 15
  • 36
  • Right. As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live(). I updated my answer appropriately. – Maria Ioannidou Apr 03 '13 at 14:01
  • So, should I use on() or delegate() since I'm using jquery 1.9.1. Anw, thanks alot for your tip – Doan Cuong Apr 03 '13 at 15:04
  • 1
    As stated in [this answer](http://stackoverflow.com/a/8359160/504368): The new on() function is used to replace the existing separate methods of binding events. As you're using jquery 1.9.1 it is better then to use on(), as follows: $("body").on('click', '.delete', function(event){...}); – Maria Ioannidou Apr 03 '13 at 15:51