Skip to main content
Known Participant
November 4, 2008
Question

Prevent button from working

  • November 4, 2008
  • 4 replies
  • 690 views
I have the following code :

<tr>
<td class="TitleText" align="center"><cfinput type="text" name="conditionCode" id="conditionCode" size="4" tabindex="25"></td>
<td class="TitleText" align="center"><cfinput type="text" name="materialNumber" id="materialNumber" size="20" tabindex="26"></td>
<td class="TitleText" align="center"><cfinput type="text" name="quantity" id="quantity" size="8" value="0" tabindex="27"></td>
<td class="TitleText" align="center"><cfinput type="text" name="unitValue" size="8" value="0.00" tabindex="28"></td>
<td class="TitleText" align="center"><cfinput type="text" name="snFlag" id="snFlag" size="1" tabindex="29"></td>
<td class="TitleText" align="center"><input type="button" value="Delete" onclick="removeRow(this);"/></td>
</tr>
</table>
</td>
</tr>
</table>

<br>
<input type="button" value="Add Another Material Number" onclick="addMaterialNumbers();" />
<br>

If I click the button Add Another Material Number, it will call a javascript function and dynamcially add anohter row after the first one.

However, if they submit the form with the new row called, and no entries in the original row, it blows up.

If they submit the form without adding the new row, another javascript function validation is called to verify that each of the cells/TD in the origianl row have a value in them.

