如何从模板到子例程获取 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-1
、appx-1
和 growth-1
。
让我们看看 JavaScript 添加新行。我不打算在这里展示它,但它应该做的是包括 name
属性和 increment 数字。下一行应具有这些名称:dbname-2
、appx-2
和 growth-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 ...');
}
我有一个 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-1
、appx-1
和 growth-1
。
让我们看看 JavaScript 添加新行。我不打算在这里展示它,但它应该做的是包括 name
属性和 increment 数字。下一行应具有这些名称:dbname-2
、appx-2
和 growth-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 ...'); }