将@Html.EditorFor“日期”值传回控制器,操作值并传回视图以填充下拉列表

Posted

技术标签:

【中文标题】将@Html.EditorFor“日期”值传回控制器,操作值并传回视图以填充下拉列表【英文标题】:pass @Html.EditorFor "Date" value back to Controller, manipulate value and pass back to view to populate Dropdown list 【发布时间】:2015-01-15 13:02:03 【问题描述】:

我有以下 MVC 应用程序,请参见下面的前端:

“Invoice Date Created”是一个html5兼容的datepicker,基于以下方法:

http://www.aubrett.com/InformationTechnology/WebDevelopment/MVC/DatePickerMVC5.aspx

我对屏幕加载的要求如下:

1) 在日期和文本框更新的日期选择器“onSelect”上,我需要传递此值,例如2014/11/19 并将其操作为 yyyymm 格式(例如 201411)。有一个问题。它需要能够为当前时期以及上一时期创造这样的价值。

因此,2014/11/19 应使用两个选项填充“发票编号期间”下拉列表:

201411(本期)201410(上期)

有没有办法让我通过这个日期 2014/11/19 例如回到我的控制器,在那里我可以进行操作并将 201411 和 201410 返回到我的下拉列表?还是我想错了?我已经阅读了大量的 javascript 文章,但没有一篇完全符合我的需要。如何以及最好的方法是什么?

我是一个 MVC 和 Javascript 新手,所以很难理解这个..

编辑 - 这是我的代码:

Finance.cshtml

@model List<FinanceMVC.Models.FinanceViewModel>
@
    ViewBag.Title = "Index";


@using (Html.BeginForm("Finance", "Finance", FormMethod.Post, new  @class = "form-horizontal" ))

    <div class="col-md-1 fade in" style="margin-left: 5%; width: 100%; font-size: 11px; height: auto;">
        <div id="div_Finance_Container" style="width: 100%; height: 80%; overflow: auto; text-align: left;" runat="server" class="scroll-pane">
            <div style="height: 500px; overflow: auto;">
                <div><a href="#" id="addNew" class="add-another-cat smallest">Add New</a></div>
                <table id="dataTable" border="0">
                    <tr>
                        <th>Invoice Type</th>
                        <th>Invoice Number</th>
                        <th>Invoice Number Period</th>
                        <th>Invoice Date Created</th>
                        <th></th>
                    </tr>
                    @if (Model != null && Model.Count > 0)
                    
                        int j = 0;
                        foreach (var i in Model)
                        
                        <tr>
                            <td>
                                <div class="col-md-1" style="width: 20%;">
                                    <select name="ddlInvoiceType">
                                        @foreach (var item in Model)
                                        
                                            foreach(var bItem in item.InvoiceType)
                                            
                                                <option value="@bItem.Description">@bItem.Description</option>
                                            
                                        
                                    </select>
                                </div>
                            </td>
                            <td>@Html.TextBoxFor(a => a[j].InvoiceNumber)</td>
                            <td>@Html.TextBoxFor(a => a[j].InvoiceNumberPeriod)</td>
                            <td>@Html.EditorFor(a => a[j].InvoiceDateCreated)</td>
                            <td>
                                @if (j > 0)
                                
                                    <a href="#" class="remove">Remove</a>
                                       
                            </td>
                        </tr>
                                j++;
                        
                    
                </table>
                <input type="submit" value="Save Bulk Data" />
            </div>
        </div>
    </div>
 


@section Scripts
@Scripts.Render("~/bundles/jqueryval")

<script language="javascript">
    $(function () 
        $(document).on('change', '#InvoiceDateCreated', function () 
            alert($(this).val());
        );
    );
</script>

<script type="text/javascript">
    $(document).ready(function () 
        $('#[0].InvoiceDateCreated').change(function () 
            $('#[0].InvoiceDateCreated').text('sam');
        );
    );
</script>

