如何使用模型将列表从视图正确连接到控制器 - javascript

我希望有一个表格,允许用户填写多个字段,当控制器接收到这些字段时,这些字段应压缩为一个对象。我很难找到可以解释这一点的单词,所以让我举个例子。

基本上,此对象(AllocationInformation)中有六个字段,这是模型的一部分:

AllocationInformation
{
    FundSource
    Function
    Location
    Program
    Subject
    Object
}

现在,模型中有一个List<AllocationInformation>。该视图将允许用户创建任意数量的Allocation对象。

因此,表单中有六个字段,并且有一个按钮让用户根据需要多次添加相同的六个字段中的另一个。

如果这些对象已经存在于模型中,则视图还需要能够呈现它们。我可以完成所有这些工作,但作为罪恶是丑陋的,我希望找到更好的方法。

目前我的看法是这样的:

<button type="button" class="btn btn-primary" onclick="addAllocation()">Add Allocation</button>
<div class="row">
    <div id="allocationsDiv" class="container">
        <div class="row">
            <div class="col-sm-1" id="fundSourceCol">FundSource</div>
            <div class="col-sm-1" id="functionCol">Function</div>
            <div class="col-sm-1" id="locationCol">Location</div>
            <div class="col-sm-1" id="programCol">Program</div>
            <div class="col-sm-1" id="subjectCol">Subject</div>
            <div class="col-sm-1" id="objectCol">Object</div>
            <div class="col-sm-1" id="removeCol">Remove?</div>
        </div>



        @if (Model.Allocations != null)
        {
            for (int i = 0; i < Model.Allocations.Count; i++)
            {
                <div>
                    @Html.TextBoxFor(m => m.Allocations[i], new { @class = "form-control input-xsmall" })
                </div>
            }
        }
    </div>
</div>

这是addAllocation()的javascript:

function addAllocation()
{
    var $row = $("<div class='row'></div>");

    $("#allocationsDiv").append($row);

    var fundSource = "<div class='col-sm-1'><input type='text' name='Allocation.FundSource' class='funding-source-item form-control' /></div>";

    $row.append(fundSource);

    var func = "<div class='col-sm-1'><input type='text' name='Allocation.Function' class='funding-source-item form-control col-sm-1' /></div>";

    $row.append(func);

    var location = "<div class='col-sm-1'><input type='text' name='Allocation.Location' class='funding-source-item form-control col-sm-1' /></div>";

    $row.append(location);

    var program = "<div class='col-sm-1'><input type='text' name='Allocation.Program' class='funding-source-item form-control col-sm-1' /></div>";

    $row.append(program);

    var subject = "<div class='col-sm-1'><input type='text' name='Allocation.Subject' class='funding-source-item form-control col-sm-1' /></div>";

    $row.append(subject);

    var object = "<div class='col-sm-1'><input type='text' name='Allocation.Object' class='funding-source-item form-control col-sm-1' /></div>";

    $row.append(object);

    var $remove = $("<div class='col-sm-1'><i class='glyphicon glyphicon-remove glyphicon-clickable col-sm-1 funding-source-item'></i></div>");

    $remove.on('click', function () {
        $row.remove()
    });

    $row.append($remove);



}

这就是问题所在。addAllocation()函数需要知道已进行了多少次分配的当前索引,以便它可以正确构建输入名称,因为它们应采用Allocation[i].FundSource形式,这意味着必须拥有一个全局javascript变量或类似的变量来跟踪它,这似乎是一个糟糕的主意。

我只是想必须要有一种我不知道的更好的方法。

如果有用的话,这是实际的AllocationInformation类:

public class AllocationInformation
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("CheckRequestModel")]
    public int CheckRequestId { get; set; }

    public CheckRequestModel CheckRequestModel { get; set; }

    public string FundSource { get; set; }

    public string Function { get; set; }

    public string Location { get; set; }

    public string Program { get; set; }

    public string Subject { get; set; }

    public string Object { get; set; }

    public float Amount { get; set; }

    public int VendorNumber { get; set; }
}

参考方案

您的Razor实现看起来不错。如果所有现有对象都应该正确回传List<AllocationInformation>对象。

问题出在您的JavaScript实现上。首先,您当前的JavaScript代码甚至都没有考虑索引。所有字段名称均采用Allocation.Foo的形式。相反,它们必须采用Allocations[N].Foo的形式(也请注意复数形式)。

实际上,获取当前索引并不容易。在您的addAllocation JavaScript方法中,只需执行以下操作:

var currentIndex = $('#allocationsDiv .row').length - 1;

然后,在字段名称中使用currentIndex变量代替N

对于它的价值,您可能需要考虑将诸如Knockout JS之类的东西集成到您的项目中。它使得处理诸如渲染集合之类的事情变得微不足道。您可以创建一个通用的“行”模板,然后将该模板绑定为可观察数组的每个实例呈现。然后,要添加或删除行,您只需要从数组中添加或删除项,而Knockout会相应地更新HTML。

编辑

