在下拉列表的值更改时更改EditorFor的值

3
我尝试制作一个在线银行网站(用于学习ASP.NET MVC)。我有一个类叫做Account
class Account
{
int account_id;
String account_number;
decimal balance;
}

我有一个与交易相关的模型。

 public class MakeTransactionModel
    {
        [Required]
        public String AccountFrom { get; set; }
        [Required]
        public String AccountTo { get; set; }

        public Decimal OrignalBalance { get; set; }
        [Required]
        public Decimal Amount { get; set; }
        [Required]
        public String TransactionFor { get; set; }
    }

然后在控制器中,我将账户放入ViewBag中。
ViewBag.account_from = new SelectList(db.Accounts, "account_id", "account_number");

在View中,我创建了一个下拉菜单,用于显示所有账户。
@Html.DropDownListFor(u => u.AccountFrom, (SelectList)ViewBag.account_from, htmlAttributes: new { @class = "form-control", @id = "AccountFrom", onchange=@"
                    @Model.OrignalBalance = 1000; // I tried this but did not work
                " })

现在,我正在尝试在EditorFor中显示所选账户的余额。

@Html.EditorFor(model => model.OrignalBalance, new { htmlAttributes = new { @id="OrignalBalance", @class = "form-control", disabled = "disabled", @readonly = "readonly" } })

我有所有的账户在 ViewBag 中,并在下拉菜单中显示这些账户的编号(这些账户也有余额)。我尝试在 DropDownFor 值改变时更改 EditorFor 的值,但仍然无法实现。我尝试使用 jquery 来实现,但不知道是否可以在 jquery 中使用 LINQ

我的 jquery 代码如下:

 <script type="text/javascript">

        $(document).ready(function () {
            $(function () {
                $('#AccountFrom').change(function () {
                    var selectedValue = $('#AccountFrom').text();
                    $('#OrignalBalance').val(@{new BankEntities().Accounts.SingleOrDefault(acc => acc.account_number == $('#AccountFrom').text())});   // I am trying to do this
                });
            });
        }
    )
    </script>

如果我能找到一个好的解决方案,就可以在更改事件上更新EditorFor。谢谢。

3个回答

5

您需要进行一次ajax调用,传递账户号码,并从服务器获取金额。

$(function()
{
    $('#AccountFrom').change(function() {
    var accountId= $('#AccountFrom').val();
    var url="@Url.Action("Balance","Account")";
       $.post(url+"?accountNumber="+accountId,function(response){
          if(response.Status==="success")
          {
            $("#OrignalBalance").val(response.Balance);
          }
          else
          {
             alert("Invalid Account");
          }
       });
    });
});

假设您有一个操作方法来返回余额。
[HttpPost]
public ActionResult Balance(string accountNumber)
{
   //Of course you want to authorize the call
   var db=new BankEntities();
   var a= db.Accounts.FirstOrDefault(x=> x.account_number ==accountNumber);
   if(a!=null)
   {
      return Json( new { Status="success", Balance=a.Balance });
   }
   else
   {
     return Json( new { Status="error"});
   }
}

如果您不想使用操作方法和ajax方式,您可以创建一个包含账户号码和余额的字典,并将其作为视图模型的一部分传递。在razor视图中,将其设置为js对象,在更改事件中,您可以查询js字典以获取值。
此外,我建议不要使用ViewBag在操作方法和视图之间传输数据以呈现下拉列表。您应该添加一个强类型属性来处理它。
因此,让我们向您的视图模型添加一些新属性。
public class MakeTransactionModel
{
   // Your other existing properties here

   public Dictionary<string,decimal> AccountBalances { set; get; }   

   // These 2 properties are for rendering the dropdown.
   public int FromAccountId { set; get; }
   public List<SelectListItem> FromAccounts { set; get; }  
}

在你的GET请求中,使用账户号码和相应的余额值填充该属性。
public ActionResult Transfer()
{
  var vm = new MakeTransactionModel();
  vm.AccountBalances = new Dictionary<string, decimal>();
  // Hard coded for demo. You may read it from your db tables.
  vm.AccountBalances.Add("CHECKING0001", 3450.50M);
  vm.AccountBalances.Add("SAVINGS0001", 4450.50M);

   //load the data for accounts.pls change to get from db
   vm.FromAccounts = new List<SelectListItem>
   {
       new SelectListItem { Value="CHECKING0001", Text="Checking" },
       new SelectListItem { Value="SAVINGS0001", Text="Saving" }
   };

  // to do : Load other properties also
  return View(vm);
}

在你的 Razor 视图中,将此属性序列化并设置为 JavaScript 对象。

@model MakeTransactionModel
@using(Html.BeginForm())
{
  @Html.DropDownListFor(s=>s.FromAccountId,Model.FromAccounts,"Select")

  @Html.EditorFor(model => model.OrignalBalance, 
     new { @id="OrignalBalance", @class = "form-control",
     disabled = "disabled", @readonly = "readonly" } )
  <input type="submit" />
}
@section Scripts
{
<script>   
var balanceDict = @Html.Raw(Newtonsoft.Json.JsonConvert
                               .SerializeObject(Model.AccountBalances));

$(function () {

    $('#FromAccountId').change(function() {
        var accountId= $('#AccountFrom').val();
        var v = balanceDict[accountId];
        $("#OrignalBalance").val(v);
    });   

});
</script>
}

谢谢您的回复。有没有其他方法可以实现这个?因为我不想创建一个动作方法。 - Waqar Ahmed
我正在尝试这段代码,但是EditorFor中的文本没有更新。我调试了代码,它正在发送响应,但现在没有显示在编辑器中。你能帮我看看可能出了什么问题吗? - Waqar Ahmed
我在ajax调用中打错了一个字。已经修复了。同时也添加了非ajax解决方案。 - Shyju
实际上,只需将 .html 更改为 .val,就可以使 jQuery 工作。 - Waqar Ahmed

2

可能看起来不太明显,但这是相当广泛的。简单概括一下,你要么必须:

  • Serialize all accounts and balances into JSON and store them client-side:

    This is more code than is appropriate here, but you could use JSON.net to get JSON for new BankEntities().Accounts.ToList() (something you should be getting from your controller code, by the way, not in your view), then set a window variable to that in your JavaScript, and call upon that whenever the value changes.

    Untested, but something like:

    var balances = @Html.Raw(JsonConvert.SerializeObject(new BankEntities()
                                                    .Accounts
                                                    // Filter by logged in user
                                                    .ToDictionary(c => c.account_number, c.balance));
    
    $(document).ready(function () {
        $(function () {
            $('#AccountFrom').change(function () {
                var selectedValue = $('#AccountFrom').text();
                $('#OrignalBalance').val(balances[selectedValue]);
            });
        });
    }
    
  • Introduce an API call performed through AJAX to get balances whenever the value changes.

    Shyju beat me to this one, but it's probably a better way to do it, as long as you're comfortable introducing an API element. It's kind of advanced for first learning MVC, but it's not too complicated.

    This is what I'd do in a production application (although I'd do it with Web API), but for just playing, the first option is a little quicker, and probably easier to understand and debug fully if you're just getting started.

这里的混淆来自于代码执行的位置。你的 script 无法引用 BankEntities,因为它是在客户端运行,而不是服务器端。

感谢您的回复。您认为在客户端存储信息是否好? - Waqar Ahmed
我可以在 SelectList 中使用序列化对象吗? - Waqar Ahmed
@WaqarAhmed 任何一种方法都可以,它们只是不同而已。SelectList 是在服务器端构建的,因此您无法访问客户端变量。虽然您可以将相同的列表传递给要序列化的列表,就像创建 SelectList 一样。如果不了解您的代码更多信息,那么这可能是我会做的。 - Matthew Haugen
@WaqarAhmed 我认为你可能需要做一些事情来取消转义字典JSON。我认为在@Html下面有一些东西,但是自从我上次使用MVC以来已经过了一段时间。 - Matthew Haugen
@WaqarAhmed 找到了;我编辑了我的代码,但你需要将那个 JSON 传递给 Html.Raw,以避免它被转义。 - Matthew Haugen

1
JQuery对于LINQ一无所知,因为它是基于客户端的。因此,我建议在账户表单变更时进行ajax请求。
例如,在视图中进行ajax调用。
<script type="text/javascript">

    $(document).ready(function() {

        $('#AccountFrom').change(function() {
            var selectedAccountNumber = $('#AccountFrom option:selected').text();
            $.ajax({
                url: "/Accounts/GetAccountBalance",
                type: "POST",
                dataType: "json",
                data: { accountNumber: selectedAccountNumber },
                success: function (
                    $('#OrignalBalance').val(data.Balance);
                }
            });
        });
    });
</script>

假设您有一个名为Accounts的控制器,其中包含以下内容:

public ActionResult GetAccountBalance(string accountNumber)
{
    var account = db.Accounts.SingleOrDefault(a => a.account_number == accountNumber);
    // add validation logic for account not exits

    return Json(new { AccountNumber = accountNumber, Balance = account.balance });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接