Question

I have a dynamically created table in an .html form and I want to do an insert in the .cfm form. I need to loop through the rows of the dynamically created table and perform an INSERT into a table in SQL Server. Also, the table was created in JavaScript. Thanks.

<cfoutput>
 <cfloop from="1" to="#ArrayLen(tblSample)#" index="i">
  <cfquery name="AppendForm" datasource="TestSource">
    INSERT INTO tblGrand
    (GrandNum,
    GrandName, 
    County, 
    VersionType, 
    VersionNum, 
    SectCode, 
    Comments,    
    Provider,       
    TypeID,     
    SubmitDate)                 
    Select
    <cfif isdefined("form.GrandNum")>
      '#GrandNum#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.GrandNme")>
      '#GrandNme#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.selCnty")>
      '#selCnty#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.VersionType")>
      '#VersionType#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.VersionNum")>
      '#VersionNum#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.SectCode[i]")>
      '#SectCode[i]#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.txtComments[i]")>
      '#textComments[i]#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.txtProvider[i]")>
      '#txtProvider[i]#',
    <cfelse>
      null,
    </cfif>
    <cfif isdefined("form.selType[i]")>
      '#selType[i]#',
    <cfelse>
      null,
    </cfif>
    '#DateFormat(Now(),"yyyy-mm-dd") &" "& TimeFormat(Now(),"HH:mm:ss")#'
    </cfquery>
  </cfloop>
</cfoutput>

Here is my html code for creating the table:

<script language="javascript" type="text/javascript">
function addRow() {

    var tbl = document.getElementById('tblSample');
    var lastRow = tbl.rows.length;  
    var iteration = lastRow;
    var row = tbl.insertRow(lastRow);

  // left cell
    var cellLeft = row.insertCell(0);
    var textNode = document.createTextNode(iteration-3);
    cellLeft.appendChild(textNode);

      // select cell
    var cellRightSel = row.insertCell(1);
    var sel = document.createElement('select');
    sel.name = 'sectCode' + iteration;
    sel.id = 'sectCode' + iteration;    
    sel.options[0] = new Option('---Any---', '0');
    sel.options[1] = new Option('Level 0.5: test1, '1');
    sel.options[2] = new Option('Level I: test2', '2');
    sel.options[3] = new Option('Level I.D: test3', '3');
    sel.options[4] = new Option('Level II.1: test4', '4');
    sel.options[5] = new Option('Level II.5: test5', '5');
    cellRightSel.appendChild(sel);

    var cellRights = row.insertCell(2);
    var els = document.createElement('input');
    els.type = 'text';
    els.name = 'txtComments' + iteration;
    els.id = 'txtComments' + iteration;
    els.size = 20;
    cellRights.appendChild(els);

    var cellRight = row.insertCell(3);
    var el = document.createElement('input');
    el.type = 'text';
    el.name = 'txtProvider' + iteration;
    el.id = 'txtProvider' + iteration;
    el.size = 20;  
    cellRight.appendChild(el);

    var cell7 = row.insertCell(8);
    var sel5 = document.createElement('select');
    sel5.name = 'selType' + iteration;
    sel5.id = 'selType' + iteration;
    sel5.options[0] = new Option('---Any---', '---Any---');
    sel5.options[1] = new Option('Fees, 'Fees);
    sel5.options[2] = new Option('Reimbursement', 'Reimbursement');
    cell7.appendChild(sel5);
}
Était-ce utile?

La solution 2

First off, what is your question? Are you getting an error? What results you are getting now - and how do they differ from what you expected?

Without knowing more about your form/data structure, I usually recommend using unique form field names in this case. When you use the same name for multiple fields, the field values are submitted as a comma delimited list. That can cause problems when the value itself contains a comma, because there is no way to determine where one value ends and the other begins.

To create unique field names, have your javascript append a counter number to each set of fields. So the fields will be named:

  • FORM.GrandNum1, FORM.GrandNme1, FORM.sectCode1, FORM.txtComments1, ...
  • FORM.GrandNum2, FORM.GrandNme2, FORM.sectCode2, FORM.txtComments2, ...
  • FORM.GrandNum3, FORM.GrandNme3, FORM.sectCode3, FORM.txtComments3,...`

Then store the total number in a hidden field. On your action page, do a simple from/to loop. If needed, use cfparam to set a default value for any fields that might not exist like checkboxes or radio buttons (text fields always exist). Then you can use null attribute of cfqueryparam which is a bit cleaner than isDefined or structKeyExists IMO.

    <cfparam name="FORM.totalFields" default="0">
    <cfloop from="1" to="#FORM.totalFields#" index="i">

       <!--- extract current set of values --->
       <cfset variables.txtComments = TRIM( FORM["txtComments"& i] )>
       <cfset variables.sectCode = TRIM( FORM["sectCode"& i] )>
       ...
       <cfquery name="AppendForm" datasource="TestSource">
          INSERT INTO tblGrand (Comments, SectCode ....)
          VALUES 
          (
            <cfqueryparam cfsqltype="cf_sql_varchar" value="#variables.txtComments#" null="#not len(variables.txtComments)#">
            , <cfqueryparam cfsqltype="cf_sql_varchar" value="#variables.sectCode#" null="#not len(variables.sectCode)#">
       ...
          )
       </cfquery>

    </cfloop>



UPDATE:

Based on your updates, your existing code is very close to what I originally described above. You just need to add the hidden field, and update it each time you add a row. Then the cfloop code above should work just fine.

    function addRow() {
        // removed extra variables
        var tbl = document.getElementById('tblSample');
        var row = tbl.insertRow(tbl.rows.length);

        // use hidden value to calculate total fields
        var iteration = parseInt(document.getElementById('totalFields').value) + 1;

        var cellLeft = row.insertCell(0);
        var textNode = document.createTextNode(iteration);

        ... etcetera ...

        // save new total 
        document.getElementById('totalFields').value = iteration;

     }

    ...

    <input type="hidden" id="totalFields" name="totalFields" value="0" />

UPDATE:

A few other comments

  1. There is no need for cfoutput around the query loop. The variables will be evaluated automatically
  2. Always use cfqueryparam when processing user supplied values to prevent sql injection. Especially when looping. cfqueryparam uses bind variables which can "enhance performance when executing a cfquery statement multiple times."
  3. Do not use DateFormat in queries. It is designed for presentation and returns a string. Date strings can be misinterpreted depending on your database settings. To avoid ambiguity always insert date/time objects ie like now() and not strings. See Matt's example and his usage of now().

Autres conseils

You need to use VALUES to insert into the database. You should also be using structKeyExists instead of isDefined and you should be using cfqueryparam too. I'd also scope your variables too.

<cfloop from="1" to="#ArrayLen(tblSample)#" index="i">
  <cfquery name="AppendForm" datasource="TestSource">
  INSERT INTO tblGrand
  (GrandNum,
  GrandName, 
  County, 
  VersionType, 
  VersionNum, 
  SectCode, 
  Comments,      
  Provider,     
  TypeID,       
  SubmitDate) 
  VALUES (
  <cfif structKeyExists(form,"GrandNum")>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.GrandNum#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"GrandNme")>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.GrandNme#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"selCnty")>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.selCnty#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"VersionType")>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.VersionType#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"VersionNum")>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.VersionNum#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"SectCode"&i)>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form['SectCode'&i]#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"txtComments"&i)>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form['textComments'&i]#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"txtProvider"&i)>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form['txtProvider'&i]#">,
  <cfelse>
    NULL,
  </cfif>
  <cfif structKeyExists(form,"selType"&i)>
    <cfqueryparam cfsqltype="cf_sql_varchar" value="#form['selType'&i]#">,
  <cfelse>
    NULL,
  </cfif>
  <cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#">)
  </cfquery>
</cfloop>

This is in addition to the other two answers. I'll restrict it to two topics not previously mentioned.

First, sometimes it's more efficient to put your loop inside your query instead of having your query inside your loop. The details would depend on your database, but one generic way of doing it is like this:

insert into yourtable
(field1, field2, etc)
select null, null, etc
from SomeSmallTable
where 1 = 3
<cfloop>
union
select #value1#, #value2#, ect
from somesmalltable
</cfloop>

In sql server you wouldn't need the "from SomeSmallTable". In mysql you could use the values keyword and still use a loop.

This method won't work with a very large number of records for a variety of reasons, but it might be worth persuing.

Next, you might have to contend with blank form fields. This is particularly true for numeric and date fields where you can't simply insert an empty string. The good news is that cfqueryparam has a null attribute. Here is an example for a date datatype

<cfqueryparam = cfsqltype="cf_sql_date" value="#something#"
null = "#not isDate(something)#">

Since isDate returns false on an empty string, this will cause a null value to be inserted into your date field instead of crashing your query.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top