Modal Bootstrap on ASP.NET MVC - c#

I trying to do a responsive async page with Modal bootstrap, it´s things all right, although when a save object on modal form, is did a update, but the return is to a json page:
The Controller Method returns a Json
using CaelumEstoque.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace CaelumEstoque.Controllers
{
public class ProdController : Controller
{
public static List<Prod> _listaProdutos = new List<Prod>()
{
new Prod { Codigo=01, Descricao="Produto 1", Preco=10 },
new Prod { Codigo=02, Descricao="Produto 2", Preco=15 },
new Prod { Codigo=03, Descricao="Produto 3", Preco=20 }
};
public ActionResult Index()
{
IList<Prod> lista = _listaProdutos;
return View(lista);
}
public ActionResult Details(int id)
{
var existe = _listaProdutos.Find(x => x.Codigo == id);
ViewBag.Detalhes = existe;
return View("parcial", existe);
}
public ActionResult Edit(int id)
{
var existe = _listaProdutos.Find(x => x.Codigo == id);
return View(existe);
}
public ActionResult ParcialEdit(Prod p)
{
var registro = _listaProdutos.Find(x => x.Codigo == p.Codigo);
registro.Descricao = p.Descricao;
registro.Preco = p.Preco;
return Json(registro);
}
public ActionResult parcial()
{
return View();
}
}
}
My Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CaelumEstoque.Models
{
public class Prod
{
public int Codigo { get; set; }
public string Descricao { get; set; }
public double Preco { get; set; }
}
}
Index View:
#model IEnumerable<CaelumEstoque.Models.Prod>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Codigo)
</th>
<th>
#Html.DisplayNameFor(model => model.Descricao)
</th>
<th>
#Html.DisplayNameFor(model => model.Preco)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr id="prod#(item.Codigo)">
<td>
#Html.DisplayFor(modelItem => item.Codigo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Descricao)
</td>
<td>
#Html.DisplayFor(modelItem => item.Preco)
</td>
<td>
Detalhe
<i class="glyphicon glyphicon-edit"></i>
#*<button class="btn btn-default details" data-id="#item.Codigo"><i class="glyphicon glyphicon-file"></i></button>
<button class="btn btn-danger delete" data-id="#item.Codigo"><i class="glyphicon glyphicon-trash"></i></button>
<button class="btn btn-primary edit" data-id="#item.Codigo"><i class="glyphicon glyphicon-edit"></i></button>*#
</td>
</tr>
}
</table>
<div class="modal" id="modal">
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script>
$(function () {
$('.details').click(function () { // class name selector
var url = $(this).data('url'); // use data(), not attr()
$("#modal").load(url, function () {
$("#modal").modal("show");
})
});
})
/*
$(".edit").click(function () {
var url = $(this).data('url'); // use data(), not attr()
$("#modal").load(url, function () {
$("#modal").modal("show");
})
})
*/
$("#.edit").click(function () {
$.ajax({
type: "POST",
url: "",
data: $('#modal').serialize(),
success: function (data) {
alert('Registro salvo com sucesso.');
$('#modal').modal('hide');
},
error: function (data) {
alert('Erro ao Salvar Registro.');
}
});
});
</script>
Modal View:
#model CaelumEstoque.Models.Prod
#{
Layout = null;
}
<div class="modal-dialog">
<div class="modal-content">
#using (Ajax.BeginForm("ParcialEdit", "Prod", new AjaxOptions { UpdateTargetId = "Error", InsertionMode = InsertionMode.Replace, OnSuccess = "OnSuccess(data)" }))
{
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title">Editar produto</h4>
</div>
<div class="modal-body">
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Codigo, new { #class = "control-label col-md-3" })
<div class="col-md-9">
#Html.TextBoxFor(model => model.Codigo, new { #class = "form-control", #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.Codigo)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Descricao, new { #class = "control-label col-md-3" })
<div class="col-md-9">
#Html.TextBoxFor(model => model.Descricao, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Descricao)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Preco, new { #class = "control-label col-md-3" })
<div class="col-md-9">
#Html.TextBoxFor(model => model.Preco, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Preco)
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" value="Salvar" class="btn btn-primary salvar" />
#*<input type="button" value="Salvar" class="btn btn-primary salvar" data-url="#Url.Action("ParcialEdit", "Prod", new {p = Model })" /> *#
<input type="button" value="Cancelar" class="btn btn-default" data-dismiss="modal" />
</div>
}
</div>
</div>
<script>
</script>
I want to know what is my mistake
Thank you

Related

Failed to create new data into the database using the popup form

I was trying to create a popup system to create new data into the database. when I click"Create" in my index view then I find a popup form.but when I click "Save" for data save then it does not work anything. suddenly it works and saves the data into the database. but it happened just one time. but I don't understand why it's not working smoothly.
Here is my code:
Model
namespace Practise.Models
{
public class Category
{
public int Id { get; set; }
public string CategoryName { get; set; }
}
}
Controller:
namespace Practise.Controllers
{
public class CategoryController : Controller
{
private ApplicationDbContext _db;
public CategoryController(ApplicationDbContext db) //input parameter
{
_db = db;
}
public IActionResult Index()
{
return View(_db.Category.ToList());
}
[HttpGet]
public IActionResult Create()
{
Category ca = new Category();
return PartialView("_CreatePartial", ca);
//return View();
}
[HttpPost]
public IActionResult Create(Category ca)
{
_db.Category.Add(ca);
_db.SaveChanges();
return PartialView("_CreatePartial", ca);
}
}
}
Index.cshtml
#model IEnumerable<Practise.Models.Category>
#{
ViewData["Title"] = "Index";
}
<div id="PlaceHolderHere"></div>
<button type="button" class="btn btn-primary" data-toggle="ajax-model" data-target="#addEmployee" data-url="#Url.Action("Create")">Create</button>
</br></br>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Id)
</th>
<th>
#Html.DisplayNameFor(model => model.CategoryName)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.CategoryName)
</td>
<td>
<partial name="_ButtonPartial" model="#item.Id" />
</td>
</tr>
}
</tbody>
</table>
#section scripts{
<script src="//cdn.jsdelivr.net/npm/alertifyjs#1.13.1/build/alertify.min.js"></script>
<script type="text/javascript">
$(function(){
var save = '#TempData["save"]'
if (save!= null) {
alertify.success(save);
}
})
</script>
}
_CreatePartial view:
#model Category
<div class="modal fade" id="#addEmployee">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="#addEmployeeLabel">Add Category</h4>
<button type="button" class="close" data-dismiss="modal">
<span>x</span>
</button>
</div>
<div class="modal-body">
<form action="Create">
<div class="form-group">
<label asp-for="CategoryName"> </label>
<input asp-for="CategoryName" class="form-control" />
<span asp-validation-for="CategoryName" class="text-danger"></span>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-save="modal">Save</button>
</div>
</div>
</div>
</div>
JS(site.js)
$(function () {
var PlaceHolderElement = $('#PlaceHolderHere');
$('button[data-toggle="ajax-model"]').click(function (event) {
var url = $(this).data('url');
$.get(url).done(function (data) {
PlaceHolderElement.html(data);
PlaceHolderElement.find('.modal').modal('show');
})
})
PlaceHolderElement.on('click', '[data-save="modal"]', function (event) {
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var sendData = form.serialize();
$.post(actionUrl, sendData).done(function (data) {
PlaceHolderElement.find('.modal').modal('hide');
})
})
})
My Output:
when I press the save button I want it to save the data to DB.but it does not work.
I have to change something like that for save data:
public IActionResult Create()
{
//Category ca = new Category();
//return PartialView("_CreatePartial", ca);
return View();
}
[HttpPost]
public IActionResult Create(Category ca)
{
_db.Category.Add(ca);
_db.SaveChanges();
return RedirectToAction("Index");
}
Create View:
#model Practise.Models.Category
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<div class="modal fade" id="#addEmployee">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="#addEmployeeLabel">Add Category</h4>
<button type="button" class="close" data-dismiss="modal">
<span>x</span>
</button>
</div>
<div class="modal-body">
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="CategoryName"> </label>
<input asp-for="CategoryName" class="form-control" />
<span asp-validation-for="CategoryName" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
#*<button type="button" class="btn btn-primary" data-save="modal">Save</button>*#
<input type="submit" class="btn btn-primary" value="Submit"/>
</div>
</form>
</div>
</div>
</div>
</div>
then successfully will save data.