<script language="javascript">
    $(document).ready(function () 

        //1. Add new row
        $("#addNew").click(function (e) 
            e.preventDefault();
            var $tableBody = $("#dataTable");
            var $trLast = $tableBody.find("tr:last");
            var $trNew = $trLast.clone();

            var suffix = $trNew.find(':input:first').attr('name').match(/\d+/);
            $trNew.find("td:last").html('<a href="#" class="remove">Remove</a>');
            $.each($trNew.find(':input'), function (i, val) 
                // Replaced Name
                var oldN = $(this).attr('name');
                var newN = oldN.replace('[' + suffix + ']', '[' + (parseInt(suffix) + 1) + ']');
                $(this).attr('name', newN);
                //Replaced value
                var type = $(this).attr('type');
                if (type.toLowerCase() == "text") 
                    $(this).attr('value', '');
                

                // If you have another Type then replace with default value
                $(this).removeClass("input-validation-error");
            );
            $trLast.after($trNew);

            // Re-assign Validation 
            var form = $("form")
                .removeData("validator")
                .removeData("unobtrusiveValidation");
            $.validator.unobtrusive.parse(form);
        );

        // 2. Remove 
        $('a.remove').live("click", function (e) 
            e.preventDefault();
            $(this).parent().parent().remove();
        );

    );
</script>

Finance.cs(模型):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace FinanceMVC.Models

    //public class Finance
    //

    //

    public partial class FinanceViewModel
    
        /*ID*/
        [Required]
        [Display(Name = "ID")]
        public int ID  get; set; 

        /*BINL_BIND_ID*/
        [Required]
        [Display(Name = "Invoice Type")]
        //public int InvoiceType  get; set; 
        public List<C_InvoiceType> InvoiceType  get; set; 

        /*BINL_Inv_Num_Pointer*/
        [Required]
        [Display(Name = "Invoice Number")]
        public char InvoiceNumber  get; set; 

        /*BINL_Inv_Num_Period*/
        [Required]
        [Display(Name = "Invoice Number Period")]
        public int InvoiceNumberPeriod  get; set; 

        /*BINL_Created*/
        [Display(Name = "Invoice Created Date")]
        [Required]
        [DataType(DataType.DateTime)]
        public DateTime InvoiceDateCreated  get; set; 

        /*BINL_SystemInserted*/
        [Required]
        [Display(Name = "Invoice System Inserted")]
        public bool InvoiceSystemInserted  get; set; 


    

    public class C_InvoiceType
    
        public int ID  get; set; 
        public string Description  get; set; 
    

FinanceController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using FinanceMVC.Models;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;

namespace FinanceMVC.Controllers

    public class FinanceController : Controller
    
        public ActionResult Finance()
        
            FinanceViewModel FVM = new FinanceViewModel();

            // This is only for show by default one row for insert data to the database
            List<FinanceViewModel> FinanceViewList = new List<FinanceViewModel> 
             
                new FinanceViewModel 
                 
                    ID = 0 , InvoiceType = ReturnInvoiceType(), InvoiceNumber = '\0', InvoiceNumberPeriod = 0, InvoiceDateCreated = DateTime.Now, InvoiceSystemInserted = false 
                 
            ;

            return View(FinanceViewList);
        

        // 
        // GET: /Finance/ 

        /*Matches file name of Finance.cshtml*/
        [HttpPost]
        public ActionResult Finance(List<FinanceViewModel> model)
        
            if (ModelState.IsValid)
            

            

            return View(model);
        

        // 
        // GET: /Finance/Welcome/ 

        public string Welcome()
        
            return "This is the Welcome action method...";
        

        public static List<C_InvoiceType> ReturnInvoiceType()
        
            string sQ = ""
                       + " Select ID, BIND_Description \n"
                       + " From Biller_InvoiceNum_DefSet with(nolock) \n"
                       ;
            try
            
                using (SqlConnection sCon = new SqlConnection(Application_Info.sMOB_Master_Conn()))
                
                    if (sCon.State != ConnectionState.Open)
                    
                        sCon.Open();
                    

                    using (SqlCommand sCmd = new SqlCommand(sQ, sCon))
                    
                        using (SqlDataReader sRdr = sCmd.ExecuteReader())
                        
                            List<C_InvoiceType> list_InvoiceType = new List<C_InvoiceType>();
                            while (sRdr.Read())
                            
                                list_InvoiceType.Add(new C_InvoiceType
                                
                                    ID = (int)sRdr["ID"],
                                    Description = (string)sRdr["BIND_Description"]
                                );
                            
                            return list_InvoiceType;
                        
                    
                
            
            catch
            

            

            return ReturnInvoiceType();
        
    

