【问题标题】:ajax POST not passing back correct dataajax POST 没有传回正确的数据
【发布时间】:2016-03-26 09:47:45
【问题描述】:

我试图将一个 json 对象传回我的设备控制器中的操作,然后将其插入到数据库中,但是当我单击表单上的提交按钮时,它似乎触发了两次。另一个问题是我在 json 对象中的位置字段和 pfID 没有被发送回控制器,其他字段被正确发送回。这是我的代码:

$('#getDevice').unbind('click').bind('click', function (e) {
    e.stopPropagation();
    //anti forgery token
    //get the form
    var form = $('#addDeviceForm');
    //from the form get the antiforgerytoken
    var token = $('input[name="__RequestVerificationToken"]', form).val();

    var URL = 'Devices/PushIPForCollection';

    //Before this we need to build the model from the input the user has given us
    var device = {
        deviceID: ' ',
        ipAddress: $('#dIPAddress').val(),
        deviceName: $('#dDeviceName').val(),
        CreatedDate: ' ',
        UpdatedDate: ' ',
        CreatedBy: ' ',
        UpdatedBy: ' ',
        deviceSubGroupID: $('#dSubgroup option:selected').val(),
        subgroup: " ",
        companyID: ' ',
        hidden: ' ',
        pfID: $('#dpfID option:selected').val(),
        pf: ' ',
        location: JSON.stringify({
            'region': $('#dRegion').val() == null ? ' ' : $('#dRegion').val(),
            'country': $('#dCountry').val() == null ? ' ' : $('#dCountry').val(),
            'city': $('#dCity').val() == null ? ' ' : $('#dCity').val(),
            'building': $('#dBuilding').val() == null ? ' ' : $('#dBuilding').val(),
            'room': $('#dRoom').val() == null ? ' ' : $('#dRoom').val(),
            'rack': $('#dRack').val() == null ? ' ' : $('#dRack').val()
        })
    };

    alert(device.pfID);
    alert(device.location);

    $.ajax({
        url: URL,
        data: {
            __RequestVerificationToken: token,
            device: device
        },
        type: 'POST',
        success: function (result) {
        },
        error: function (jqXHR, textStatus, errorThrown) {
            alert("An error has occurred please contact us");
        }
    })
    $('#add-device').modal('hide');
    return false;
});

当我提醒我的 pfID 时,它会返回一个字符串 "ba4475ef-0eed-441a-a77e-d733c288bf8e"

这是我的模型:

public class Devices
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int deviceID { get; set; }

    [Display(Name="IP Address:"), StringLength(50)]
    public string ipAddress { get; set; }

    [Display(Name = "DeviceName:"), StringLength(50)]
    public string deviceName { get; set; }

    public DateTime? CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
    public string CreatedBy { get; set; }
    public string UpdatedBy { get; set; }

    [Display(Name="Add to subgroup:")]
    public long? deviceSubGroupID { get; set; }

    [ForeignKey("deviceSubGroupID")]
    public DeviceSubGroup subgroup { get; set; }
    public string companyID { get; set; }
    public string hidden { get; set; }
    public string pfID { get; set; }
    [ForeignKey("pfID")]
    public PfHealth.Pf pf { get; set; }
    public string location { get; set; }
}

这是我的发布方法:

 public ActionResult PushIPForCollection(Devices device)
    {
        //Before committing to the database we need to check if the device already exists
        var checkIfDeviceExists = db.devices.Any(check => check.ipAddress == device.ipAddress);

        if (!checkIfDeviceExists)
        {
            if (ModelState.IsValid)
            {
                var userID = User.Identity.GetUserId();


                device.CreatedDate = DateTime.Now;
                device.UpdatedDate = DateTime.Now;
                device.CreatedBy = userID;
                device.UpdatedBy = userID;

                var subgroup = db.deviceSubGroups.Where(sub => sub.deviceSubID == device.deviceSubGroupID).FirstOrDefault();
                device.communityString = subgroup.snmpCommunityString;
                device.companyID = subgroup.companyID;

                db.devices.Add(device);
                db.SaveChanges();
            }

        }
        //Can change this to get json in order to let to view know what message to display to the user.
        return RedirectToAction("index");
    }

这是我在视图中的表单:

<div class="modal fade" id="add-device" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="add-device-Label"><strong>ADD DEVICE</strong></h4><!--add depending on which panel you have clicked-->
        </div>
        <div class="modal-body" id="add-device-body">
            <!--Depending on which panel insert content-->
            @using (Html.BeginForm("PushIPForCollection", "Devices", FormMethod.Post, new { id = "addDeviceForm" }))
            {
                @Html.AntiForgeryToken()

                <hr />
                <div class="form-horizontal">
                    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.LabelFor(m => m.device.ipAddress, new { @class = "col-md-2 control-label"})
                        </div>
                        <div class="col-md-9">
                            @Html.TextBoxFor(m => m.device.ipAddress, new { @class = "form-control", @id = "dIPAddress" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.LabelFor(m => m.device.deviceName, new { @class = "col-md-2 control-label" })
                        </div>
                        <div class="col-md-9">
                            @Html.TextBoxFor(m => m.device.deviceName, new { @class = "form-control", @id = "dDeviceName" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.LabelFor(m => m.device.deviceSubGroupID, new { @class = "col-md-2 control-label" })
                        </div>
                        <div class="col-md-9">
                            @Html.DropDownListFor(m => m.device.deviceSubGroupID, (IEnumerable<SelectListItem>)ViewBag.subGroups, "None", new { @id = "dSubgroup" })
                            @Html.ValidationMessageFor(m => m.device.deviceSubGroupID, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("Region:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("Region", "", new { @class = "form-control", @id = "dRegion" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("Country:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("Country", "", new { @class = "form-control", @id = "dCountry" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("City:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("City", "", new { @class = "form-control", @id = "dCity" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("Building:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("Building", "", new { @class = "form-control", @id = "dBuilding" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("Room:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("Room", "", new { @class = "form-control", @id = "dRoom" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.Label("Rack:")
                        </div>
                        <div class="col-md-9">
                            @Html.TextBox("Rack", "", new { @class = "form-control", @id = "dRack" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-3">
                            @Html.LabelFor(model=>model.device.pfID)
                        </div>
                        <div class="col-md-9">
                            @Html.DropDownListFor(m => m.device.pfID, (IEnumerable<SelectListItem>)ViewBag.pathfinders, "None", new { @id = "dpfID" })
                            @Html.ValidationMessageFor(m => m.device.pfID, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                            <button id="getDevice" type="submit" value="CreateGroups" data-loading-text="Loading..." class="btn btn-primary">Save changes</button>
                        </div>
                    </div>
                </div>

            }
        </div>
    </div>
</div>

【问题讨论】:

  • 只需使用data: $('#addDeviceForm').serialize(), 发回您的表单。如果您的视图是通过强绑定到您的模型而正确生成的,那么它将正确地绑定到您的模型。 pfID 返回"ba4475ef-0eed-441a-a77e-d733c288bf8e" 有什么问题?你期待它是什么?
  • \@StephenMuecke 抱歉,我可能没有正确解释,它应该返回,但是当我在操作中设置断点时,它会作为空字符串与位置一起返回。我这样做的原因是因为我想将 location 中的所有字段分组并将其作为 JSON 存储在数据库中
  • 您需要向您展示模型、视图和 POST 方法。我们不可能猜到你有什么错误(如果你正确生成了视图,你的所有脚本都可以被几行代码替换)
  • @StephenMuecke 我已更新我的帖子以包含您需要的所需信息。
  • 不确定您从哪里得到创建这样一个视图的想法。首先pfID 应该是Guid,因为那是您回帖的内容。 location 是 typeof string so why are you trying to construct a complex object? location` 应该是一个复杂的对象,包含属性 string Regionstring Country 等。然后将所有帮助程序更改为使用 xxxFor() 方法,以便您强绑定到您的模型。您应该删除助手中的所有 new { id = xx 代码 - 它们不是必需的。

标签: javascript jquery json asp.net-mvc-5 controller-action


【解决方案1】:

您不需要手动创建javascript对象,您可以使用jQueryserialize方法将整个表单序列化并通过ajax发送,只要表单字段名称与参数名称/模型属性名称匹配HttpPost 动作方法。

您可以创建特定于视图的视图模型。

public class CreateDeviceVm
{
   public string DeviceId {set;get;}
   public string IPAddress {set;get;}
   public int DeviceSubGroupId {set;get;}
   public List<SelectListItem> DeviceSubGroups {set;get;}
   public string City {set;get;}
   public string Room {set;get;}
   //Add properties NEEDED FOR THE VIEW. 
}

在您的 GET 操作中,创建此视图模型的对象,分配 DeviceSubGroups 属性并发送到视图。

public ActionResult Create()
{
  var vm = new CreateDeviceVm();
  vm.DeviceSubGroups = db.DeviceSubGroups
                  .Select(s=> new SelectLisItem { Value=s.Id.ToString(),
                                                  Text = s.Name }).ToList();

  return View(vm);
}

在你的视图中,它是视图模型的强类型, @model CreateDeviceVm

@using(Html.BeginForm())
{
  <label>DeviceId</label>
  @Html.TextBoxFor(s=>s.DeviceId)
  <label>IP Address</label>
  @Html.TextBoxFor(s=>s.IPAddress)
  <label>Sub group</label>
  @Html.DropDownListFor(s=>s.DeviceSubGroups,Model.DeviceSubGroups,"Select")
  <label>City</label>
  @Html.TextBoxFor(s=>s.City)
  <label>Room</label>
  @Html.TextBoxFor(s=>s.Room)
  <input type="submit" id="btnSave" />
}

现在您可以添加一些 javascript 来监听提交按钮上的点击事件,获取对表单的引用,将其序列化并使用 jQuery ajax 发送到服务器。

$(function(){    
  $("#btnSave").click(function(e){    
    e.preventDefault();

    var _f=$(this).closest("form");
    $.post(_f.attr("action")._f.serialize(),function(res){
        //check res and do something
    });    
  });    
});

在您的 HttpPost 操作方法中,

[HttpPost]
public ActionResult Create(CreateDeviceVm model)
{
   var exists= db.devices.Any(x=> x.ipAddress == model.ipAddress);
   if (!exists)
   {
      var d= new Device();
      d.IpAddress=model.IPAddress;
      d.DeviceSubGroupId=model.DeviceSubGrouId;
      //Map other properties as well.

      db.Devices.Add(d);
      db.SaveChanges();
      return Json( new { status="success"});
   }
   return Json( new { status="failed"});
}

【讨论】:

  • OP 正在使用诸如@Html.TextBoxFor(m =&gt; m.device.ipAddress) 之类的代码,建议视图中的主模型包含设备属性,因此需要调整主模型以包含CreateDeviceVm 的属性,但随后post 方法需要一个[Bind(Prefix="...")] 属性。建议更好的方法是使用[ChildActionOnly] 方法,该方法基于CreateDeviceVm 返回表单的一部分,并在主视图中使用@Html.Action() 来避免BindAttribute
  • 我的回答是建议使用特定于视图的平面视图模型。我没有遵循您的评论的含义。
  • 这是给 OP 的。我猜主视图用于显示设备列表,表单用于添加新设备。在这种情况下,主视图可以是 List&lt;device&gt; 并包含 @Html.Action() 以呈现表单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多