How to avoid multiple submit of form in ASP.NET MVC?

I tried to write a code and scripts using ASP.NET MVC 5. Was I use modal to do Create, Update, and Delete functionality which is working properly but when it comes with Creating, and Updating because I enable remote validations, it works at first but suddenly when you click again the submit button it will submit or post the data. In short, my validation is not working. Please, I need help.
Model:
[Key]
[Display(Name = "ID")]
[Column("LAND_TYPE_CAT_ID", Order = 0, TypeName = "bigint")]
public long CategoryId { get; set; }
[Display(Name = "Category Name")]
[StringLength(100)]
[Column("LAND_TYPE_CAT", Order = 1, TypeName = "nvarchar")]
public string CategoryName { get; set; }
[Display(Name = "Description")]
[StringLength(255)]
[Column("LAND_TYPE_CAT_DESC", Order = 2, TypeName = "nvarchar")]
public string CategoryDescription { get; set; }
[Display(Name = "Created Date")]
[Column("CREATE_DATE", Order = 3, TypeName = "datetime")]
public DateTime? CreateDate { get; set; }
[Display(Name = "Modified Date")]
[Column("MODIFIED_DATE", Order = 4, TypeName = "datetime")]
public DateTime? ModifiedDate { get; set; }
[Display(Name = "Last Modified By")]
[StringLength(255)]
[Column("LAST_MODIFIED_BY", Order = 5, TypeName = "nvarchar")]
public string LastModifiedBy { get; set; }
ViewModels:
For Create:
[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateCreate", "Category", ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }
For Update:
[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateEdit", "Category", AdditionalFields = "CategoryId, CategoryName",
ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(LandTypeCategoryCreateViewModels viewModel)
{
if (ModelState.IsValid)
{
var vm = new LandTypeCategory
{
CategoryName = viewModel.CategoryName,
CategoryDescription = viewModel.CategoryDescription,
CreateDate = DateTime.Now,
LastModifiedBy = "Tester"
};
_context.LandTypeCategories.Add(vm);
await _context.SaveChangesAsync();
TempData["Created"] = "New category type added.";
var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
return Json(new {success = true, url});
}
return PartialView("_Create", viewModel);
}
public async Task<ActionResult> Edit(long? id)
{
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var vm = await _context.LandTypeCategories.FindAsync(id);
if (vm == null)
return HttpNotFound();
var viewModel = new LandTypeCategoryEditViewModels
{
CategoryId = vm.CategoryId,
CategoryName = vm.CategoryName,
CategoryDescription = vm.CategoryDescription
};
return PartialView("_Edit", viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(LandTypeCategoryEditViewModels viewModel)
{
if (ModelState.IsValid)
{
var vm =
await _context.LandTypeCategories.SingleAsync(x => x.CategoryId == viewModel.CategoryId);
vm.CategoryName = viewModel.CategoryName;
vm.CategoryDescription = viewModel.CategoryDescription;
vm.ModifiedDate = DateTime.Now;
vm.LastModifiedBy = "Modify Tester";
_context.Entry(vm).State = EntityState.Modified;
await _context.SaveChangesAsync();
TempData["Updated"] = "Category type updated.";
var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
return Json(new {success = true, url});
}
return PartialView("_Edit", viewModel);
}
Remote Validation:
public async Task<JsonResult> ValidateCreate(string CategoryName)
{
return
Json(
await _context.LandTypeCategories.AllAsync(
c => c.CategoryName.ToLower() != CategoryName.ToLower()), JsonRequestBehavior.AllowGet);
}
public async Task<JsonResult> ValidateEdit(int CategoryId, string CategoryName)
{
var category = await _context.LandTypeCategories.FindAsync(CategoryId);
var result = true;
if (category.CategoryName.ToLower() != CategoryName.ToLower())
result =
await _context.LandTypeCategories.AllAsync(
c => c.CategoryName.ToLower() != CategoryName.ToLower());
return Json(result, JsonRequestBehavior.AllowGet);
}
Index.cshtml
#model IEnumerable<MvcPPT.Models.LandTypeCategory>
#{
ViewBag.Title = "Category";
}
<div class="container">
<br />
<br />
<br />
#Html.ActionLink("Add New", "Create", "Category", new { ViewBag.CategoryId }, new { data_modal = "", #class = "btn btn-primary", style = "position: absolute;background-color: #3498db; border-color: #3498db;" })
<table class="table table-hover table-bordered" id="same-datatable" style="font-size: smaller; width: 100%;">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.CategoryId)</th>
<th>#Html.DisplayNameFor(model => model.CategoryName)</th>
<th>#Html.DisplayNameFor(model => model.CategoryDescription)</th>
<th>#Html.DisplayNameFor(model => model.CreateDate)</th>
<th>#Html.DisplayNameFor(model => model.ModifiedDate)</th>
<th>#Html.DisplayNameFor(model => model.LastModifiedBy)</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.CategoryId)</td>
<td>#Html.DisplayFor(modelItem => item.CategoryName)</td>
<td>#Html.DisplayFor(modelItem => item.CategoryDescription)</td>
<td>#Html.DisplayFor(modelItem => item.CreateDate)</td>
<td>#Html.DisplayFor(modelItem => item.ModifiedDate)</td>
<td>#Html.DisplayFor(modelItem => item.LastModifiedBy)</td>
<td>
#Html.ActionLink("Edit", "Edit", "Category", new { id = item.CategoryId }, new { data_modal = "", #class = "btn btn-warning btn-xs" })
#Html.ActionLink("Delete", "Delete", "Category", new { id = item.CategoryId }, new { data_modal = "", #class = "btn btn-danger btn-xs" })
</td>
</tr>
}
</tbody>
</table>
</div>
<div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div id="myModalContent"></div>
</div>
</div>
</div>
_Create.cshtml
#model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels
<div class="modal-header" style="background-color: #3498db; color: #fff;">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>
#using (Html.BeginForm())
{
<div class="modal-body">
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
#Html.LabelFor(model => model.CategoryName, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryName, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CategoryDescription, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryDescription, "", new {#class = "text-danger"})
</div>
</div>
<div class="modal-footer" style="padding-right: 0px;">
<input class="btn btn-success" type="submit" value="Save"/>
<button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
}
#Scripts.Render("~/bundles/jqueryval")
_Edit.cshtml
#model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels
<div class="modal-header" style="background-color: #3498db; color: #fff;">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>
#using (Html.BeginForm())
{
<div class="modal-body">
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
#Html.LabelFor(model => model.CategoryName, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryName, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CategoryDescription, new {#class = "control-label col-md-4"})
<div class="col-md-8">
#Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.CategoryDescription, "", new {#class = "text-danger"})
</div>
</div>
<div class="modal-footer" style="padding-right: 0px;">
<input class="btn btn-success" type="submit" value="Save"/>
<button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
}
#Scripts.Render("~/bundles/jqueryval")
jQuery How Modal Call:
// Add new
$.ajaxSetup({ cache: false });
$("a[data-modal]").on("click",
function (e) {
$("#myModalContent").load(this.href,
function () {
$("#myModal").modal({
keyboard: true
},
"show");
bindForm(this);
});
return false;
});
function bindForm(dialog) {
$("form", dialog).submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$("#myModal").modal("hide");
window.location.reload();
} else {
$("#myModalContent").html(result);
bindForm(dialog);
}
}
});
return false;
});
}
since both create and edit forms are partial views which i am guessing will render on same Main view i will advice you to remove the
#Scripts.Render("~/bundles/jqueryval")
from both partial pages and add the line in the top of main page since when you click the create button it will load the script bundle and again when you click the edit it will load them for the 2nd time
next is properly write the #gtml.begin form tags like
#using (Html.BeginForm(ActionName , ControllerName, FormMethod.Post))
i am not sure how is your form post is workng now
Option 1:
You can disable the button once it is submitted then.
$('form').submit(function() {
$(this).find(':submit').attr('disabled', 'disabled');
});
Option 2:
By creating a action filter. (So here you can validate duplication of anti-forgery token.)
How do I prevent multiple form submission in .NET MVC without using Javascript?