值得一提的是,我为您提供的查找当前索引的方法仅在未将项目带外移除的情况下才有效。例如,如果您从三个项目(索引0、1和2)开始,删除第二个项目(索引1),然后添加一个新项目,则实际上您将再次以0、2和2为索引。显然,这是行不通的。您可以在删除所有现有项后尝试为其重新编制索引,这将需要选择每一行,并基于for循环使用新索引更新名称参数。但是,那确实很笨拙。这就是为什么您应该使用像Knockout JS这样的东西的另一个原因。所有这些逻辑开箱即用。

更新:淘汰赛速成班

通常,这就是我使用Knockout代码为视图设置代码的方式:

外部JS

var Namespace = Namespace || {};

Namespace.Application = (function () {
    var _init = function (data) {
        var viewModel = Namespace.ViewModel(data);
        ko.applyBindings(viewModel);
        _wireEvents(viewModel);
        return viewModel;
    };

    var _wireEvents = function (viewModel) {
        $('#AddAllocation').on('click', viewModel.AddAllocation);
        $('#Allocations).on('click', '.remove', viewModel.RemoveAllocation);
        // other event handlers here
    };

    return {
        Init: _init
    };
})();

Namespace.ViewModel = function (data) {
    var self = {};

    self.Allocations = ko.observableArray(
        $.map(data.Allocations, Namespace.AllocationViewModel)
    );

    self.AddAllocation = function () {
        self.Allocations.push(new Namespace.AllocationViewModel(Namespace.Allocation));
    };

    self.RemoveAllocation = function () {
        var data = ko.dataFor(this);
        self.Allocations.remove(data);
    };

    return self;
};

Namespace.AllocationViewModel = function (data) {
    var self = {};

    self.Id = ko.observable(data.Id);
    self.CheckRequestId = ko.observable(data.CheckRequestId);
    // etc.

    return self;
};

页面JS

<script>
    var Namespace = Namespace || {};

    Namespace.Allocation = @Html.Raw(Json.Encode(YourProject.Namespace.To.AllocationInformation));

    $(document).ready(function () {
        var data = @Html.Raw(Json.Encode(Model));
        Namespace.Application.Init(data);
    });
</script>

此处使用的Namespace变量是对应用程序使用名称空间的一般指示。在JavaScript中污染全局名称空间是一种不好的形式,因此您只需创建一些对组织唯一的变量(通常是公司名称),然后将所有变量和函数放在该对象上。

Namespace.Application对象是视图的核心功能。您可以随意命名。它不必称为Application

Namespace.Allocation只是您拥有的AllocationInformation类的JavaScript对象表示。存储此内容使您可以轻松地基于此对象模板添加新分配。

Namespace.ViewModel是主要的淘汰赛视图模型,Namespace.AllocationViewModel是特定于单个分配的视图模型。主视图模型最终将带有一个可观察的数组(通过$.map)。

在此示例代码中,我手动创建了所有可观察对象。实际上,有一个适用于Knockout的映射插件,可让您执行以下操作:

Namespace.ViewModel = function (data) {
    var model = ko.mapping.fromJS(data);

    return model;
}

它为data对象的任何成员自动创建可观察对象。然后,您只需要向视图模型添加其他所需的东西,而不必手动拼出每个属性。

当<form>'.submit'函数被覆盖时(使用Ajax)将数据获取到php吗? - javascript

我已覆盖此网页上表单的.submit函数,因为该网页已加载在“ index.php”中的#mainContent内,并且我希望“提交”按钮仅替换此#mainContent。我正在尝试将数据从此表单获取到.php文件,以便对数据库进行查询(或简单地回显已填充的变量,以指示已传递数据)。我是AJAX的新手。有人可以向我解释如何将数据传递到.php文件,或者指向要…

使用php重新加载内容 - javascript

在对网站进行编程时,我以前使用过此代码,它可以完美工作,但是现在当我想使用一些Flash部件时,每次单击链接时,它都会重新加载所有网站。源代码: <!DOCTYPE html> <html> <head> <title>Hot King Staff</title> <meta charset=…

用jQuery填充模式形式 - javascript

我正在将订单表从数据库绘制到datatables(jquery插件)中。我要在每笔最后一笔交易或每笔交易中增加付款。问题是,如何获取单击添加付款按钮以添加付款的行的订单ID。其次,当点击addpayment时,它会弹出一个带有字段或订单号的模态表单。我想用在td中找到的订单ID填充该字段,并使其不可编辑或隐藏,但在提交模态表单时将其发布到服务器。表格和模式表…

保留文本区域的数据或值,然后选择输入 - javascript

通过$ _POST提交表单时,输入文件值仍然保留。像这样: if($_POST){ $error = false; if(!$post['price']){ $error = true; $error_note['price'] = "*Should not be empty"; } if($err…

混合码错误 - javascript

好的,我在网站上为用户个人资料提供了一个基本的多合一页面,如下所示:<?php if($_GET['p']=='pb'){ echo '<p>pb</p>'; }elseif($_GET['p']=='example2'){ ec…