【问题讨论】:

为什么不直接在客户端使用 javascript/jqeury。您可以轻松创建这 2 个选项并更新下拉列表,而无需调用服务器。 您已将InvoiceNumberPeriod 的控件呈现为文本框,但您的问题说它是一个下拉菜单。你要哪个? @StephenMuecke,它仍然是一个文本框,将其更改为下拉列表。因此,必须填充下拉列表。 @StephenMuecke,将对此进行进一步调查。对不起,就像我说的,我是一个 Javascript 菜鸟,所以很快看到解决方案有点棘手。 所以本质上,每次选择日期时,您都希望呈现 2 个选项,一个用于当前月份,一个用于上个月,格式为“yyyyMM”? 【参考方案1】:

编辑:

对于使用 MVC 5 而不是 MVC 5.1 的任何人,请继续阅读并在下面找到解决方法。对于使用 MVC 5.1 的任何人,请参阅 @StephenMuecke 的回答,因为这适用于 5.1。

原帖:

感谢@StephenMuecke,我找到了一个解决方案,以防其他人遇到同样的问题

东西。下面是我的完整解释和代码。

一些帖子建议使用 TextBoxFor 代替,但这会破坏 默认 html5 日期选择器

基本上,我们的应用程序是一个空白的 MVC 5 应用程序(Visual Studio 2012 with Web Installer),

提出EditorFor控件不接受html属性作为参数的问题。请

请参阅下面的链接:

MVC5 and Bootstrap3: Html.EditorFor wrong class? How to change?

Asp.net MVC5 with Bootstrap EditorFor size

Is there a solution for using ASP.NET MVC 5 Html.EditorFor() and Bootstrap 3.0?

综上所述,MVC 5.1 具有此功能。任何使用 MVC 5 的人都不能像下面这样添加@class 属性:

@Html.EditorFor(a => a[j].InvoiceDateCreated, new  htmlAttributes = new  @class = "InvoiceDateCreated" )

相反,我使用了下面提到的以下解决方法:

Change id attribute of an html.editorfor helper in MVC4 with Razor

结果如下:

@Html.EditorFor(a => a[j].InvoiceDateCreated, null, "ID")

如果我们在 Chrome 中查看(再次感谢 Stephen),代码如下:

<input class="form-control datecontrol" data-val="true" data-val-date="The field Invoice Created Date must be a date." data-val-required="The Invoice Created Date field is required." id="myID" name="myID" type="date" value="2014/11/19" />

正如我们所看到的,现在我们可以在 jQuery 中使用它来呈现带有 id 属性的控件,如下所示:

<script>
    function padLeft(nr, n, str) 
        return Array(n - String(nr).length + 1).join(str || '0') + nr;
    

    $('#myID').change(function () 
        var row = $(this).closest('tr');
        var date = new Date($(this).val());
        var currentMonth = date.getFullYear().toString() + padLeft(date.getMonth() + 1, 2);
        date.setMonth(date.getMonth() - 1);
        var previousMonth = date.getFullYear().toString() + padLeft(date.getMonth() + 1, 2);
        var select = row.find('#InvoiceNumberPeriod').empty();
        select.append($('<option></option>').val(currentMonth).text(currentMonth));
        select.append($('<option></option>').val(previousMonth).text(previousMonth));
    );