Is there a way to prevent/disable the add new row button from working if no entries are made in the original row ?
    This topic has been closed for replies.

    4 replies

    Inspiring
    November 12, 2008
    Hi,
    first problem: how to verify the header first, then the rows.
    I have added the validation for the rows to the click of the submit button. If an error occurs then the send() function returns a false, which means the click event is aborted and the form is not submitted.
    You can move the content of the send() function to the end of your verification function so it gets executed after your header verification (or move your complete header verification to the beginning of my send() function.

    second problem: one or multiple error messages.
    In the send() function I'm looping through the rows, and add any errors to the status variable. You can also show the error message there right away by putting the alert() function directly into the loop. (new example below)

    forth problem: verifying the radio buttons
    I have added the html and verification for the radio buttons in the script below.
    Although from a user-interface design perspective, if there are radio buttons in a form then there should always be one that is preselected.

    fifth problem: submitting the date to different pages
    This is not possible the way you are describing it. If your website presents a form to a browser and the form data is submitted back to the server, then the form data is only available to that script (defined by the "action" attribute of the form). Using <cflocation> is similar to clicking a link, it just navigates you away from that page and shows a new page to the browser. The form data is then lost.
    I don't know what your serialized.cfm script does (or the other script), but if these are the scripts that process the form entries into the DB then you should <cfinclude> them, which means they are processed as part of the page that receives the form data.

    cheers,
    fober


    ========================================
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <html>
    <head>
    <title>Untitled</title>
    </head>

    <body>
    <script language="JavaScript">
    function checkrow(x){
    error="";
    if (! document.getElementById('material_'+x).value)
    error=error + "Missing Material in "+x +"\n";

    if (!document.getElementById('qty_'+x).value)
    error=error + "Missing Quantity in "+x +"\n";

    if (!document.getElementById('defined_'+x+'N').checked && !document.getElementById('defined_'+x+'Y').checked)
    error=error + "Missing Defined in "+x +"\n";

    if (error)
    alert(error);

    return(error);
    }

    function show(){
    current= parseInt(document.getElementById('rows').value);
    status= checkrow(current);
    if ( status == '' && current <10){
    try{
    document.getElementById('row_'+ (current+1) ).style.display= 'table-row';
    }
    catch(err){
    document.getElementById('row_'+ (current+1) ).style.display= 'block';
    }
    document.getElementById('rows').value= current+1;
    }
    }

    function hide(){
    current= parseInt(document.getElementById('rows').value);
    if (current >1){
    document.getElementById('row_'+ current ).style.display= 'none';
    document.getElementById('rows').value= current-1;
    }
    }

    function send(){
    status="";
    current= parseInt(document.getElementById('rows').value);
    for (row=1; row<=current; row++)
    checkrow(row);
    if ( status != ''){
    return(false);
    }

    }
    </script>

    <cfoutput>
    <table border="1">
    <form action="" method="post">
    <tr>
    <td colspan="4">
    <input type="Submit" value="submit" onclick="return send();">
    <input type="Hidden" name="rows" id="rows" value="1">
    </td>
    </tr>
    <cfloop index="x" from="1" to="10">
    <tr id="row_#x#" <cfif x GT 1>style="display:none"</cfif> >
    <td>#x#</td>
    <td>
    <input type="Text" name="material_#x#" id="material_#x#">
    </td>
    <td>
    <input type="Text" name="qty_#x#" id="qty_#x#">
    </td>
    <td>
    <input type="Radio" name="defined_#x#" id="defined_#x#Y" value="Yes">Yes 
    <input type="Radio" name="defined_#x#" id="defined_#x#N" value="No">No 
    </td>
    </tr>
    </cfloop>
    <tr>
    <td colspan="4">
    <input type="Button" value="Add" onclick="show()">
    <input type="Button" value="Delete" onclick="hide()">
    </td>
    </tr>
    </form>
    </table>
    </cfoutput>

    <cfif isdefined("form.rows")>
    <cfloop index="z" from="1" to="#form.rows#">
    <cfoutput>
    MATERIALS:#form['material_#z#']# / #form['qty_#z#']# / #form['defined_#z#']#<br>
    <cfif form["defined_#z#"] is "Yes">
    <!---<cfinclude template="">--->
    </cfif>

    </cfoutput>
    </cfloop>
    </cfif>

    </body>
    </html>
    Known Participant
    November 13, 2008
    Hi fober1, thanks for your response again. You are great !

    I copied your new code and ran it and when I submit without inputting anything, it popsup with three messages in the one box. When I click ok, the form still submits and blows up on the radio button part, define_, something about scope variable.

    Anyway, I tried to apply some of your new changes and my entire form started to act weird. Depending on what I changed, the error messages were still together in one box, then when I click ok, the individual ones for the header started poppping up. Then when I change it back, must have missed something, becasue the multiple errors box comes up, when I click ok, it comes up again,then when I click ok, I am able to continue. I did get the radio button edits to work, so thats good news.

    One other thing that I noticed is that when I fill out the first row, and click to add the next row, when I tab, it goes back to the first row, then tab again, then down, then tab, back up, etc. I have tabindex for my first row so I was wondering if that did anything or now.

    Here is my partial code attached. If you have time to take a look, great, otherwise I will just used what you had yesterday.

    This is my partial javascript to edit the header section. I want these messages to popup first, individaully, before the row messages :

    <script Language="JavaScript">

    function validateForm()

    {

    if (document.initiateForm.siteID.value == "2" && document.initiateForm.mTrak.value == "")
    {
    alert("MTrak Number must be entered.");
    document.initiateForm.mTrak.focus();
    return (false);
    }

    else if (document.initiateForm.siteID.value == "2" && document.initiateForm.mTrak.value.length !== 10)
    {
    alert("MTrak Number must be 10 characters.");
    document.initiateForm.mTrak.focus();
    return (false);
    }

    if (document.initiateForm.siteID.value == "3" && document.initiateForm.bol.value == "")
    {
    alert("Bill of Lading Number must be entered.");
    document.initiateForm.bol.focus();
    return (false);
    }

    else if (document.initiateForm.siteID.value == "3" && document.initiateForm.bol.value.length > 20)
    {
    alert("Bill of Lading Number cannot be more than 20 characters.");
    document.initiateForm.bol.focus();
    return (false);
    }


    this is your javascript code, that I modified, and what I have in there now :

    <script language="JavaScript">
    function checkrow(x){
    error="";

    if (document.getElementById('siteID').value == 2 && !document.getElementById('mtrak').value)
    error=error + "MTrak Number is required."+"\n";

    if (document.getElementById('siteID').value == 3 && !document.getElementById('bol').value)
    error=error + "Bill of Lading is required."+"\n";

    if (document.getElementById('problemID').value == 0)
    error=error + "Problem Type is required."+"\n";

    if (! document.getElementById('conditionCode_'+x).value)
    error=error + "Condition Code is required for line "+x +"\n";

    if (! document.getElementById('materialNumber_'+x).value)
    error=error + "Material Number is required for line "+x +"\n";

    if (!document.getElementById('quantity_'+x).value)
    error=error + "Quantity is required for line "+x +"\n";

    if (document.getElementById('quantity_'+x).value == 0)
    error=error + "Quantity cannot be zero for line "+x +"\n";


    var numericExpression = /^[0-9]+$/;
    if(document.getElementById('quantity_'+x).value.match(numericExpression)){

    }else{

    document.getElementById('quantity_'+x).focus();
    error=error + "Quantity msut be numeric for line "+x +"\n";
    }


    if (!document.getElementById('unitValue_'+x).value)
    error=error + "Unit Value is requried for line "+x +"\n";

    //if (!document.getElementById('snFlag_'+x).checked == true)
    //error=error + "Serial Flag must by Y or N for line "+x +"\n";
    if (!document.getElementById('snFlag_'+x+'N').checked && !document.getElementById('snFlag_'+x+'Y').checked)
    error=error+"Serial Flag must be checked for line "+x+"\n";

    if(error)
    alert(error);

    return(error);
    }
    function show(){
    current= parseInt(document.getElementById('rows').value);
    status= checkrow(current);
    if ( status == '' && current <10){
    try{
    document.getElementById('row_'+ (current+1) ).style.display= 'table-row';
    }
    catch(err){
    document.getElementById('row_'+ (current+1) ).style.display= 'block';
    }
    document.getElementById('rows').value= current+1;
    }
    //else
    //alert(status);
    }
    function hide(){
    current= parseInt(document.getElementById('rows').value);
    if (current >1){
    document.getElementById('row_'+ current ).style.display= 'none';
    document.getElementById('rows').value= current-1;
    }
    }
    function send(){
    status="";
    current= parseInt(document.getElementById('rows').value);
    for (row=1; row<=current; row++)
    status= status + checkrow(row);
    if ( status != ''){
    alert(status);
    return(false);
    }

    }
    </script>

    This is the part where I dispaly the first row, then call all additional rows, with the delete and add buttons :

    <cfloop index="x" from="1" to="10">
    <tr id="row_#x#" <cfif x GT 1>style="display:none"</cfif> >
    <td class="TitleText" align="center"><input type="text" name="conditionCode_#x#" id="conditionCode" size="1"></td>
    <td class="TitleText" align="center"><input type="text" name="materialNumber_#x#" id="materialNumber" size="40"></td>
    <td class="TitleText" align="center"><input type="text" name="quantity_#x#" id="quantity" size="8" value="0"></td>
    <td class="TitleText" align="center"><input type="text" name="unitValue_#x#" id="unitValue" size="8" value="0.00"></td>
    <td class="TitleText" align="center"><input type="radio" name="snFlag_#x#" id="snFlag_#x#Y" size="1" value="1">Yes
    <input type="radio" name="snFlag_#x#" id="snFlag_#x#N" size="1" value="0">No</td>
    <td class="TitleText" align="center"><input type="Button" value="Delete" onclick="hide()"></td>
    </tr>
    </cfloop>
    </table>

    </td>
    </tr>
    </table>
    </center>
    </cfoutput>

    <br>
    <input type="button" value="Add Another Material Number" onclick="show()">

    So again, if I submit without inputting anything, I would like the header messages to popup individaully, then focus puts the cursor in the field with the error. If the first error is correcte, then the seoncd one should popup. When it gets down to the first row, each individual column in that row show be edited individaully with your message and then focus, instead of all messages in one box. Then the same for the second row, third, etc, with the tabs working properly.

    I am almost there and could not have gone this far without your help. Like I said, if this is too cumbersome to review, then I can just use waht I had yestereday, which is probabaly as good as it is gonig to get.

    Thanks again for all your help. I really appreciate you taking the time.

    Regards
    Inspiring
    November 11, 2008
    Hi,

    Here's a correction to the script. It did work with firefox, but it had a problem with IE.
    The example you have provided for how to get the values into a SQL statement is correct.

    cheers,
    fober


    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <html>
    <head>
    <title>Untitled</title>
    </head>

    <body>
    <script language="JavaScript">
    function checkrow(x){
    error="";
    if (! document.getElementById('material_'+x).value)
    error=error + "Missing Material in "+x +"\n";

    if (!document.getElementById('qty_'+x).value)
    error=error + "Missing Quantity in "+x +"\n";

    return(error);
    }

    function show(){
    current= parseInt(document.getElementById('rows').value);
    status= checkrow(current);
    if ( status == '' && current <10){
    try{
    document.getElementById('row_'+ (current+1) ).style.display= 'table-row';
    }
    catch(err){
    document.getElementById('row_'+ (current+1) ).style.display= 'block';
    }
    document.getElementById('rows').value= current+1;
    }
    else
    alert(status);
    }

    function hide(){
    current= parseInt(document.getElementById('rows').value);
    if (current >1){
    document.getElementById('row_'+ current ).style.display= 'none';
    document.getElementById('rows').value= current-1;
    }
    }

    function send(){
    status="";
    current= parseInt(document.getElementById('rows').value);
    for (row=1; row<=current; row++)
    status= status + checkrow(row);
    if ( status != ''){
    alert(status);
    return(false);
    }

    }
    </script>

    <cfoutput>
    <table>
    <form method="post">
    <tr>
    <td colspan="3">
    <input type="Submit" value="submit" onclick="return send();">
    <input type="Hidden" name="rows" id="rows" value="1">
    </td>
    </tr>
    <cfloop index="x" from="1" to="10">
    <tr id="row_#x#" <cfif x GT 1>style="display:none"</cfif> >
    <td>#x#</td>
    <td>
    <input type="Text" name="material_#x#" id="material_#x#">
    </td>
    <td>
    <input type="Text" name="qty_#x#" id="qty_#x#">
    </td>
    </tr>
    </cfloop>
    <tr>
    <td colspan="3">
    <input type="Button" value="Add" onclick="show()">
    <input type="Button" value="Delete" onclick="hide()">
    </td>
    </tr>
    </form>
    </table>
    </cfoutput>

    <cfif isdefined("form.rows")>
    <cfloop index="z" from="1" to="#form.rows#">
    <cfoutput>
    MATERIALS:#form['material_#z#']# / #form['qty_#z#']# <br>
    </cfoutput>
    </cfloop>
    </cfif>

    </body>
    </html>
    Known Participant
    November 12, 2008
    Hello fober1,

    Your sample code works great !

    I copied it and ran it and it does everthing that I wanted. I then methodically started putting in my code/requirements based on your code and it actually started to work, along with the inserts. However, I did run into a few minor problems that I am not sure how to solve.

    First, my form has a header part, then the line item part, then the additional row part (your code). If they submit without filling out the form, I call a javascript function called validateForm that checks for required fields and lenghts and issues alert error messages. It also validates the first row, which is alwasy displayed when the form is opened. The edit of each cell/field is done one at a time and displays one message per error, not all the errors combined in one alert box.

    But what is happening now is that your javascript code/edit is activated first, for the initial row and all subsequent rows. After all the criteria is satified, it then calls the validateForm funtion and then edits the header part. I have this function before the checkrow function but that does not seem to matter. This is a minor thing and the header part still gets validated, but I was just wondering how to get it back to edit the header part, then the first row, then the acdtional rows.

    I added radio buttons and moved the edit button to the row :
    <td class="TitleText" align="center"><input type="radio" name="snFlag_#x#" id="snFlag" size="1" tabindex="29" value="1">Yes
    <input type="radio" name="snFlag_#x#" id="snFlag" size="1" tabindex="29" value="0">No</td>
    <td class="TitleText" align="center"><input type="Button" value="Delete" onclick="hide()"></td>

    Using your edit examples, how would I validate that one of the buttons was selected ?

    Finally,each row has to have a button selected, Yes, (value =1) or No, (value=0). If they choose yes, I pass that rows data to one page and if they choose no, I pass that rows data to another page. When I originally had to text box to enter y or n, I used this code :
    <cfif ListFind(form.snflag,"Y") or ListFind(form.snFlag, "y")>
    <cflocation url="serialized.cfm?gfmRdn=#form.gfmRdn#&fromScreen=initiateGfm2">

    But now with radio buttons and your example, I changed it to this :
    <cfif ListFind('#form['snflag_#z#']#',"1")>
    <cflocation url="serialized.cfm?gfmRdn=#form.gfmRdn#&fromScreen=initiateGfm2">
    However, if I only have one row, the error message says something about form scope for snFlag_2 does not exists or is invalid. What do I need to do to make this work, or do I have to go back to the text box ?

    I think I am almost there, using your example, but not quite, but getting closer and closer. I just need to finish this off and close the loop.

    Thanks again for all your help, it is much appreciated.

    Regards
    Inspiring
    November 11, 2008
    Hi,

    Dynamically adding rows and fields can cause several other problems.
    I would recommend to build a form that includes as example 10 rows for the serial numbers, but hide the rows 2-10, and use the add row /delete row buttons to just switch the visibility of the additional rows.

    The example below shows:
    1) how to hide the rows initially
    2) how to verify data entry before adding a row
    3) how to verify data before submission
    4) how to read the values on server side

    p.s. The hidden field "rows" is also submitted in your form, and allows you to evaluate on server side in CFML how many rows have been submitted. (Have a look at the end of the example to see how to get to the values in CF)

    cheers,
    fober

    ====================================================
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <html>
    <head>
    <title>Untitled</title>
    </head>

    <body>
    <script language="JavaScript">
    function checkrow(x){
    error="";
    if (! document.getElementById('material_'+x).value)
    error=error + "Missing Material in "+x +"\n";

    if (!document.getElementById('qty_'+x).value)
    error=error + "Missing Quantity in "+x +"\n";

    return(error);
    }
    function show(){
    current= parseInt(document.getElementById('rows').value);
    status= checkrow(current);
    if ( status == '' && current <10){
    document.getElementById('row_'+ (current+1) ).style.display= 'table-row';
    document.getElementById('rows').value= current+1;
    }
    else
    alert(status);
    }
    function hide(){
    current= parseInt(document.getElementById('rows').value);
    if (current >1){
    document.getElementById('row_'+ current ).style.display= 'none';
    document.getElementById('rows').value= current-1;
    }
    }
    function send(){
    status="";
    current= parseInt(document.getElementById('rows').value);
    for (row=1; row<=current; row++)
    status= status + checkrow(row);
    if ( status != ''){
    alert(status);
    return(false);
    }

    }
    </script>

    <cfoutput>
    <table>
    <form method="post">
    <tr>
    <td colspan="3">
    <input type="Submit" value="submit" onclick="return send();">
    <input type="Hidden" name="rows" id="rows" value="1">
    </td>
    </tr>
    <cfloop index="x" from="1" to="10">
    <tr id="row_#x#" <cfif x GT 1>style="display:none"</cfif> >
    <td>#x#</td>
    <td>
    <input type="Text" name="material_#x#" id="material_#x#">
    </td>
    <td>
    <input type="Text" name="qty_#x#" id="qty_#x#">
    </td>
    </tr>
    </cfloop>
    <tr>
    <td colspan="3">
    <input type="Button" value="Add" onclick="show()">
    <input type="Button" value="Delete" onclick="hide()">
    </td>
    </tr>
    </form>
    </table>
    </cfoutput>

    <cfif isdefined("form.rows")>
    <cfloop index="z" from="1" to="#form.rows#">
    <cfoutput>
    MATERIALS:#form['material_#z#']# / #form['qty_#z#']# <br>
    </cfoutput>
    </cfloop>
    </cfif>

    </body>
    </html>

    Known Participant
    November 11, 2008
    Hi fober1, thanks for your response.

    Your method about hiding the rows was a suggestion from a co worker, since he had done something similar. However, maybe it was just the way he did it, but his code looked real cumbesome and complex, and I found this method that seemed easier to follow, so that is why I went with it. But I just cannot get it to edit, so I guess I will go with your suggestion.

    I copied your sample code and ran it and when I tried to add or delete a row, it came up with an error that says could not get the display property invalid argument, and it listed line 24.

    Also, I currently use this to insert the first row and each addtional row into the table :

    <cfloop from="1" to="#listlen(form.materialNumber)#" index="i">

    <cfset col1 = listgetat(form.conditionCode, i)>
    <cfset col2 = listgetat(form.materialNumber, i)>
    <cfset col3 = listgetat(form.quantity, i)>
    <cfset col4 = listgetat(form.unitValue, i)>
    <cfset col5 = listgetat(form.snFlag, i)>

    I have five columns per row.

    So with your method, the insert would be :

    <cfif isdefined("form.rows")>
    <cfloop index="z" from="1" to="#form.rows#">
    <cfoutput>
    insert table
    set materialNumber = form['material_#z#']# / #form['qty_#z#']# ...etc ?
    </cfoutput>
    </cfloop>
    Inspiring
    November 4, 2008
    Olivia Crazy Horse wrote:
    >
    > Is there a way to prevent/disable the add new row button from working if no
    > entries are made in the original row ?
    >

    Sure, in the function that adds the row, call the function that
    validates the previous rows or logic like it. If it does not validate,
    this function does not add the row.

    Known Participant
    November 10, 2008
    This is the javascript code that I use to add a new row :
    <script type="text/javascript">
    function addMaterialNumbers() {
    //add a row to the rows collection and get a reference to the newly added row
    var newRow = document.all("addMaterialNumbers").insertRow();

    //add 3 cells (<td class="TitleText" >) to the new row and set the innerHTML to contain text boxes

    var oCell = newRow.insertCell();
    oCell.innerHTML = "        <input type='text' name='conditionCode' id='conditionCode' size='1' width='105'>";

    oCell = newRow.insertCell();
    oCell.innerHTML = "<input type='text' name='materialNumber' size='40'>";

    oCell = newRow.insertCell();
    oCell.innerHTML = "<input type='text' name='quantity' size='8' value='0'>";

    oCell = newRow.insertCell();
    oCell.innerHTML = "<input type='text' name='unitValue' size='8' value='0.00'>";

    oCell = newRow.insertCell();
    oCell.innerHTML = "   <input type='text' name='snFlag' size='1' value='N'>"

    oCell = newRow.insertCell();
    oCell.innerHTML = "<input type='button' value='Delete' onclick='removeRow(this);'/>";

    }


    //END ADD


    //deletes the specified row from the table
    function removeRow(src)
    {
    /* src refers to the input button that was clicked.
    to get a reference to the containing <tr> element,
    get the parent of the parent (in this case <tr>)
    */
    var oRow = src.parentElement.parentElement;

    //once the row reference is obtained, delete it passing in its rowIndex
    document.all("addMaterialNumbers").deleteRow(oRow.rowIndex);

    }
    // -->
    </SCRIPT>

    Immedately after this, I have another function that validates that fields are required :
    <script Language="JavaScript">

    function validateForm()

    {

    if (document.initiateForm.conditionCode.value.length == 0)
    {
    alert("Condition Code must be entered.");
    document.initiateForm.conditionCode.focus();
    return (false);
    } etc...

    So this function validateForms needs to be added to function addMaterialNumbers, and it will validate each of the cells in the new row ? Where should it be added, at the beginnnig, or end ?