如何从模板到子例程获取 table 值?

How to get table values from template to subroutine?

我有一个 table 和 table_id="mytable"

我需要在单击提交后发送操作子例程中 table 的所有行。在子程序中,我需要在修改一些值后将行逐行插入到table中。

最简单的方法是什么?


我的真实模板:

<form method="post" action="/savesmop" >
<section class="wrapper">
  <h1>Select Items and add components</h1>
  <ul class="tabs">
<% FOREACH Component_Id IN components.keys.nsort %>
    <li><a href="#tab<% components.$Component_Id.Component_Id %>"><% components.$Component_Id.Component_Name %></a></li>
<% END %>
  </ul>
  <div class="clr"></div>
  <section class="block">
<% FOREACH Component_Id IN **components.keys.nsort** %>
    <article id="tab<% components.$Component_Id.Component_Id %>">
 <% FOREACH ACTIVITY_ID IN activities.keys.nsort %>
  <% IF activities.$ACTIVITY_ID.Component_Id == components.$Component_Id.Component_Id  %>
         <input class="toggle-box" id="t<% activities.$ACTIVITY_ID.ACTIVITY_ID %>" name="t<% activities.$ACTIVITY_ID.ACTIVITY_ID %>" type="checkbox" >
   <label for="t<% activities.$ACTIVITY_ID.ACTIVITY_ID %>"><% activities.$ACTIVITY_ID.ACTIVITY_NAME %>
     <input type="button" class="btnsmall1" onclick="addRow('<% activities.$ACTIVITY_ID.ACTIVITY_ID %>')" value="+" />
              <input type="button" class="btnsmall2" onclick="deleteRow('<% activities.$ACTIVITY_ID.ACTIVITY_ID %>')" value="X" />
   </label>
   <div>
   
   <table id="<% activities.$ACTIVITY_ID.ACTIVITY_ID %>" name="<% activities.$ACTIVITY_ID.ACTIVITY_ID %>">
   <tr><td><input type="checkbox" name="chk"/></td>
   <% FOREACH ATTRIBUTE_ID IN attributes.keys.nsort %>
    <% IF attributes.$ATTRIBUTE_ID.ACTIVITY_ID == activities.$ACTIVITY_ID.ACTIVITY_ID %>
     
     <td>
     <% IF attributes.$ATTRIBUTE_ID.ATTRIBUTE_NAME == 'Object Type' %>
     <select id="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>" name="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>">
     <option value="" disabled selected>Select Object Type</option>
     <option value="TABLE">TABLE</option>
     <option value="VIEW">VIEW</option>
     <option value="OTHER">OTHER</option>
     </select>
     <% ELSIF attributes.$ATTRIBUTE_ID.ATTRIBUTE_NAME == 'SVN Path' %>
     <input size="90" type="TEXT" placeholder="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_NAME %>" id="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>" name="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>"/>
     <% ELSE %>
     <input type="TEXT" placeholder="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_NAME %>" id="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>" name="<% attributes.$ATTRIBUTE_ID.ATTRIBUTE_ID %>"/>
     <% END %>
     </td>
    <% END %>
   <% END %>
   </tr>
   </table>
   </div>
   <br>
  <% END %>
 <% END %>
     </article>
<% END %>
</section>
</section>

<input class="btn2" type="submit" value="SAVE" />

</form>

我从 3 个不同的数据库 table 中选择了 3 个哈希值,并循环遍历它们以动态生成此模板。

如您所见,每个列表项中有多个 table,每个 table 中的列数也不同。我在 javascript 中所做的是在添加一行的同时克隆 table 的第一行。我不知道如何在 javascript addrow 函数中添加新行时将每个文本输入的名称标签递增 1。

下面是我的 javascript 函数:

function deleteRow(tableID) 
    { 
        try
        { 
            var table = document.getElementById(tableID);
            var rowCount = table.rows.length;

            for(var i=0; i<rowCount; i++) 
            {

                var row = table.rows[i];
                var chkbox = row.cells[0].childNodes[0];

                if(null != chkbox && true == chkbox.checked)
                {
                    table.deleteRow(i);
                    rowCount--;
                    i--;
                }
            }
        }
        catch(e){alert(e);}
    }

function addRow(tableID) 
    {

      var table = document.getElementById(tableID); // find table to append to

      var row = document.getElementById(tableID).rows.item(0); // find row to copy

      var clone = row.cloneNode(true); // copy children too
      clone.id = "newID"; // change id or other attributes/contents
      table.appendChild(clone); // add new row to end of table
       }

