I am trying to append an item to the SQL table but when I press the save button nothing happens. The reset button works but not the Save. Nothing is showing in the database either. Basically, I don't understand why the buttons act as if there was no code attached to it. No Error message or crash shows up either.
View
#model BudgetAmazon.ViewModel.ItemViewModel
#{
ViewBag.Title = "Item";
}
<h2>Index</h2>
<script type="text/javascript">
$(document).ready(function () {
$("#btnSave").click(function () {
SaveItem();
});
$("#btnReset").click(function () {
ResetItem();
});
});
function ResetItem() {
$("#CategoryId").val("1");
$("#ItemCode").val("");
$("#ItemName").val("");
$("#Description").val("");
$("#ItemPrice").val("0");
$("#ImagePath").val("");
}
function SaveItem() {
var formData = new FormData();
formData.append("CategoryId", $("#CategoryId").val());
formData.append("ItemCode", $("#ItemCode").val());
formData.append("ItemName", $("#ItemName").val());
formData.append("Description", $("#Description").val());
formData.append("ItemPrice", $("#ItemPrice").val());
formData.append("ImagePath", $("#ImagePath").get(0).files[0]);
$.ajax({
async: true,
type: 'POST',
contentType: false,
processDate: false,
data: formDate,
url: '/Item/Index',
success: function (data) {
if (data.success) {
alert(data.Message);
ResetItem();
}
},
error: function (data) {
alert('There is a problem adding items.');
}
});
}
</script>
<div class="container">
<div class="col-md-4">
<div class="form-group">
Category :
#Html.DropDownListFor(model => model.CategoryId, new SelectList(Model.CategorySelectListItem, "Value", "Text"),
new { #class = "form-control"})
</div>
</div>
<div class="col-md-4">
<div class="form-group">
Item Code :
#Html.TextBoxFor(model => model.ItemCode, new { #class = "form-control", autocomplete = "Off"})
</div>
</div>
<div class="col-md-4">
<div class="form-group">
Item Name :
#Html.TextBoxFor(model => model.ItemName, new { #class = "form-control", autocomplete = "Off" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
Description :
#Html.TextBoxFor(model => model.Description, new { #class = "form-control", autocomplete = "Off" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
Item Price :
#Html.TextBoxFor(model => model.ItemPrice, new { #class = "form-control", autocomplete = "Off" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
Image Path :
#Html.TextBoxFor(model => model.ImagePath, new { type = "file", #class = "form-control"})
</div>
</div>
<div>
<input type="button" value="Save" name="save" class="btn btn-primary" id="btnSave"/>
<input type="button" value="Reset" name="reset" class="btn btn-danger" id="btnReset"/>
</div>
</div>
Controller
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BudgetAmazon.Models;
using BudgetAmazon.ViewModel;
namespace BudgetAmazon.Controllers
{
public class ItemController : Controller
{
private BudgetAmazonEntities3 objBudgetAmazonEntities;
public ItemController()
{
objBudgetAmazonEntities = new BudgetAmazonEntities3();
}
// GET: Item
public ActionResult Index()
{
ItemViewModel objItemViewModel = new ItemViewModel();
objItemViewModel.CategorySelectListItem = (from objCat in objBudgetAmazonEntities.Categories select new SelectListItem()
{
Text = objCat.CategoryName,
Value = objCat.CategoryId.ToString(),
Selected = true
});
return View(objItemViewModel);
}
[HttpPost]
public JsonResult Index(ItemViewModel objItemViewModel)
{
string NewImage = Guid.NewGuid() + Path.GetExtension(objItemViewModel.ImagePath.FileName);
objItemViewModel.ImagePath.SaveAs(Server.MapPath("~/Images/" + NewImage));
Item objItem = new Item();
objItem.ImagePath = "~/Images/" + NewImage;
objItem.CategoryId = objItemViewModel.CategoryId;
objItem.Description = objItemViewModel.Description;
objItem.ItemCode = objItemViewModel.ItemCode;
objItem.ItemId = Guid.NewGuid();
objItem.ItemName = objItemViewModel.ItemName;
objItem.ItemPrice = objItemViewModel.ItemPrice;
objBudgetAmazonEntities.Items.Add(objItem);
objBudgetAmazonEntities.SaveChanges();
return Json(new {Success = true, Message = "Item is added Successfully."}, JsonRequestBehavior.AllowGet);
}
}
}
ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BudgetAmazon.ViewModel
{
public class ItemViewModel
{
public Guid ItemId { get; set; }
public int CategoryId { get; set; }
public string ItemCode { get; set; }
public string ItemName { get; set; }
public string Description { get; set; }
public decimal ItemPrice { get; set; }
public HttpPostedFileBase ImagePath { get; set; }
public IEnumerable<SelectListItem> CategorySelectListItem { get; set; }
}
}
I think the problem is you have made a typo mistake while giving the forma data. Try changing "formDate" to "formData". I have attached the picture to show where to.
enter image description here
As far as I know, your url may require something like .html file extension. Try to revise like url: "/Item/index.html, and see if the request success or not.
Related
I'm having a basic form with few text fields and a file upload controller on a bootstrap modal dialog (Bootstrap 4). below is my code:
Model:
public class DemoContent
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[RegularExpression("([0-9]+)",ErrorMessage = "Age must be numbers only")]
public int Age { get; set; }
[EmailAddress]
public string Email { get; set; }
[DataType(DataType.Upload)]
[Display(Name = "Image")]
public HttpPostedFileBase ImageUrl { get; set; }
}
JavaScript
$(function() {
$("a[data-modal=demoPopup]").on("click", function () {
$("#demoModalContent").load(this.href, function () {
$("#demoModal").modal({ keyboard: true }, "show");
$("#demoForm").submit(function () {
if ($("#demoForm").valid()) {
var files = $("ImageUrl").get(0).files;
var data = $(this).serialize();
data.append("ImageUrl", files[0]);
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$("#demoModal").modal("hide");
location.reload();
} else {
$("#MessageToClient").text(result.message);
}
},
error: function () {
$("#MessageToClient").text("The web server had an error.");
}
});
return false;
}
});
});
return false;
});
Controller:
[HttpPost]
public ActionResult Create(DemoContent model)
{
if (model.Age > 55)
{
var file = model.ImageUrl;
return Json(new { success = true });
}
else
{
return Json(new { success = false,message="Invalid Data" });
}
}
Now when i open the popup it works also when i submit the form it goes to the controller along with the file. but the problem is once the server returns the success message the popup shows that message in a blank page instead of capturing it and refreshing the current page or showing the messages. any idea why is this happening.
link to source files : https://drive.google.com/open?id=1W3H3kFEpHJWfaf7_UnJI3O5I900GxyC7
May be you wrote your javascripts function in document.ready() function,That is why it again refreshing.
Write your JavaScript code as follows:
$(function() {
$("a[data-modal=demoPopup]").on("click", function () {
$("#demoModalContent").load(this.href, function () {
$("#demoModal").modal({ keyboard: true }, "show");
$("#demoForm").submit(function (event) { // Pass the event as parameter to the function.
event.preventDefault(); // I have added these two lines
event.stopImmediatePropagation();
if ($("#demoForm").valid()) {
var files = $("ImageUrl").get(0).files;
var data = $(this).serialize();
data.append("ImageUrl", files[0]);
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$("#demoModal").modal("hide");
location.reload();
} else {
$("#MessageToClient").text(result.message);
}
},
error: function () {
$("#MessageToClient").text("The web server had an error.");
}
});
return false;
}
});
});
return false;
});
I think you should install and use Microsoft.Unobtrusive.Validation and *.Ajax, if you want your modal to be updated (I get your question like that...). With this, you can use code like the following example, which can update your modal (used this in a project a few days ago):
Modal:
#using (Ajax.BeginForm("Login", new { Controller = "Home", area = "" }, new AjaxOptions() { OnSuccess = "onSuccessLogin", HttpMethod = "POST", UpdateTargetId = "loginmodalbody"}, new { id = "loginForm" }))
{
<div class="modal-body" id="loginmodalbody">
<div class="text-danger loginfailed"></div>
<div class="container">
<div class="card border-primary mb-3" style="margin: 0 auto;">
<div class="card-body">
#Html.Partial("~/Views/Shared/Modals/LoginModalBody.cshtml")
</div>
</div>
<div class="container">
<span><a onclick="alert('Leads to pw info')" href="#">Forgot password?</a></span>
</div>
<br />
<button class="btn btn-primary btn-block buttonlogin">Login</button>
</div>
<br />
</div>
}
Modal Body:
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-lg-12 col-12">
#Html.EditorFor(model => model.EMail, new { htmlAttributes = new { #class = "form-control", placeholder = "EMail", #id = "inputemail" } })
#Html.ValidationMessageFor(model => model.EMail, "", new { #class = "text-danger", #id = "dangeremail" })
</div>
</div>
<div class="form-group">
<div class="col-lg-12 col-12">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control", placeholder = "Passwort", #id = "inputpassword" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger", #id = "dangerpassword" })
</div>
</div>
</div>
Thus, it updates your modal body after getting data from the posting of the form - you define the id to be updated within the AjaxOptions, as shown in the above snippet.
When clicking a button I am calling a web api with ajax. My form is using JqueryVal, to make form validations, according to my viewmodel data annotations.
My problem is that when I click the button "Listo" in my form, it calls my API, inspite of jqueryval is marking an error( selecting a file is required)
This is my code:
My viewmodel that contains data annotations(the dataannotations are used along with the jquery.validate.js and jquery.validate.unobtrusive.js. As you can see, it is working, but is not preventing the API from being called):
public class CursoViewModel
{
public Guid Id { get; set; }
[MaxLength(125)]
public string Titulo { get; set; }
[Required]
public string Descripcion { get; set; }
[Required(ErrorMessage ="selecciona una imagen para tu curso")]
[DataType(DataType.Upload)]
public HttpPostedFileBase Imagen { get; set; }
}
The class posted to my api
public class person
{
public string name { get; set; }
public string surname { get; set; }
}
The Api code
[HttpPut]
[Route("api/ProfesorCurso/test")]
public string Put(person p)
{
return p.name + p.surname;
}
My View
#model project.ViewModels.CourseViewModel
<form id="Editcurso" method="post" action="#">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Please fix the following errors.")
<div class="container">
<div class="form-group">
#Html.LabelFor(c=>c.Titulo)
#Html.TextBoxFor(c => c.Titulo, new {id="titulo", #class="form-control"})
#Html.ValidationMessageFor(m => m.Titulo)
</div>
<div class="form-group">
#Html.LabelFor(c => c.Descripcion)
#Html.TextAreaFor(c => c.Descripcion, new {id="descripcion", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Descripcion)
</div>
<div class="thumbnail" id="imagencurso"></div>
<div class="form-group">
#Html.LabelFor(m => m.Imagen)
#Html.TextBoxFor(m => m.Imagen, new {id="imagen" ,type = "file", data_rule_validCustomer = "true" })
#Html.ValidationMessageFor(m => m.Imagen)
</div>
<button id="submiter" type="submit" class="btn btn-primary">Listo!</button>
</div>
</form>
The scripts in the view
#section scripts
{
#Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$("#submiter").click(function () {
jQuery.support.cors = true;
var person = new Object();
person.name = "Sourav";
person.surname = "Kayal";
$.ajax({
url: '/api/ProfesorCurso/test',
type: 'PUT',
dataType: 'json',
data: person,
success: function (data) {
console.log(data);
return false;
},
error: function (x, y, z) {
alert('error al postear');
return false;
}
});
});
});
</script>
}
What can I do to prevent ajax to call my api when clicking my form button, if there are Jquery validation errors?
thanks
You should be handling the .submit() event of the form, and then your can check .valid(), and if not cancel the ajax call. Note you should also be cancelling the default submit.
$('#Editcurso').submit(e) {
e.preventDefault(); // prevent the default submit
if (!$(this).valid()) {
return; // exit the function and display the errors
}
....
$.ajax({
....
});
}
As a side note, there is no point adding new { id="titulo" } etc - the HtmlHelper methods that generate form controls already add an id attribute based on the property name
I tried to minimize huge problem to a small one so I created the new sample web project; mvc-empty in VS. I created one view named „Index” in Home controller. Index view code:
#model WebApplication16.ViewModels.Home.IndexVM
#{
ViewBag.Title = "Index";
}
#Html.Partial("~/Views/Home/_Orders.cshtml", Model.Orders)
#section scripts{
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script>
$("#Type").change(function () {
$('#order-current > img').remove();
var currentOrder = "#Type_" + $("#Type").find('option:selected').text();
var $img = $(currentOrder).clone();
$img.removeClass("hidden");
$("#order-current").append($img);
$("#ajax-form").submit();
});
</script>
}
Home controller code:
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
IndexVM dataVM = new IndexVM();
GetControlsDataSource(dataVM.Orders);
return View(dataVM);
}
private static void GetControlsDataSource(OrdersVM dataVM)
{
List<SelectListItem> typeControlDataSource = new List<SelectListItem>();
foreach (var en in Enum.GetValues(typeof(TypeEnum)))
{
SelectListItem item = new SelectListItem();
item.Text = en.ToString();
item.Value = ((int)en).ToString();
typeControlDataSource.Add(item);
}
dataVM.TypeControlDataSource = typeControlDataSource;
}
[HttpPost]
public ActionResult Pay(IndexVM dataVM)
{
GetControlsDataSource(dataVM.Orders);
if (ModelState.IsValid)
{
dataVM.Orders.Info = "Info bla bla bla";
return PartialView("~/Views/Home/_Orders.cshtml", dataVM.Orders);
}
else
{
return View(dataVM);
}
}
}
There is also a partial view named “_Orders”, which is rendered on the Index view.The code of _Orders partial view:
#model WebApplication16.ViewModels.Home.OrdersVM
#using (Ajax.BeginForm("Pay", "Home", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "result",
}, new { id = "ajax-form" }))
{
<div id="result">
<div id="order-current">
</div>
<div>
#Html.TextBoxFor(x => x.Name, new { #class = "form-control", style = "margin-top:10px;", id = "Name" })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div>
#Html.DropDownListFor(x => x.Type, Model.TypeControlDataSource, new { #class = "form-control", style = "margin-top:10px;", id = "Type", })
#Html.ValidationMessageFor(x => x.Type)
</div>
<div>
<p>#Model.Info</p>
</div>
<button type="submit" class="btn btn-primary" name="ok"> OK</button>
</div>
}
<div id="orders-container">
<img id="Type_I" src="~/App_Images/Type_I.png" class="img-responsive hidden" />
<img id="Type_II" src="~/App_Images/Type_II.png" class="img-responsive hidden" />
<img id="Type_III" src="~/App_Images/Type_III.png" class="img-responsive hidden"/>
</div>
Index model is described by class IndexVM:
public class IndexVM
{
public IndexVM()
{
this.Orders = new OrdersVM();
}
public OrdersVM Orders { get; set; }
}
_Orders model is described by class OrdersVM:
public class OrdersVM
{
[Required]
public string Name { get; set; }
public string Info { get; set; }
[Required]
public TypeEnum Type { get; set; }
public List<SelectListItem> TypeControlDataSource { get; set; }
}
public enum TypeEnum
{
I,
II,
III
}
After change of value in DropDownListFor control with id=”Type”, the picture from hidden field should be injected by jquery code located in Index view into container with id=”order-current” and after that operation the ajax-form should be submitted. It works properly but after calling
return PartialView("~/Views/Home/_Orders.cshtml", dataVM.Orders);
from the HomeController, the field Info is updated properly but the injected picture from the “order-current” div container is gone. I tried to see what’s wrong in Google Chrome using F12 button and there are no errors but appeared an infinite loop in “browserLink” script. I can’t explain why.
All I want is to see the injected picture in container with id=”order-current after submitting the ajax-form. How to do this and what I did wrong?
Thanks to my friend I finally solved the problem. After updating the “result” container, all events added by jQuery to controls located in this container are unpinned. That’s why it crashes.
The way to make it work correctly is to create a function and pin it to the event OnComplete of AjaxBeginForm. After each update of the result container via ajax, this function is called. I also made a small mistake in Home controller because I inserted a wrong view model class. After all changes, it looks like this;
Home controller code:
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
IndexVM dataVM = new IndexVM();
GetControlsDataSource(dataVM.Orders);
return View(dataVM);
}
private static void GetControlsDataSource(OrdersVM dataVM)
{
List<SelectListItem> typeControlDataSource = new List<SelectListItem>();
foreach (var en in Enum.GetValues(typeof(TypeEnum)))
{
SelectListItem item = new SelectListItem();
item.Text = en.ToString();
item.Value = ((int)en).ToString();
typeControlDataSource.Add(item);
}
dataVM.TypeControlDataSource = typeControlDataSource;
}
[HttpPost]
public ActionResult Pay(OrdersVM dataVM)
{
GetControlsDataSource(dataVM);
if (ModelState.IsValid)
{
dataVM.Info = "Info bla bla bla";
return PartialView("~/Views/Home/_Orders.cshtml", dataVM);
}
else
{
return View(dataVM);
}
}
}
Index view:
#model WebApplication16.ViewModels.Home.IndexVM
#{
ViewBag.Title = "Index";
}
#Html.Partial("~/Views/Home/_Orders.cshtml", Model.Orders)
<div id="orders-container">
<img id="Type_I" src="~/App_Images/Type_I.png" class="img-responsive hidden" />
<img id="Type_II" src="~/App_Images/Type_II.png" class="img-responsive hidden" />
<img id="Type_III" src="~/App_Images/Type_III.png" class="img-responsive hidden" />
</div>
#section scripts{
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script>
function imageOnChangeEvent() {
$("#ajax-form").submit();
}
function OnCompleteAjaxForm() {
$('#order-current > img').remove();
var currentOrder = "#Type_" + $("#Type").find('option:selected').text();
var $img = $(currentOrder).clone();
$img.removeClass("hidden");
$("#order-current").append($img);
}
</script>
}
_Orders partial view code:
#model WebApplication16.ViewModels.Home.OrdersVM
<div id="result">
#using (Ajax.BeginForm("Pay", "Home", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "result",
OnComplete = "OnCompleteAjaxForm()"
}, new { id = "ajax-form" }))
{
<div id="order-current">
</div>
<div>
#Html.TextBoxFor(x => x.Name, new { #class = "form-control", style = "margin-top:10px;", id = "Name" })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div>
#Html.DropDownListFor(x => x.Type, Model.TypeControlDataSource, new { #class = "form-control", style = "margin-top:10px;", id = "Type", onchange = "imageOnChangeEvent()" })
#Html.ValidationMessageFor(x => x.Type)
</div>
<div>
<p>#Model.Info</p>
</div>
<button type="submit" class="btn btn-primary" id="button_ok" name="ok"> OK</button>
}
</div>
I am a newbie at ASP.net MVC5, my problem is this:
I am creating a partial view "AgregaGuia", in which I make a query to TblGuias model of a row that do not yet have "fechaRecepcionGuia", these guides are filled in a combobox and when selected this the guide fills all textbox in that view. However when running the application it generated the following error: DataBinding : 'System.String' does not Contain a property with the name 'numeroGuia'.
Could anyone help me please??
this is my model:
public partial class TblGuias
{
public TblGuias()
{
this.TblFactIC = new HashSet<TblFactIC>();
}
public string numeroGuia { get; set; }
public string companiaEnvios { get; set; }
public string destino { get; set; }
public decimal pesoGuia { get; set; }
public System.DateTime fechaEnvioGuia { get; set; }
public Nullable<System.DateTime> fechaRecepcionGuia { get; set; }
public string comprobante { get; set; }
public virtual ICollection<TblFactIC> TblFactIC { get; set; }
}
this is my controller:
public class vueInveEntrsController : Controller
{
public ActionResult AgregaGuia()
{
ViewData["guia"] = new SelectList(db.TblGuias.Where(g => g.fechaRecepcionGuia == null).Select((g => g.numeroGuia)),"numeroGuia", "companiaEnvios","destino","pesoGuia","fechaEnvioGuia");
return PartialView(db.TblGuias.ToList());
}
[HttpPost]
public ActionResult Action(string numero)
{
var query = from c in db.TblGuias
where c.numeroGuia == numero
select c;
return Json(query);
}
}
and my view is as follows:
#using (#Html.BeginForm("Action", "vueInveEntrs", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.Label("Seleccione Guia", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("numero", (SelectList)ViewData["guia"], new { onchange = "Action(this.value);", #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Compañia Envios", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("transporte", null, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Destino", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("destino", null, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Peso", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("peso", null, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Fecha Envio", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("fechaenvio", null, new { #class = "form-control" })
</div>
</div>
}
<script type="text/javascript">
function Action(numero) {
$.ajax({
url: '#Url.Action("Action", "vueInveEntrs")',
type: "POST",
data: { "numero": numero },
"success": function (data) {
if (data != null) {
var vdata = data;
$("#transporte").val(vdata[0].companiaEnvios);
$("#destino").val(vdata[0].destino);
$("#peso").val(vdata[0].pesoGuia);
$("#fechaenvio").val(vdata[0].fechaEnvioGuia);
}
}
});
}
</script>
The problem is this line in your controller:
ViewData["guia"] = new SelectList(
db.TblGuias.Where(g => g.fechaRecepcionGuia == null).Select((g => g.numeroGuia)),
"numeroGuia", "companiaEnvios","destino","pesoGuia","fechaEnvioGuia");
You are not specifying the constructor parameters for SelectList properly. There are several different overloads, but I think the one you want is this one:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
The first parameter, items, represents the list of items that you want be rendered into <option> tags inside the <select>.
The second parameter, dataValueField, is the name of the property on the items in the enumerable which will become the value attribute inside each <option> tag.
Similarly, the third parameter, dataTextField, is the name of the property which will become the text displayed for each <option>.
So, if you change your code to the following, I think it should work:
ViewData["guia"] = new SelectList(
db.TblGuias.Where(g => g.fechaRecepcionGuia == null), "numeroGuia", "numeroGuia");
If you want different text to display in the dropdown list, change the third parameter to a different property from your TblGuias class.
I want to create a field object in ASP.NET MVC and store it to a database. The field should contain its coordinates which the user can select with the google maps api.
And now, how can I pass the coordinates of the markers, which are stored in a javascript array, to the Model´s List?
This is my Controller for this:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using BL;
using MvcAgrarTest.Models;
namespace MvcAgrarTest.Controllers
{
public class FieldsController : Controller
{
private MvcAgrarContext db = new MvcAgrarContext();
// GET: Fields
public ActionResult Index()
{
var field = db.CreateFieldViewModel.Include(f => f.FieldType);
return View(field.ToList());
}
// GET: Fields/Create
public ActionResult Create()
{
var model = new CreateFieldViewModel();
ViewBag.FieldTypeId = new SelectList(db.FieldType, "FieldTypeId", "Name");
return View(model);
}
// POST: Fields/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateFieldViewModel model, CreateFieldViewModel field, string[] markers)
{
if (ModelState.IsValid)
{
PostCoordinates(markers);
db.CreateFieldViewModel.Add(field);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.FieldTypeId = new SelectList(db.FieldType, "FieldTypeId", "Name", field.FieldTypeId);
return Json(true);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Here my Create View with the Google Maps script:
#model MvcAgrarTest.Models.CreateFieldViewModel
#{
ViewBag.Title = "Create";
}
<h2>Feld anlegen</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #placeholder = "Feldname", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FieldTypeId, "Feldtyp", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("FieldTypeId", null, "--Feldart auswählen--", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.FieldTypeId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Size, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Size, new { htmlAttributes = new { #placeholder = "In Hektar", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Size, "", new { #class = "text-danger" })
</div>
</div>
<div id="google">
<script src="https://maps.googleapis.com/maps/api/js?sensor=false" type="text/javascript"></script>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.5.5/jquery.validate.min.js" type="text/javascript"></script>
<script type="text/javascript">
var map;
function initialize() {
var myLatLng = new google.maps.LatLng(50.617109, 8.065738);
var myOptions = {
zoom: 5,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// array to store markers that has been drawn
var markers = [];
// event listener draw a marker
google.maps.event.addListener(map, 'click', function (e) {
var marker = new google.maps.Marker();
marker.setPosition(e.latLng);
marker.setMap(map);
marker.setVisible(true);
markers.push(marker);
// draw polygon on marker click
// once user clicks on on of the markers
google.maps.event.addListener(marker, 'click', function (e) {
document.getElementById("label").innerHTML = "";
drawPoints(markers);
label.style.borderStyle = "dotted"
for (i = 0; i < markers.length; ++i) {
document.getElementById("label").innerHTML += markers[i].position;
}
// empty the markers array
markers = [];
});
});
}
function drawPoints(markers) {
var poly = new google.maps.Polygon;
var points = [];
for (var i = 0; i < markers.length; i++) {
points.push(markers[i].getPosition());
}
poly.setMap(map);
poly.setPath(points);
poly.setVisible(true);
}
</script>
<body onload="initialize()">
<div id="map_canvas" style="width: 500px; height: 300px"></div>
</body>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Erstellen" class="btn btn-default" />
</div>
</div>
</div>
}
and finally my ViewModel to create the field:
public class CreateFieldViewModel
{
[Key]
[Display(Name="ID")]
public int FieldId { get; set; }
[Required]
[Display(Name="Fieldname")]
public string Name { get; set; }
[Required]
[Display(Name="Fieldtype")]
public int FieldTypeId { get; set; }
[Required]
[Range(0.01, int.MaxValue, ErrorMessage = "The Size can´t be 0 or less")]
[Display(Name="Fieldsize")]
public float Size { get; set; }
[Display(Name="Coordinates")]
public List<string> Coordinates { get; set; }
public virtual FieldType FieldType { get; set; }
}
/edit: Id did it like this now, but it still doesn´t work
changed part from the google maps API:
var passdata = [];
google.maps.event.addListener(marker, "click", function(e){
for (y=0; y<markers.length; ++y){
passdata[y] = markers[y].position
}
drawpoints(markers);
$.ajax({
url: "#Url.Action("Create","Fields")",
typ: "POST",
datatype: "json",
data: JSON.stringify({coordinates: passdata}),
contentType: "application/json; charset=utf-8",
traditional: true,
success: function (data) {
alert(data);
},
});
And the Controller Function:
// GET: Fields/Create
public ActionResult Create()
{
var model = new CreateFieldViewModel();
ViewBag.FieldTypeId = new SelectList(db.FieldType, "FieldTypeId", "Name");
return View(model);
}
// POST: Fields/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateFieldViewModel field, string[] coordinates)
{
if (ModelState.IsValid)
{
field.Coordinates = coordinates;
db.CreateFieldViewModel.Add(field);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.FieldTypeId = new SelectList(db.FieldType, "FieldTypeId", "Name", field.FieldTypeId);
return View(field);
}
I understood, (looking by you code) that you want to go with submitting form, and not ajax?
If so, you have two choices (known to me):
Create html hidden input and paste there as value serialized JSON of your markers array - but you will have to deserialize this value later. In this example you need to change Coordinates type in your model to string.
JavaScript
// some sample coordinates, you need to extract them from markers
var coordinates = ["12,21","213,231"];
var dataToSend = JSON.stringify(coordinates);
$("#coordinatesInput").val(dataToSend);
HTML
<input hidden id="coordinatesInput" name="model.Coordinates" value=""/>
Create dynamically, using JavaScript (for example append function) many hidden html inputs with name model.Coordinates[i] and value of single coordinate (use some loop).
JavaScript
var coordinates = ["231,2132","312,231","231,321"];
var container = $("#container");
//container, where you will be adding inputs, in you example it could be form-horizontal class
coordinates.forEach(function(val, i){
container.append('<input hidden name="model.Coordinates['+i+']" value="'+val+'">');
});
Of course using AJAX is much better way, and AlexB answer is way to go, but mechanism of it is a little different. It is good to use only AJAX (not form submitting), because in your example you need to use two Actions, one for AJAX and one for form submitting.
You can pass your Javascript array to your controller using an Ajax call :
$.ajax({
url : "#Url.Action("MethodName", "ControllerName")",
contentType : "application/json; charset=utf-8",
dataType : "json",
type : "POST",
data : JSON.stringify({coordinates: markers})
})
(where markers is your JS array to pass to the controller, I guess)
And your controller will look like
public ActionResult MethodName(Single[] coordinates)
{
// ...
}