Asp.net mvc ASP.NET MVC 4嵌套视图模型Ajax
也许我的想法是错误的,因为我最近对WPF和MVVM进行了深入研究,但是我的Web项目中有以下ViewModelsAsp.net mvc ASP.NET MVC 4嵌套视图模型Ajax,asp.net-mvc,mvvm,asp.net-mvc-4,Asp.net Mvc,Mvvm,Asp.net Mvc 4,也许我的想法是错误的,因为我最近对WPF和MVVM进行了深入研究,但是我的Web项目中有以下ViewModels public class Route { public Address Source {get; set;} public Address Destination {get; set;} } public class Address { public string Text {get; set;} public Location Location {
public class Route
{
public Address Source {get; set;}
public Address Destination {get; set;}
}
public class Address
{
public string Text {get; set;}
public Location Location {get; set;}
}
puclic class Location
{
[Required]
public double? Latitude {get; set;}
[Required]
public double? Longitude {get; set;}
}
public class Search
{
public Route {get; set;}
public IEnumerable<Route> Results {get; set;}
}
如果不清楚我想做什么-我想让用户在源框和目标框中输入一些搜索文本,然后得到结果。当用户选择一个自动完成选项时,源和目标框应该通过Ajax自动完成,并填充Address.Location.Latitude和Address.Location.Longitude
最后,一旦用户拥有有效的源和目标位置,Home.cshtml上的Submit按钮应该通过Ajax调用,以获取搜索结果并将其绑定到网格
我想是相当标准的东西
我正在努力用“最干净”的方式来实现以下目标:
public class Route
{
public Address Source { get; set; }
public Address Destination { get; set; }
}
public class Address
{
[Required]
[ValidCity("Location", ErrorMessage = "Please select a valid city")]
public string Text { get; set; }
public Location Location { get; set; }
}
public class Location
{
public double? Latitude { get; set; }
public double? Longitude { get; set; }
}
public class Search
{
public Route RouteSearch { get; set; }
public IEnumerable<Route> Results { get; set; }
}
然后控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new Search
{
RouteSearch = new Route
{
Source = new Address(),
Destination = new Address()
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Route search)
{
if (!ModelState.IsValid)
{
return PartialView("_Route", search);
}
// TODO: do the search here and return the results:
var lat1 = Math.PI * search.Source.Location.Latitude.Value / 180;
var lon1 = Math.PI * search.Source.Location.Longitude.Value / 180;
var lat2 = Math.PI * search.Destination.Location.Latitude.Value / 180;
var lon2 = Math.PI * search.Destination.Location.Longitude.Value / 180;
var R = 6371;
var distance = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) +
Math.Cos(lat1) * Math.Cos(lat2) *
Math.Cos(lon2 - lon1)) * R;
return Json(new { distance = distance });
}
public ActionResult GetLocation(string text)
{
var results = new[]
{
new { city = "Paris", latitude = 48.8567, longitude = 2.3508 },
new { city = "London", latitude = 51.507222, longitude = -0.1275 },
new { city = "Madrid", latitude = 40.4, longitude = -3.683333 },
new { city = "Berlin", latitude = 52.500556, longitude = 13.398889 },
}.Where(x => x.city.IndexOf(text, StringComparison.OrdinalIgnoreCase) > -1);
return Json(results, JsonRequestBehavior.AllowGet);
}
}
相应的~/Views/Home/Index.cshtml
视图:
@model Search
@using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "searchComplete" }))
{
<div id="search">
@Html.Partial("_Route", Model.RouteSearch)
</div>
<p><button type="submit">OK</button></p>
}
地址类的编辑器模板(~/Views/Home/EditorTemplates/Address.cshtml
):
啊…我缺少的东西是:HiddenFor,用来捕获信息,以及BeginForm在顶层捕获child部分视图上的HiddenFor。非常感谢!关于验证文本的部分,而不是位置Lat/Long…很棒的东西。
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new Search
{
RouteSearch = new Route
{
Source = new Address(),
Destination = new Address()
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Route search)
{
if (!ModelState.IsValid)
{
return PartialView("_Route", search);
}
// TODO: do the search here and return the results:
var lat1 = Math.PI * search.Source.Location.Latitude.Value / 180;
var lon1 = Math.PI * search.Source.Location.Longitude.Value / 180;
var lat2 = Math.PI * search.Destination.Location.Latitude.Value / 180;
var lon2 = Math.PI * search.Destination.Location.Longitude.Value / 180;
var R = 6371;
var distance = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) +
Math.Cos(lat1) * Math.Cos(lat2) *
Math.Cos(lon2 - lon1)) * R;
return Json(new { distance = distance });
}
public ActionResult GetLocation(string text)
{
var results = new[]
{
new { city = "Paris", latitude = 48.8567, longitude = 2.3508 },
new { city = "London", latitude = 51.507222, longitude = -0.1275 },
new { city = "Madrid", latitude = 40.4, longitude = -3.683333 },
new { city = "Berlin", latitude = 52.500556, longitude = 13.398889 },
}.Where(x => x.city.IndexOf(text, StringComparison.OrdinalIgnoreCase) > -1);
return Json(results, JsonRequestBehavior.AllowGet);
}
}
@model Search
@using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "searchComplete" }))
{
<div id="search">
@Html.Partial("_Route", Model.RouteSearch)
</div>
<p><button type="submit">OK</button></p>
}
@model ToDD.Controllers.Route
<h3>Source</h3>
@Html.EditorFor(x => x.Source)
<h3>Destination</h3>
@Html.EditorFor(x => x.Destination)
@model Address
<span class="address">
@Html.TextBoxFor(x => x.Text, new { data_url = Url.Action("GetLocation") })
@Html.ValidationMessageFor(x => x.Text)
@Html.HiddenFor(x => x.Location.Latitude, new { @class = "lat" })
@Html.HiddenFor(x => x.Location.Longitude, new { @class = "lon" })
</span>
<script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.20.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
var searchComplete = function (result) {
if (result.distance) {
alert('the distance is ' + result.distance);
} else {
$('#search').html(result);
attachAutoComplete();
}
};
var attachAutoComplete = function () {
$('.address :text').autocomplete({
source: function (request, response) {
$.ajax({
url: $(this.element).data('url'),
type: 'GET',
cache: false,
data: { text: request.term },
context: response,
success: function (result) {
this($.map(result, function (item) {
return {
label: item.city,
value: item.city,
latitude: item.latitude,
longitude: item.longitude
};
}));
}
});
},
select: function (event, ui) {
var address = $(this).closest('.address');
address.find('.lat').val(ui.item.latitude);
address.find('.lon').val(ui.item.longitude);
},
minLength: 2
}).change(function () {
var address = $(this).closest('.address');
address.find('.lat').val('');
address.find('.lon').val('');
});
}
$(document).ready(attachAutoComplete);