既然你没有说明你使用的是哪个 Dancer 版本,我假设你使用的是 first version of Dancer (and not Dancer2)。

您似乎不确定通过 GET 或 POST 提交表单时一般是如何工作的。这不是 Dancer 特有的,但对 HTTP 协议的工作方式非常通用,并且与 HTML.

相关联

如果您的 HTML 文档中有表单,则 <input><textarea> 等表单元素需要具有 name 属性。这就是将进入请求的内容。 id 属性仅适用于 CSS 和 JS(已简化)。

<form action="/save" method="GET">
  <input type="text" name="foo" id="input-foo" />
  <input type="submit" value="save" />
</form>

如果您输入 bar 并点击该按钮,您的浏览器将导航至:

/save?foo=bar

如果 <input> 上没有 name 属性,浏览器将忽略它。

<form action="/save" method="GET">
  <input type="text" id="input-foo" />
  <input type="submit" value="save" />
</form>

这将引导您:

/save

如果您不想显示 submit 按钮的 value,这也很有用。只是不要给它一个 name 属性。

好的,现在您有多行输入字段。那些是动态的。您为 <table><input> 元素指定了整数作为 id。这很奇怪,但应该不是问题。但是没有name个属性.

你应该给每个 <input> 一个不同的名字。例如,使用与您的占位符相关的名称。

<table id="101">
    <tr>
        <td><input type="checkbox" name="chk" /></td>
        <td><input type="text" placeholder="Database Name" name="dbname-1" /></td>
        <td><input type="text" placeholder="Database Appx Size" id="appx-1" /></td>
        <td><input type="text" placeholder="Rate of growth" id="growth-1" /></td>
    </tr>
</table>

现在一行包含三个不同的名称:dbname-1appx-1growth-1

让我们看看 JavaScript 添加新行。我不打算在这里展示它,但它应该做的是包括 name 属性和 increment 数字。下一行应具有这些名称:dbname-2appx-2growth-2。你在这里得到模式。

最后,我们需要在 Perl 代码中做一些事情。我们将获取所有参数,将它们过滤为我们感兴趣的三种字段类型,然后迭代这些参数以插入它们。我们还将确保它们不为空。

post '/savesmop' => sub {

    # get all the parameters
    my %values = params;

    # remove unwanted ones that don't belong to the rows
    foreach my $key ( keys %values ) {
        delete $values{$key} unless $key =~ m/^(?:dbname|appx|growth)-/;
    }

    my $dbh = DBI->connect( 'dbid', 'user', 'pwd' ) or die $DBI::errstr;
    my $sth = $dbh->prepare("INSERT INTO TABLE_Fact VALUES (?,?,?)") or die $dbh->errstr;

    # iterate over the dbnames only
    foreach my $dbname ( grep {m/^dbname/} sort keys %values ) {

        # field should not be empty
        next unless $values{$dbname};

        # fetch the number from the dbname...
        ( undef, my $id ) = split /-/, $dbname;

        # ... and the other two should exist and not be empty also
        next unless my $appx = $values{ 'appx-' . $id };
        next unless my $pwd  = $values{ 'pwd-' . $id };

        # now insert
        $sth->execute( @values{ $dbname, $appx, $pwd } ) or die $dbh->errstr;
    }
    template "savesmop";

};

关键是你不需要知道有多少。 while 循环不是将内容插入数据库的最佳方法。通常,您使用 for 循环迭代数据。 Perl 的 foreach my $item (@list) 语法特别有用,因为您不必关心 array/list 有多长。


几个侧节点:

  • 您是否考虑过使用 DBIx::Class? There is a good plugin for that called Dancer::Plugin::DBIC 来简化您的 Dancer 应用程序的使用。 DBIx::Class 有一些学习曲线,但值得!
  • 如果您被对象关系映射器吓到或认为它太过分了,请改为查看 Dancer::Plugin::Database。它有助于将 $dbh 抽象出来,您无需关心连接。
  • 如果你根本不需要插件(这不是一个明智的决定,如果其他人已经完成了工作并且经过了充分测试总是好的!),至少不要不要在路由处理程序中建立与数据库的新连接。 Dancer 运行 一直在运行(除非您 运行 将其作为 CGI),因此它将受益于保持连接打开。在应用程序代码的顶部连接到 DB,并将其保存在 config 中。这很奇怪,但效率更高。

    use Dancer;
    use DBI;
    
    config 'dbh' => DBI->connect('...') or die $DBH::errstr;
    
    get '/foo' => sub {
      config->dbh->prepare('select ...');
    }