</script>

它现在完美运行。不确定它是否是最优雅的解决方案,或者它对“最佳实践”列表的评价有多高,但它确实有效。

【讨论】:

或者你可以使用@Html.TextBoxFor(a =&gt; a[j].InvoiceDateCreated, new @class = "InvoiceDateCreated", @type = "date" ) 来呈现浏览器的数据选择器。而且由于您的问题在循环中呈现了此问题,因此您会生成重复的 id(无效的 html)和名称属性(因此它不会回发),因此它绝对是 not best practice :- ) 谢谢,做了这个改变。真的很有帮助,@StephenMuecke,非常感谢。【参考方案2】:

您可以使用 jquery 完成此客户端,而无需调用服务器。由于您有多行,因此您需要为控件指定一个类名,以便可以选择它们,例如

@Html.EditorFor(a => a[j].InvoiceDateCreated, new  htmlAttributes = new  @class = "InvoiceDateCreated" )

并添加以下脚本

function padLeft(nr, n, str) 
  return Array(n - String(nr).length + 1).join(str || '0') + nr;


$('.InvoiceDateCreated').change(function () 
  var row = $(this).closest('tr');
  var date = new Date($(this).val());
  var currentMonth = date.getFullYear().toString() + padLeft(date.getMonth() + 1, 2);
  date.setMonth(date.getMonth() - 1);
  var previousMonth = date.getFullYear().toString() + padLeft(date.getMonth() + 1, 2);
  var select = row.find('.InvoiceNumberPeriod').empty();
  select.append($('<option></option>').val(currentMonth).text(currentMonth));
  select.append($('<option></option>').val(previousMonth).text(previousMonth));
);

【讨论】:

快来试一试。 请注意,您在呈现集合的方式方面存在许多问题。例如,您有一个删除函数来删除一行,但如果您删除了 5 行中的第 3 行,则只有前 2 行会回发(您没有 Index 属性,因此如果名称索引器绑定失败不从零开始并且是连续的)。还有其他问题。 是的,我也意识到在非 html5 浏览器中“adEventListener”不再受支持,对吧?仍然会克服这些问题。不幸的是,认为 Javascript 方面存在问题。尝试实现更改和功能,但遇到了一些问题。会不断更新。感谢您迄今为止的所有反馈。 注意我在脚本的最后两行做了一些更正(忘记了一些引号) 谢谢,我只是在让它工作时遇到了一些麻烦。它永远不会触发我放置在 "$('.InvoiceDateCreated').change(function () " 部分中的警报。【参考方案3】:

如果你想从javascript调用控制器,你可以使用ajax post函数。

    $.ajax(
        type: "POST",
        url: "Finance/Finance",
        dataType: "json",
        data: 
           // pass in some data
        ,
        success: function (results) 
            // do something (or nothing) with the returned data
        ,
        error: function (e) 
            alert(e.status + " - " + e.statusText);
        
    );

【讨论】:

谢谢,我也会尽快尝试一下@Grentley。 我已经尝试过这种方法,但我恐怕无法实现?我已经到了这一点,在页面加载时它会返回到 url。但是,我需要在选定日期执行此操作的东西。我意识到这是我对 Javascript/ajax 等方面的知识缺乏。但我似乎无法做到这一点..

以上是关于将@Html.EditorFor“日期”值传回控制器,操作值并传回视图以填充下拉列表的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 视图需要将选定的下拉列表和日历日期传递给模型

在单个(已禁用)@Html.EditorFor 上禁用验证

将 Int 属性从文本字段传回控制器

如何将@html.editorfor 居中?

当前日期和时间 - MVC razor 中的默认值

在 MVC 2 中将 css 类添加到 Html.EditorFor