How to send model from parent to child

I have question about how to send model from parent to child using partial view and fancybox.
Here is my model
public class SampleHeaderViewModels
{
[Display(Name = "ID")]
public int intID { get; set; }
[Display(Name = "Field 1")]
public string txtField1 { get; set; }
[Display(Name = "Field 2")]
public string txtField2 { get; set; }
}
public class SampleDetailViewModels
{
[Display(Name = "ID")]
public int intID { get; set; }
[Display(Name = "Line")]
public int intLine { get; set; }
[Display(Name = "Detail 1")]
public string txtDetail1 { get; set; }
}
public class SampleViewModels
{
public SampleHeaderViewModels Header { get; set; }
public List<SampleDetailViewModels> Detail { get; set; }
public SampleDetailViewModels OneDetai { get; set; }
public SampleViewModels()
{
Header = new SampleHeaderViewModels();
Detail = new List<SampleDetailViewModels>();
OneDetai = new SampleDetailViewModels();
}
}
Here is my Index View:
<div class="row">
<div class="block">
<div class="block-content controls">
<div class="col-md-6">
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.Header.txtField1, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.HiddenFor(m => m.Header.intID)
#Html.TextBoxFor(m => m.Header.txtField1, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.Header.txtField2, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.Header.txtField2, htmlAttributes: new { #class = "form-control" })
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="block">
<div class="block-content controls">
<div class="col-md-12">
<div class="row-form">
<table id="tbDataTable" class="table table-bordered">
<thead>
<tr>
<td>
#Html.LabelFor(m => m.Detail.FirstOrDefault().intLine)
</td>
<td>
#Html.LabelFor(m => m.Detail.FirstOrDefault().txtDetail1)
</td>
</tr>
</thead>
<tbody>
#if (Model.Detail != null)
{
foreach (var item in Model.Detail)
{
<tr>
<td>
#Html.DisplayFor(m => item.intLine)
</td>
<td>
#Html.DisplayFor(m => item.txtDetail1)
</td>
</tr>
}
}
</table>
</div>
<div class="row-form">
<div class="col-md-2">
<button type="button" id="btnAddDetail" class="btn btn-info">Add Detail</button>
</div>
</div>
</div>
</div>
</div>
</div>
And my Index Have javascript:
<script>
$("#btnAddDetail").click(function () {
debugger;
var model = #Html.Raw(Json.Encode(Model));
$.ajax({
type: 'POST',
contentType: 'application/json',
url: '/Sample/ViewDetail',
//data: $('#form1').serialize(),
data: JSON.stringify(model),
contentType: "application/json; charset=utf-8",
datatype: 'JSON',
success: function (data) {
// on success, post returned data in fancybox
$.fancybox.open(data,
{
closeClickOutside: false,
iframe: {
preload: true
}
}
); // fancybox
},
error: function (data) {
console.log(data);
}
});
});
</script>
Here is my Partial View:
<div class="col-md-6">
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.OneDetai.intLine, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.OneDetai.intLine, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="row-form">
<div class="col-md-4">
#Html.LabelFor(m => m.OneDetai.txtDetail1, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-8">
#Html.TextBoxFor(m => m.OneDetai.txtDetail1, htmlAttributes: new { #class = "form-control" })
</div>
</div>
</div>
<div class="row-form">
<div class="col-md-2">
<button type="submit" id="btnAddLine" class="btn btn-info">Add Detail</button>
</div>
</div>
And this is my Controller
public ActionResult Index()
{
return View(new SampleViewModels());
}
[HttpPost]
public ActionResult ViewDetail(SampleViewModels obj)
{
return PartialView("AddDetail", obj);
}
public ActionResult AddDetail(SampleViewModels obj)
{
obj.Detail.Add(obj.OneDetail);
return View("Index", obj);
}
The idea is: In order to add new detail, I have to click btnAddDetail. And it will open popup. I have to fill the popup and click btnAddLine in child form. And the data will be appear in datatable.
The question is, how I can send my Parent Model to Child model using ajax?
When the button btnAddDetail in Index triggered, I tried to send my model in JSON, but its always send the FIRST STATE of my model. If I set value in Field 1 and Field 2, and press btnAddDetail, my ViewDetail Controller always get null model. Field1 = null, Field2 = null.
I've tried data: $('#form1').serialize(), to send my Model, It won't send my Detail Model. It just send my Header model.
Is there any way to send my Model to partial view, and send it back to my parent view?
Please help me, I haven't find any solution yet.
Thank you.
var model = #Html.Raw(Json.Encode(Model));
will not work, you will always get null...
if you have to make ajax post, you should do this to get values
for textbox values give them id and set your json
var model = {
"Header": {
"intID": 0,
"txtField1": $("#id-textField1").val(),
"txtField2": $("#id-textField2").val(),
},
"Detail": [],
"OneDetai": {
"intID": 0,
"intLine": 0,
"txtDetail1": null
}
}

MVC Update view with uploaded file

I'm new to MVC and have spent several hours trying to find a solution to this issue. I'm trying to set up an invoicing system for some rental properties. The property manger provides an excel file that contains the current water readings. I have to subtract the water readings from last months to find out the monthly usage. The view I've made does this and shows all the units simultaneously. What I'm having problems with is passing the uploaded file along with the model data (last months readings) to the controller. The file shows up but none of the other data.
In the view I have two submit buttons. One to upload the file to be integrated into the model data and the other to create the new records based on the previous and current(uploaded) data. Below are the relevant model, view and controllers.
Ultimately the billing manger would see last month's data, upload the new data, review and verify there are no errors and then submit the data for the new invoices.
If there is better way to accomplish that then what I'm trying here please let me know. This just seemed like it would be easier that recreating model data with all the linq queries. Thanks in advance for your help!
Model:
public partial class UtilityData
{
public DateTime bEntryDate { get; set; }
public string bPrevDate { get; set; }
public int bID { get; set; }
//public int residenceCount { get; set; }
public IEnumerable<UtilEntry> utilData { get; set; }
public HttpPostedFileBase UploadFile { get; set; }
}
public partial class UtilEntry
{
public int rID { get; set; }
public long? WaterReading { get; set; }
public int ResNumber { get; set; }
public long? prevWaterReading { get; set; }
public decimal wDifference { get; set; }
public int GrnUpper { get; set; }
public int GrnLower { get; set; }
public int YelUpper { get; set; }
public int YelLower { get; set; }
}
View:
#model PropertiesAdminSite.Models.UtilityData
#{
ViewBag.Title = "CreateNewCycle";
}
<h2>New Residence Utilities</h2>
#using (Html.BeginForm("Upload", "ImportWater", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="control-group">
#Html.TextBoxFor(m => m.UploadFile, new { type = "file"})
#*<input type="file" class="btn btn-info" name="postedFile"/>*#
</div>
<div class="control-group">
<input type="submit" class="btn btn-info" value="Upload" />
</div>
<div class="col-lg-12 visible-lg">
<br>
<span style="color:green">#ViewBag.Message</span>
</div>
}
#using (Html.BeginForm("IndexMulti", "Utilities", FormMethod.Post))
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
#Html.LabelFor(model => model.bEntryDate, htmlAttributes: new { #class = "control-label col-md-1" })
#Html.DisplayFor(model => model.bEntryDate)
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="dataTable_wrapper">
<!--div id="dataTables-example_wrapper" class="dataTables_wrapper form-inline dt-bootstrap no-footer">-->
<div class="row">
<div class="col-sm-12">
<table class="table table-striped table-bordered table-hover dataTable no-footer" id="dataTables-Bills" role="grid" aria-describedby="dataTables-example_info">
<!-- /table headers-->
<thead>
<tr role="row">
<th>#Html.DisplayNameFor(model => model.utilData.First().ResNumber)</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().WaterReading)</th>
<th>
#Html.DisplayNameFor(model => model.utilData.First().prevWaterReading)
#* TODO: fix date format *#
#Html.DisplayFor(model => model.bPrevDate)
</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().wDifference)</th>
<th>Actions</th>
</tr>
</thead>
<!-- /table body-->
<tbody>
#foreach (var item in Model.utilData)
{
<tr role="row">
<td>
#Html.DisplayFor(modelItem => item.ResNumber, null, "residence_" + item.rID)
#Html.HiddenFor(model => item.GrnLower, new { id = "grnLower_" + item.rID })
#Html.HiddenFor(model => item.GrnUpper, new { id = "grnUpper_" + item.rID })
#Html.HiddenFor(model => item.YelLower, new { id = "yelLower_" + item.rID })
#Html.HiddenFor(model => item.YelUpper, new { id = "yelUpper_" + item.rID })
</td>
<td>
#Html.EditorFor(model => item.WaterReading, null, "waterReading_" + item.rID)
</td>
<td>
<span id="#string.Format("prevWater_{0}",item.rID)">
#Html.DisplayFor(model => item.prevWaterReading, null, "prevWater_" + item.rID)
</span>
#Html.HiddenFor(model => item.prevWaterReading, new { id = "hprevWater_" + item.rID })
</td>
<td>
<span id="#string.Format("hdifference_{0}",item.rID)">
#Html.DisplayFor(model => item.wDifference)
</span>
#Html.HiddenFor(model => item.prevWaterReading, new { id = "hdifference_" + item.rID })
</td>
<td>
#Html.ActionLink("View History", "ExportDataIndex", "ExportData", new { rID = item.rID, bId = Model.bID }, null) |
<a href="#Url.Action("ExportToExcel", "ExportData", new { rID = item.rID, bId = Model.bID })" class="btn btn-success">
<i class="fa fa-file-excel-o" aria-hidden="true" title="Export to Excel"></i>
</a> |
<a href="#Url.Action("ChartData", "Utilities", new { rID = item.rID, bId = Model.bID })" class="btn btn-info">
<i class="fa fa-bar-chart" aria-hidden="true" title="Water Usage History"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
Controller:
// GET: ImportWater
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload([Bind(Include = "bEntryDate,bPrevDate,bID,utilData,UploadFile")]UtilityData uData) //<----The file gets uploaded but none of the Model data from the view.
{
HttpPostedFileBase postedFile = uData.UploadFile;
if (postedFile != null && postedFile.ContentLength > 0)
{
string fileName = postedFile.FileName;
string fileContentType = postedFile.ContentType;
byte[] fileBytes = new byte[postedFile.ContentLength];
var data = postedFile.InputStream.Read(fileBytes, 0, Convert.ToInt32(postedFile.ContentLength));
using (var package = new ExcelPackage(postedFile.InputStream))
{
//Todo: read file and insert data
}
ViewBag.Message = "File uploaded successfully.";
}
return View(uData);
}
I now understand what the issue was; I didn't fully understand how the POST worked. I thought the form would always send the full model object back and that is not the case. I created hidden items to capturethe model data I wanted to post back.
#using (Html.BeginForm("Upload", "ImportWater", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="control-group">
#Html.TextBoxFor(m => m.UploadFile, new { type = "file"})
#*<input type="file" class="btn btn-info" name="postedFile"/>*#
</div>
<div class="control-group">
<input type="submit" class="btn btn-info" value="Upload" />
</div>
<div class="col-lg-12 visible-lg">
<br>
<span style="color:green">#ViewBag.Message</span>
#Html.HiddenFor(model => model.bID)
#Html.HiddenFor(model => model.bEntryDate)
#Html.HiddenFor(model => model.bPrevDate)
#for (int i = 0; i < Model.utilData.Count(); i++)
{
#Html.HiddenFor(model => model.utilData[i].ResNumber)
#Html.HiddenFor(model => model.utilData[i].GrnLower)
#Html.HiddenFor(model => model.utilData[i].GrnUpper)
#Html.HiddenFor(model => model.utilData[i].prevWaterReading)
#Html.HiddenFor(model => model.utilData[i].rID)
#Html.HiddenFor(model => model.utilData[i].WaterReading)
#Html.HiddenFor(model => model.utilData[i].wDifference)
#Html.HiddenFor(model => model.utilData[i].YelLower)
#Html.HiddenFor(model => model.utilData[i].YelUpper)
}
</div>
}

Return different model on partial view

I'm having some trouble returning a ViewBag with a list of a model to a PartialView, which is a different type of model from the ParentView, but I wish to render the result, only inside the partial view that is rendered on the Parent View. Perhaps looking at my code, will give a better understanding.
Here is my controller:
public ActionResult Search()
{
//ViewBag.Usuarios = db.User.ToList();
return View();
}
[HttpGet]
public ActionResult Pesquisar(UserFilter userFilter)
{
List<UserModel> retorno = new List<UserModel>();
ViewBag.Mensagem = "Não foi encontrado registro com os filtros informados";
if (userFilter.Name != null)
{
retorno = db.User.Where(x => x.Name.Contains(userFilter.Name)).ToList();
if (retorno != null)
{
ViewBag.Usuarios = retorno;
return PartialView("Search", ViewBag.Usuarios);
}
return View("Search", ViewBag.Mensagem);
}
if (userFilter.UserID != 0)
{
UserModel retorn = new UserModel();
var id = Convert.ToInt16(userFilter.UserID);
retorn = db.User.FirstOrDefault(x => x.UserID == id);
return View("Details", retorn);
}
return View("Search", ViewBag.Mensagem);
}
Here is my Parent View
#model Sistema_ADFP.Filters.UserFilter
<body>
<div class="container">
<h2>Buscar Usuário</h2>
<form role="form" method="GET" action="/User/Pesquisar">
<div class="col-lg-12">
<div class="col-lg-3">
<div class="form-group">
<label>Nome</label>
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label>ID</label>
#Html.EditorFor(model => model.UserID, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label>CPF</label>
#Html.EditorFor(model => model.CPF, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="form-group pull-right">
<label> </label>
<input type="submit" class="btn btn-primary"/>
</div>
</form>
</div>
<div class="clearfix"></div>
#{
if (ViewBag.Mensagem == null)
{
<div id="resultadoLista">
#{
Html.RenderPartial("_List");
}
</div>
}
else
{
<label>Nenhum registro encontrado</label>
}
}
</body>
And here is my Partial View
<h4>Usuários</h4>
<div class="table-responsive">
<table class="table">
<tr class="inverse" align="center">
<th>Nome</th>
<th>Sexo</th>
<th>Estado Civil</th>
<th>Educação</th>
<th>Profissão</th>
<th>Voluntário</th>
<th>Data Nascimento</th>
<th>Ações</th>
</tr>
#if (ViewBag.Usuarios != null)
{
foreach (var item in ViewBag.Usuarios)
{
<tr class="active">
<td data-th="Nome"><a class="modal-ajax-link" href="#test-popup">#item.Name</a></td>
<td data-th="Sexo">#item.Sex</td>
<td data-th="EstadoCivil">#item.MaritalStatus</td>
<td data-th="Education" align="center">#item.Education.Description</td>
<td data-th="Education" align="center">#item.Profession.Name</td>
#if (item.Voluntary)
{
<td data-th="Voluntario" align="center">Ativo</td>
}
else
{
<td data-th="Voluntario" align="center">Inativo</td>
}
<td data-th="DataNasc" align="center">#item.BirthDate</td>
#* data-mfp-src="#HttpContext.Current.Request.Url.Host:#HttpContext.Current.Request.Url.Port/User/Details/2" *#
<td data-th="Ações" align="center">
<a class="btn btn-info modal-ajax-link" href='#Html.ActionLink("Editar", "Edit",
new { id = #item.UserID })'><i class="icon_pencil"></i></a>
<a class="btn btn-danger modal-ajax-link" href="#delete-modal"><i class="icon_trash_alt"></i></a>
</td>
</tr>
}
}
</table>
</div>
The error that i'm getting is:
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[Sistema_ADFP.Models.UserModel]',
but this dictionary requires a model item of type
'Sistema_ADFP.Filters.UserFilter'.
I understand the error reason , but I can not get to a means of resetting the flow and make it work. Does anybody knows or have a tip of what i can do ?
The solution to fix this is by not using ViewBag and create ViewModel for your view. The ViewModel is a class for your view and will have all necessary properties for your view. So, for the sake of example, you could have a view model called:
public class WrapperVM
{
public UserFilter Filter {get; set;}
public UserModel Model {get; set;}
}
Thus, fill these properties and pass WrapperVM to parent view (change to #model WrapperVM) and then you can pass usermodel to partial view. I hope this helps.

Categories

Resources