模型绑定 editable table 表单中的字段 (Razor Pages)
Model Binding editable table fields within a form (Razor Pages)
我的 Asp.Net 6 - Razor Pages 应用程序在表单中有一个 editable table。
我正在尝试将 editable table 字段绑定到模型,但不确定如何操作,因为 td
字段不能与 asp-for
一起使用标记助手。
我希望能够从页面模型的 OnPost()
方法中的 table 检索编辑后的值。
这些是我要从中检索值的两个 editable table 列的 ID:
对于 id="importColumn"
,当用户单击一个单元格时,此列的单元格值会使用 Javascript 单击处理程序从勾号更改为叉号.
对于 id="modifiedColumnNames"
,用户修改了此列中任何单元格的值。
.cshtml 格式:
<form method="post" asp-antiforgery="true">
<table id="columnsToImportTable" class="display roundedCorners" width="100%">
<thead>
<tr>
<th class="centreText">Column Name</th>
<th class="centreText">Import Column</th>
<th class="centreText">Database Column Name</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.newLayer.ColumnNames.Count(); i++)
{
<tr>
<td class="greyOutBackground centreText defaultCursor">@Model.newLayer.ColumnNames[i]</td>
<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true">✔
<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true">
</td>
<td id="modifiedColumnNames">
<div contenteditable>@Model.newLayer.ColumnNames[i]</div>
<input type="hidden" asp-for="@Model.newLayer.ColumnNames[i]">
</td>
</tr>
}
</tbody>
</table>
<div>
<input id="importButton" type="submit" value="Import">
</div>
</form>
Javascript/Jquery 点击处理程序:
$('#columnsToImportTable td.tick').click(function(e) {
e.stopPropagation();
e.preventDefault();
var $this = $(this);
if ($this.hasClass('true')) {
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor red tick false centreElement">✖<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="false"></td>');
} else {
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true centreElement">✔<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true"></td>');
}
$this.toggleClass('true');
});
型号:
public class NewLayer
{
public List<string> ColumnNames { get; set; } = new List<string>();
public List<string> ColumnDataTypes { get; set; } = new List<string>();
public List<string> LayerNames { get; set; } = new List<string>();
public List<string> ImportColumn { get; set; } = new List<string>();
public string SelectedLayer { get; set; } = null!;
public string SelectedNameField { get; set; } = null!;
}
页面模型:
public class IndexModel: PageModel {
private FileProcessor _FileProcessor = new FileProcessor();
private AppContext _context;
[BindProperty(SupportsGet = true)]
public NewLayer newLayer {get;set;}
public IndexModel(AppContext context) {
_context = context;
newLayer = new NewLayer();
}
public void OnGet() {
var filePath = "[FilePath]";
var ColumnNamesAndDatatypes = _FileProcessor.GetColumnNamesAndTypes(filePath);
for (var i = 0; i < ColumnNamesAndDatatypes.Count(); i++) {
newLayer.ColumnNames.Add(ColumnNamesAndDatatypes[i].ColumnName);
newLayer.ColumnDataTypes.Add(ColumnNamesAndDatatypes[i].DataType);
newLayer.ImportColumn.Add("true");
}
newLayer.LayerNames = _context.Layers.Select(l => l.LayerName).ToList();
}
public void OnPost(NewLayer newLayer) {
var test = this.newLayer;
}
}
由于您使用模型绑定方法提交表单并将数据从客户端传输到 back-end,我们应该根据视图模型设置隐藏字段的名称 属性 和索引。
到importColumn
列,当用户点击单元格时,可以使用clone()
方法获取importColumn
隐藏字段,然后更改其值属性,最后添加它到新的 td
元素。
对于modifiedColumnNames
列,当用户修改值时,需要将contenteditable div内容复制到隐藏字段。您可以使用 div 的 input
事件。
您可以参考以下代码:
Html 元素:为 modifiedColumnNames 隐藏字段添加 class。
<form method="post" asp-antiforgery="true">
<table id="columnsToImportTable" class="display roundedCorners" width="100%">
<thead>
<tr>
<th class="centreText">Column Name</th>
<th class="centreText">Import Column</th>
<th class="centreText">Database Column Name</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.newLayer.ColumnNames.Count(); i++)
{
<tr>
<td class="greyOutBackground centreText defaultCursor">@Model.newLayer.ColumnNames[i]</td>
<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true">✔
<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true">
</td>
<td id="modifiedColumnNames">
<div class="editdiv" contenteditable>@Model.newLayer.ColumnNames[i]</div>
<input type="hidden" asp-for="@Model.newLayer.ColumnNames[i]">
</td>
</tr>
}
</tbody>
</table>
<div>
<input id="importButton" type="submit" value="Import">
</div>
</form>
JS代码:
<script>
$(function(){
$('#columnsToImportTable td.tick').click(function(e) {
e.stopPropagation();
e.preventDefault();
var $this = $(this);
// get the ImportColumn hidden field.
var hiddentag = $(this).find("input[type='hidden']").clone();
if ($this.hasClass('true')) {
//change the hidend field' value
$(hiddentag).attr("value","false");
//get the html
var newtag = $(hiddentag)[0].outerHTML;
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor red tick false centreElement">✖' + newtag + '</td>');
} else {
$(hiddentag).attr("value","true");
var newtag = $(hiddentag)[0].outerHTML;
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true centreElement">✔' + newtag + '</td>');
}
$this.toggleClass('true');
});
//
$(".editdiv").each(function(index, item){
$(item).on('propertychange input', function (e) {
$(this).next("input[type='hidden']").val($(this).text());
});
});
});
</script>
Index.cshtml.cs:
public class IndexModel : PageModel
{
//private FileProcessor _FileProcessor = new FileProcessor();
//private AppContext _context;
[BindProperty(SupportsGet = true)]
public NewLayer newLayer { get; set; }
public IndexModel()
{
newLayer = new NewLayer();
}
public void OnGet()
{
for (var i = 0; i < 3; i++)
{
newLayer.ColumnNames.Add("Name " + i.ToString());
newLayer.ColumnDataTypes.Add("DataType " + i.ToString());
newLayer.ImportColumn.Add("true");
}
newLayer.LayerNames = new List<string>() { "L1", "L2" };
}
public void OnPost(NewLayer newLayer)
{
var test = this.newLayer;
}
}
结果是这样的:
我的 Asp.Net 6 - Razor Pages 应用程序在表单中有一个 editable table。
我正在尝试将 editable table 字段绑定到模型,但不确定如何操作,因为 td
字段不能与 asp-for
一起使用标记助手。
我希望能够从页面模型的 OnPost()
方法中的 table 检索编辑后的值。
这些是我要从中检索值的两个 editable table 列的 ID:
对于
id="importColumn"
,当用户单击一个单元格时,此列的单元格值会使用 Javascript 单击处理程序从勾号更改为叉号.对于
id="modifiedColumnNames"
,用户修改了此列中任何单元格的值。
.cshtml 格式:
<form method="post" asp-antiforgery="true">
<table id="columnsToImportTable" class="display roundedCorners" width="100%">
<thead>
<tr>
<th class="centreText">Column Name</th>
<th class="centreText">Import Column</th>
<th class="centreText">Database Column Name</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.newLayer.ColumnNames.Count(); i++)
{
<tr>
<td class="greyOutBackground centreText defaultCursor">@Model.newLayer.ColumnNames[i]</td>
<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true">✔
<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true">
</td>
<td id="modifiedColumnNames">
<div contenteditable>@Model.newLayer.ColumnNames[i]</div>
<input type="hidden" asp-for="@Model.newLayer.ColumnNames[i]">
</td>
</tr>
}
</tbody>
</table>
<div>
<input id="importButton" type="submit" value="Import">
</div>
</form>
Javascript/Jquery 点击处理程序:
$('#columnsToImportTable td.tick').click(function(e) {
e.stopPropagation();
e.preventDefault();
var $this = $(this);
if ($this.hasClass('true')) {
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor red tick false centreElement">✖<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="false"></td>');
} else {
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true centreElement">✔<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true"></td>');
}
$this.toggleClass('true');
});
型号:
public class NewLayer
{
public List<string> ColumnNames { get; set; } = new List<string>();
public List<string> ColumnDataTypes { get; set; } = new List<string>();
public List<string> LayerNames { get; set; } = new List<string>();
public List<string> ImportColumn { get; set; } = new List<string>();
public string SelectedLayer { get; set; } = null!;
public string SelectedNameField { get; set; } = null!;
}
页面模型:
public class IndexModel: PageModel {
private FileProcessor _FileProcessor = new FileProcessor();
private AppContext _context;
[BindProperty(SupportsGet = true)]
public NewLayer newLayer {get;set;}
public IndexModel(AppContext context) {
_context = context;
newLayer = new NewLayer();
}
public void OnGet() {
var filePath = "[FilePath]";
var ColumnNamesAndDatatypes = _FileProcessor.GetColumnNamesAndTypes(filePath);
for (var i = 0; i < ColumnNamesAndDatatypes.Count(); i++) {
newLayer.ColumnNames.Add(ColumnNamesAndDatatypes[i].ColumnName);
newLayer.ColumnDataTypes.Add(ColumnNamesAndDatatypes[i].DataType);
newLayer.ImportColumn.Add("true");
}
newLayer.LayerNames = _context.Layers.Select(l => l.LayerName).ToList();
}
public void OnPost(NewLayer newLayer) {
var test = this.newLayer;
}
}
由于您使用模型绑定方法提交表单并将数据从客户端传输到 back-end,我们应该根据视图模型设置隐藏字段的名称 属性 和索引。
到importColumn
列,当用户点击单元格时,可以使用clone()
方法获取importColumn
隐藏字段,然后更改其值属性,最后添加它到新的 td
元素。
对于modifiedColumnNames
列,当用户修改值时,需要将contenteditable div内容复制到隐藏字段。您可以使用 div 的 input
事件。
您可以参考以下代码:
Html 元素:为 modifiedColumnNames 隐藏字段添加 class。
<form method="post" asp-antiforgery="true">
<table id="columnsToImportTable" class="display roundedCorners" width="100%">
<thead>
<tr>
<th class="centreText">Column Name</th>
<th class="centreText">Import Column</th>
<th class="centreText">Database Column Name</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.newLayer.ColumnNames.Count(); i++)
{
<tr>
<td class="greyOutBackground centreText defaultCursor">@Model.newLayer.ColumnNames[i]</td>
<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true">✔
<input type="hidden" asp-for="@Model.newLayer.ImportColumn[i]" value="true">
</td>
<td id="modifiedColumnNames">
<div class="editdiv" contenteditable>@Model.newLayer.ColumnNames[i]</div>
<input type="hidden" asp-for="@Model.newLayer.ColumnNames[i]">
</td>
</tr>
}
</tbody>
</table>
<div>
<input id="importButton" type="submit" value="Import">
</div>
</form>
JS代码:
<script>
$(function(){
$('#columnsToImportTable td.tick').click(function(e) {
e.stopPropagation();
e.preventDefault();
var $this = $(this);
// get the ImportColumn hidden field.
var hiddentag = $(this).find("input[type='hidden']").clone();
if ($this.hasClass('true')) {
//change the hidend field' value
$(hiddentag).attr("value","false");
//get the html
var newtag = $(hiddentag)[0].outerHTML;
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor red tick false centreElement">✖' + newtag + '</td>');
} else {
$(hiddentag).attr("value","true");
var newtag = $(hiddentag)[0].outerHTML;
$this.html('<td id="importColumn" class="greyOutBackground centreText pointerCursor green tick true centreElement">✔' + newtag + '</td>');
}
$this.toggleClass('true');
});
//
$(".editdiv").each(function(index, item){
$(item).on('propertychange input', function (e) {
$(this).next("input[type='hidden']").val($(this).text());
});
});
});
</script>
Index.cshtml.cs:
public class IndexModel : PageModel
{
//private FileProcessor _FileProcessor = new FileProcessor();
//private AppContext _context;
[BindProperty(SupportsGet = true)]
public NewLayer newLayer { get; set; }
public IndexModel()
{
newLayer = new NewLayer();
}
public void OnGet()
{
for (var i = 0; i < 3; i++)
{
newLayer.ColumnNames.Add("Name " + i.ToString());
newLayer.ColumnDataTypes.Add("DataType " + i.ToString());
newLayer.ImportColumn.Add("true");
}
newLayer.LayerNames = new List<string>() { "L1", "L2" };
}
public void OnPost(NewLayer newLayer)
{
var test = this.newLayer;
}
}
结果是这样的: