here's the code dropdown and textbox:
<form id="myForm">
<label for="departmentsDropdown"><b>Department</b></label>
<select class="form-control" onchange="getValue()"
id="numero_control" name="numero_control">
</select><br />
<input type="text" value="" id="Nombre" /><br>
<input type="text" value="" id="id" /><br>
</form>
function onchange:
<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<div class="jumbotron">
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/Home/GetData",
data: "{}",
success: function (data) {
var s = '<option value="-1">Porfavor selecciona algun valor</option>';
for (var i = 0; i < data.length; i++) {
s += '<option value="' + data[i].Nombre + data[i].id + '">' +
data[i].numero_control + '</option>';
}
$("#numero_control").html(s);
}
});
});
function getValue() {
var myVal = $("#numero_control").val();
$("#Nombre").val(myVal);
$("#id").val(myVal);
}
</script>
</div>
Controller action method:
crudEntities db = new crudEntities();
public ActionResult Index()
{
return View();
}
public ActionResult GetData()
{
var data = from als in
db.registro select new
{ als.id, als.Nombre,als.numero_control };
return Json(data.ToList(),
JsonRequestBehavior.AllowGet);
}
my error is I have two value in the dropdown i was load in two textbox the problem is if i run the project watch the two value in one textbox input:
Image of the error:
I would like it to come out like this:
I have information such as id, Nombre, numero_control. When I choose the numero_control from the dropdown, I want to print id on one of the 2 textboxes and id on the other textbox.
I followed this video to do it.
Related
Need to upload files using MVC model biding by AJAX jQuery/JSON.
I was uploading with a normal submit form, but now I need to change to AJAX.
How can I do this? I mean, biding using MVC and AJAX, serializing my form or something like that.
Now, my imagemPro and imagemPre, on Controller, are always 'null'.
At my View:
#model Ri.Models.Produto
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="#Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="#Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="#Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="#Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
#section scripts{
<script src="~/admin/js/produtoAdd.js"></script>
}
At my Controller:
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd([Bind("TituloProduto,ImagemProduto,TituloPremio,ImagemPremio")] Produto produto, IFormFile imagemPro, IFormFile imagemPre)
{
if (!ModelState.IsValid)
{
return Json(new { success = false, msg = "1" });
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPro.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemProduto = imagemPro.FileName;
}
if (imagemPro != null)
{
var name = Path.Combine(_enviroment.WebRootPath + "/imgs", System.IO.Path.GetFileName(imagemPre.FileName));
await imagemPro.CopyToAsync(new FileStream(name, FileMode.Create));
produto.ImagemPremio = imagemPre.FileName;
}
_context.Add(produto);
await _context.SaveChangesAsync();
return Json(new { success = true });
}
My script:
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
//alert('false');
}
});
Create = function () {
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.cache = true;
options.async = true;
contentType = "application/json; charset=utf-8",
options.data = $('#frmAdd').serialize();
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
I recommend you to create a viewModel
public class ProdutoViewModel
{
public Produto Produto {get; set;}
public IFormFile ImagemPro {get; set;}
public IFormFile ImagemPre {get; set;}
}
action ( remove Bind attribute too)
[HttpPost("/api/ProdutoAdd")]
public async Task<IActionResult> ProdutoAdd(ProdutoViewModel model )
I recommend you to use a submit button instead of ajax, it would be much easier for you
#model ProdutoViewModel
<form class="settings-form" id="frmAdd" enctype="multipart/form-data">
....
<input type="submit" value="Criar" class="btn app-btn-primary">
</form>
1.Model Binding binds the property by name attribute, your parameter name here is imagemPro/imagemPre.
2.The jQuery serialize() method will not include input file elements. So file user selected is not going to be included in the serialized value.
You need create a FormData object, append the files to that then append the form field values as well to this same FormData object. You may simply loop through all the input field and add it.
Here is a whole working demo you could follow:
#model Produto
//add `method="post"` in form tag
//otherwise it will not generate token input
<form class="settings-form" id="frmAdd" enctype="multipart/form-data" method="post">
<label for="setting-input-1" class="form-label">Título</label>
<input asp-for="#Model.TituloProduto" type="text" class="form-control" required>
<input asp-for="#Model.ImagemProduto" type="file" class="form-control" required>
<label for="setting-input-1" class="form-label">Premio</label>
<input asp-for="#Model.TituloPremio" type="text" class="form-control" required>
<input asp-for="#Model.ImagemPremio" type="file" class="form-control" required>
<input type="button" value="Criar" class="btn app-btn-primary" id="btnAdd">
</form>
#section scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/admin/js/produtoAdd.js"></script>
}
JS:
<script>
$(function () {
$("#btnAdd").click(function (e) {
e.preventDefault();
var _this = $(this);
var _form = _this.closest("form");
var isvalid = _form.valid();
if (isvalid) {
Create();
}
else {
}
});
Create = function () {
var fdata = new FormData();
var fileInput1 = $('#ImagemProduto')[0];
var file1 = fileInput1.files[0];
fdata.append("imagemPro", file1);
var fileInput2 = $('#ImagemPremio')[0];
var file2 = fileInput2.files[0];
fdata.append("imagemPre", file2);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
var options = {};
options.type = "POST";
options.url = "/api/ProdutoAdd";
options.dataType = "JSON";
options.contentType = false; //change here...
options.processData= false; //add this...
options.data = fdata;
options.beforeSend = function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val());
};
options.success = function (data) {
};
options.error = function (res) {
};
$.ajax(options);
};
});
</script>
Your payload and your content type don't match. jQuery.serialize encodes your form data as application/x-www-form-urlencoded, but you're telling the server to expect a content type of application/json. Easiest solution is to change the content type.
Also, you might want to use the form submit event of the form, rather than a 'click' event on a button. The reason for this is that browsers will submit forms in other ways besides clicking the button, (e.g. pressing "enter" key while in a text input). Submit will handle all of these methods.
Another side note: your method of creating your options object will work, but that syntax is a little awkward. The most common "best practice" is to declare the properties inline with the object:
var options = {
type: 'POST',
url: '/api/ProdutoAdd',
// etc ...
success: function (data) {
},
// etc ...
};
That keeps you from having to type options. before every property.
I'm trying to persist a TempData value on a return PartialView(). It works correctly in one Post but not another and I'm stymied.
In the following action it works correctly and the value gets passed, via javascript redirect to the action that is using the value:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult DeletetheFile(int attachmentid, string issueId)
{
string response = _adoSqlService.DeleteAttachment(attachmentid);
TempData["ID"]= issueId;
TempData.Keep();
return PartialView("_DeleteFile");
}
In the following action it is getting set properly (see the first image), but by the time it gets to the same action as the first one I showed it has changed (see second image).
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult EditFile(IFormCollection collection)
{
AttachmentModel model = new AttachmentModel();
model.attachmentId = Convert.ToInt32(collection["attachmentId"]);
model.aIssueAttachmentDescription = collection["aIssueAttachmentDescription"];
string response = _adoSqlService.EditFileDescription(model);
TempData.Remove("ID");
TempData["ID"] = collection["issueId"];
TempData.Keep();
return PartialView("_EditFile");
}
When it gets to the where I need it is now returning [string1] instead of the 20-003.
Both of the above actions run against a partial view in a modal pop-up. The following javascript captures the modal action and redirects the results to the Issue/Edit controller/action.
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
})
The redirection seems to happen since the edit action is being called in both cases. It's just that in the second case it is not getting the correct value of the TempData value. Here is the start of the Edit action which resides in a different controller than the 2 actions above:
public ActionResult Edit(string id)
{
if (id == null)
{
id = TempData["ID"].ToString();
}
----------More Comments
So after working on this for the past 4 hrs I've come up with a work-around. I'm not sure this is the correct technique or not. What I ended up doing was adding a hidden input field on the partial views and then parsing the ajax response for that value.
var issueid = $(response).find('[name="issueidSaved"]').val();
window.location.href = "/Issue/Edit/?id=" + issueid
My concern now is that the issueid is now included in the query string and is visible in the URL.
Is this the correct method or should I go back to using TempData and trying to get that to work?
UPDATE
Hopefully I can explain this better. The goal is to get a TempData value into the following action in my Issues Controller which is tied to my Edit Page (Issues/Edit):
public ActionResult Edit(string id)
{
if (id == null)
{
id = TempData["ID"].ToString();
}
I have a modal on my Edit page that is populated with different partial views depending upon what is populating it. The partial views use the Attachment controller, while the Edit view uses the Issues Controller. I use Javascript/ajax to capture the submit from the partial views to close the modal and redirect to the Edit view so a refresh of the data affected by the partial views is reflected on the Edit view. The TempData value is working correctly when I submit the _DeleteFile, but not when I submit the _EditFile partial views in the modal.
Here is the common Javascript/ajax on the Edit view:
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
//Using this to scroll the page on the close of the modal/page refresh
$(document).ready(function () {
var JumpTo = '#ViewBag.JumpToDivId';
if (JumpTo != "") {
$(this).scrollTop($('#' + JumpTo).position().top);
}
});
//Using this to Capture the click that opens the modals
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
//Using this to Capture the click that Submits the _EditFile,_DeleteFile,_CreateEdit forms on the modal
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
var issueid = "";
issueid = $('body').find('[name="issueidSaved"]').val();
var jumpto = $('body').find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
if (issueid == "")
{
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto=" + jumpto;
}
}
});
})
//Using this to Capture the click that Submits the _UploadFile form on the modal
$(function () {
$('body').on('click', '.fileupload', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var fdata = new FormData();
$('input[name="file"]').each(function (a, b) {
var fileInput = $('input[name="file"]')[a];
if (fileInput.files.length > 0) {
var file = fileInput.files[0];
fdata.append("file", file);
}
});
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$("form input[type='hidden']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
url: actionUrl,
method: "POST",
contentType: false,
processData: false,
data: fdata
}).done((response, textStatus, xhr) => {
var isValid = $(response).find('[name="IsValid"]').val() == 'True';
var issueid = $(response).find('[name="issueidSaved"]').val();
var jumpto = $(response).find('[name="jumpto"]').val();
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit/?id=" + issueid + "&jumpto="+jumpto;
}
});
})
});
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
Here is the _DeleteFile Partial view and the AttachmentController code that handles the submit:
<!--Modal Body Start-->
<div class="modal-content">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<input name="issueidSaved" type="hidden" value="#ViewBag.ID" />
<input name="jumpto" type="hidden" value="#ViewBag.JumpToDivId" />
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Delete File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="DeletetheFile" asp-route-attachmentid="#ViewBag.id" asp-route-issueId="#ViewBag.issueId" asp-controller="Attachment" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
Are you sure you want to delete the #ViewBag.title File?
<!--Modal Footer Start-->
<div class="modal-footer">
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">No</button>
<input type="submit" class="btn btn-success relative" id="btnSubmit" data-save="modal" value="Yes">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult DeletetheFile(int attachmentid, string issueId)
{
string response = _adoSqlService.DeleteAttachment(attachmentid);
ViewBag.ID = issueId;
ViewBag.JumpToDivId = "upload";
TempData["ID"]= issueId;
TempData.Keep();
return PartialView("_DeleteFile");
}
Here is the _EditFile partial view and the AttachmentController code:
Edit File
×
<form asp-action="EditFile" asp-controller="Attachment" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<input name="issueId" type="hidden" value="#ViewBag.issueId" />
<input name="attachmentId" type="hidden" value="#ViewBag.attachmentId" />
<label class="control-label">#ViewBag.aFileName</label><br />
Make changes to description then select "Save Changes".<br />
<input name="aIssueAttachmentDescription" class="form-control formtableborders" id="titletext" value="#ViewBag.aIssueAttachmentDescription" />
<!--Modal Footer Start-->
<div class="modal-footer">
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">No</button>
<input type="submit" class="btn btn-success relative" id="btnSubmit" data-save="modal" value="Save Changes">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult EditFile(IFormCollection collection)
{
AttachmentModel model = new AttachmentModel();
model.attachmentId = Convert.ToInt32(collection["attachmentId"]);
model.aIssueAttachmentDescription = collection["aIssueAttachmentDescription"];
string response = _adoSqlService.EditFileDescription(model);
ViewBag.ID = collection["issueId"];
ViewBag.JumpToDivId = "upload";
TempData.Remove("ID");
TempData["ID"] = collection["issueId"];
TempData.Keep();
return PartialView("_EditFile");
}
When I inspect the TempData at the Issue/Edit action after the _DeleteFile submit it displays the following (which is correct):
When I inspect the TempData at the Issue/Edit action after the _EditFile submit it displays the following (which is incorrect):
You need to change
TempData["ID"] = collection["issueId"];
to
TempData["ID"] = collection["issueId"].ToString();
Because collection["issueId"] is Type Microsoft.Extensions.Primitives.StringValues rathar than Type String.
Here is a picture to show the Type:
I am using MVCGrid.NET http://mvcgrid.net/
And I created a Non-Fluent grid http://mvcgrid.net/gettingstarted see Non-Fluent Example
GridDefinition<YourModelItem> def = new GridDefinition<YourModelItem>();
GridColumn<YourModelItem> column = new GridColumn<YourModelItem>();
column.ColumnName = "UniqueColumnName";
column.HeaderText = "Any Header";
column.ValueExpression = (i, c) => i.YourProperty;
def.AddColumn(column);
def.RetrieveData = (options) =>
{
return new QueryResult<YourModelItem>()
{
Items = new List<YourModelItem>(),
TotalRecords = 0
};
};
MVCGridDefinitionTable.Add("NonFluentUsageExample", def);
Now I have my grid appear when you submit a form, but when I submit the form again, I am expecting new data, but the grid does not reload or refresh or anything. It does't even reset when I refresh the page, I have to do a full reload of the page to reset it, which is lame, does anyone know how to refresh or reload the grid when I want to show new data?
I have even tried this: http://mvcgrid.net/demo/NoQueryOnPageLoad
But it did not reload or refresh.
PLEASE HELP!
It reloads, try this,
//model class
public class YourModelItem
{
public int Id { get; set; }
public string YourProperty { get; set; }
}
//controller
public class HomeController : Controller
{
private static List<YourModelItem> _modelItems = new List<YourModelItem>();
public ActionResult Index()
{
GridDefinition<YourModelItem> def = new GridDefinition<YourModelItem>();
GridColumn<YourModelItem> column = new GridColumn<YourModelItem>();
column.ColumnName = "UniqueColumnName";
column.HeaderText = "Any Header";
column.ValueExpression = (i, c) => i.YourProperty;
def.AddColumn(column);
def.RetrieveData = (options) => new QueryResult<YourModelItem>()
{
Items = _modelItems,
TotalRecords = 0
};
MVCGridDefinitionTable.Add("NonFluentUsageExample", def);
return View();
}
[HttpPost]
public JsonResult Add(YourModelItem item)
{
_modelItems.Add(item);
return Json(true, JsonRequestBehavior.AllowGet);
}
}
index.cshtml
#{
ViewBag.Title = "Home Page";
}
#using MVCGrid.Web
<div class="jumbotron">
<div id="form1">
<div class="form-group">
<label for="Id">ID</label>
<input type="number" class="form-control" id="Id" aria-describedby="Id" placeholder="Enter Id">
</div>
<div class="form-group">
<label for="YourProperty">YourProperty</label>
<input type="text" class="form-control" id="YourProperty" placeholder="Enter Your Property">
</div>
<button id="addItem">Submit</button>
</div>
<br />
#Html.MVCGrid("NonFluentUsageExample")
</div>
#section scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#addItem").click(function () {
var formData = { Id: $('#Id').val(), YourProperty: $('#YourProperty').val() };
$.ajax({
type: "POST",
url: "/Home/add",
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(formData),
success: function(data) {
if (data) {
MVCGrid.reloadGrid('NonFluentUsageExample');
}
}
});
});
});
</script>
}
_layout.cshtml -> body
<body>
<div class="container body-content">
#RenderBody()
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
<script src="~/MVCGridHandler.axd/script.js"></script>
#RenderSection("scripts", required: false)
</body>
It adds item and reloads after "Submit".
Just have installed MVCGrid in new asp.net mvc - Install-Package MVCGrid.Net
Put these lines as above
I am new to MonoDevelop, C#, and Linux. To learn how things work, I'm trying to make a simple web page to input the height and width of a rectangle, then use a submit button to calculate and display the area.
I have two problems. First, I can't get the submit button to actually do anything. Second, I'm having trouble getting the value of the textboxes in the C# code. Once I get it, I think I can handle the values okay to calculate the area and spit it back out. The Request.Form commands were my point of problem I believe.
Here's what I have so far:
<body>
<div>
Height <input type="text" name="inHeight" value=1 /><br />
Width <input type="text" name="inWidth" value=1 /><br />
<br />
<input type="button" name="btnCalculateArea" value="Calculate Area" onclick="CalculateArea()" /><br />
<br />
<%= Html.Encode(ViewData["Message"]) %>
</div>
</body>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace rectangle_area.Controllers
{
public class HomeController : Controller
{
public string strHeight;
public string strWidth;
public int intHeight;
public int intWidth;
public double dblArea;
public ActionResult Index ()
{
return View ();
}
public ViewResult CalculateArea ()
{
strHeight = Request.Form ["inHeight"];
strWidth = Request.Form ["inWidth"];
if (strHeight != null && strWidth != null) {
intHeight = Convert.ToInt16 (strHeight);
intWidth = Convert.ToInt16 (strWidth);
dblArea = intHeight * intWidth;
ViewData ["Message"] = "The area of this rectangle is " + dblArea + " square units.";
} else {
ViewData ["Message"] = "Please enter values for the Height and Width.";
}
return View ();
}
}
}
You have to bind there a function that makes an ajax call to your controller.
Thanks for the direction, Christos! With the help of a friend and more research, I got it working. Here's what I ended up with:
<head runat="server">
<title>Calculate the area of a rectangle</title>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var serviceURL = '/Home/CalculateArea';
$('#calcBtn').click(function(){
$.ajax({
type: "GET",
url: serviceURL,
data: { inHeight: $("#inHeight").val(), inWidth: $("#inWidth").val() },
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
});
function successFunc(data, status) {
alert(data);
}
function errorFunc() {
alert('error');
}
});
</script>
</head>
<body>
<div>
Height <input type="text" id="inHeight" value=2 /><br />
Width <input type="text" id="inWidth" value=3 /><br />
<br />
<input id="calcBtn" type="submit" value="Calculate Area" /><br />
<br />
</div>
</body>
[HttpGet]
public ActionResult CalculateArea ()
{
strHeight = Request.Params ["inHeight"];
strWidth = Request.Params ["inWidth"];
if (strHeight != null && strWidth != null) {
intHeight = Convert.ToInt16 (strHeight);
intWidth = Convert.ToInt16 (strWidth);
dblArea = intHeight * intWidth;
ViewData ["Message"] = "The area of this rectangle is " + dblArea + " square units.";
} else {
ViewData ["Message"] = "Please enter values between 0 and 999.";
}
return Json(ViewData["Message"], JsonRequestBehavior.AllowGet);
}
I am very new to both JQuery and Asp.net MVC 3 (C#), so I apologize if this is trivial. I have an MVC partial view (Index.cshtml) that has a list of tasks. These tasks are contained within indivudal divs that I have in a list style layout. I have a button called "add task" that opens a dialog. This dialog will save the added task to the database via an AJAX Json call to the controller.
This is where I am having trouble - after the dialog closes I would like the list of tasks to reload with the task i just added. I have found examples where the entire page is reloaded, and I found examples where the controller is supposed to return a rendered view. My problem is that the dialog is being opened from the partial I want to reload. Is there a way to accomplish what I am trying to do.
Index.cshtml
#model IEnumerable<TaskManagementApplication.Models.Project>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div id="ProjectAccordionWrapper">
#foreach (var item in Model)
{
<div class="ProjectWrapper">
<h3>#item.Name</h3>
<div class="column">
<button class="createTaskButton" id="#item.ProjectID">Create New Task</button>
#foreach(var task in item.Tasks) {
var buttonClass = "taskID" + task.TaskID;
<div class="portlet">
<div class="portlet-header">#task.TaskName</div>
<div class="portlet-content">#task.TaskDescription</div>
<button class="editTaskButton" id="#task.TaskID">Edit Task</button>
</div>
}
</div>
</div>
}
</div>
<div id="dialog-form" title="Create new user">
<p class="validateTips">All form fields are required.</p>
<form>
<fieldset>
<label for="TaskName">Task Name</label>
<input type="text" name="TaskName" id="name" class="text ui-widget-content ui-corner-all" />
<label for="TaskDescription">Task Description</label>
<input type="text" name="TaskDescription" id="description" value="" class="text ui-widget-content ui-corner-all" />
<input type="hidden" name="TaskID" id="ID" />
<input type="hidden" name="ProjectID" id="ProjectID" />
</fieldset>
</form>
</div>
Partial Javascript
function GetTask(id) {
if (id.length > 0) {
$.ajax({
url: '/Project/GetTaskFromID',
type: "POST",
data: { "id": id },
success: PopulateDialogFields,
error: HandleError
});
}
}
function PopulateDialogFields(data) {
$("#name").val(data.TaskName);
$("#description").val(data.TaskDescription);
$("#ID").val(data.TaskID);
}
function HandleError(data) {
alert(data.error);
var foo = data;
}
function SaveTask() {
var taskName = $("#name").val();
var taskDescription = $("#description").val();
var id = $("#ID").val();
var projectID = $("#ProjectID").val();
if (id.length > 0) {
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "taskID": id }
});
}
else {
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "projectID": projectID }
});
}
}
$("#dialog-form").dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
"OK": function () {
SaveTask();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
},
close: function () {
allFields.val("").removeClass("ui-state-error");
window.location.reload(true);
},
open: function () {
var id = $(this).data("id");
var projectID = $(this).data("projectID");
$("#ProjectID").val(projectID);
var button = $("#" + id);
GetTask(id);
}
});
$(".editTaskButton")
.button()
.click(function () {
$("#dialog-form").data('id', this.id).dialog("open");
});
$(".createTaskButton")
.button()
.click(function () {
$("#dialog-form").data('projectID', this.id).dialog("open");
});
I am relatively new to jQuery and ASP.NET MVC as well, however, here's what first comes to mind.
In order to maintain the AJAX-y aspect of the page, I suggest that you create a method that handles a POST which returns a JSON formatted set of TaskManagementApplication.Models.Project. This method can optionally return filtered results.
The markup would look like this,
<div id="ProjectAccordionWrapper">
<div id="ProjectWrapperTemplate" class="ProjectWrapper" style="display: none;">
<h3 id="itemName"></h3>
<div class="column">
<button class="createTaskButton" id="itemProjectID">Create New Task</button>
<div id="portletTemplate" class="portlet">
<div class="portlet-header" id="taskName"></div>
<div class="portlet-content" id="taskDescription"></div>
<button class="editTaskButton" id="taskID">Edit Task</button>
</div>
</div>
</div>
</div>
Next, you would have jQuery clone the ProjectWrapperTemplate element, and set all of the corresponding fields.
$(function () {
$.ajax({
url: '/Project/GetTasks',
type: "POST",
data: { }
}).done(function (data) {
data.forEach(function (element) {
AppendProjectWrapper(element);
});
});
function AppendProjectWrapper(data) {
var projectAccordionWrapper = $('#ProjectAccordionWrapper');
var projectWrapper = $('#ProjectWrapperTemplate').clone(true, true);
projectWrapper.id = nothing; // remove the id, so as to not have duplicates
projectWrapper.style.display = nothing; // remove the style "display: none"
var itemName = projectWrapper.children('#itemName'); // h3
itemName.id = nothing;
itemName.text(data.ItemName);
var itemProjectID = projectWrapper.children('#itemProjectID'); // button Create New Task
itemProjectID.id = data.ItemProjectID;
var portletTemplate = projectWrapper.children('#portletTemplate'); // div
data.Tasks.forEach(function (element) {
var portlet = portletTemplate.clone();
portlet.id = nothing;
var taskName = portlet.children('#taskName');
taskName.id = nothing;
taskName.text(element.TaskName);
var taskDescription = portlet.children('#taskDescription');
taskDescription.id = nothing;
taskDescription.text(element.TaskDescription);
var editTaskButton = portlet.children('#taskID');
editTaskButton.id = element.TaskID;
portlet.appendTo(projectWrapper);
});
portletTemplate.remove(); // remove the portlet template element
projectWrapper.appendTo(projectAccordionWrapper);
}
}
Finally, have '/Project/SaveTask' return a JSON formatted TaskManagementApplication.Models.Project of the currently saved task.
$.ajax({
url: '/Project/SaveTask',
type: "POST",
data: { "taskName": taskName, "taskDescription": taskDescription, "taskID": id }
}).done(function (data) {
AppendProjectWrapper(data);
});
The return data for '/Project/GetTasks' should look as follows:
[
{
ItemName: '#item.Name',
ItemProjectID: '#item.ProjectID',
Tasks: [
TaskName: '#task.TaskName',
TaskDescription: '#task.TaskDescription',
TaskID: '#task.TaskID'
]
}
]
The return data from '/Project/SaveTask' should follow the same format, except or the outer-most array.
Please note that a lot of this code is untested.
It may be easiest to refactor the list into another action+view. Then, you can call this in both the original Index.cshtml view, and via the .load() method in jQuery. So, assuming this:
Projects controller
[HttpGet]
[ChildActionOnly]
public ActionResult Tasks(int id)
{
// create the appropriate model object as an IEnumerable of your Task type
return View(model);
}
Tasks.cshtml
#foreach(var task in Model) {
var buttonClass = "taskID" + task.TaskID;
<div class="portlet">
<div class="portlet-header">#task.TaskName</div>
<div class="portlet-content">#task.TaskDescription</div>
<button class="editTaskButton" id="#task.TaskID">Edit Task</button>
</div>
}
You would adjust Index.cshtml like so:
#model IEnumerable<TaskManagementApplication.Models.Project>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div id="ProjectAccordionWrapper">
#foreach (var item in Model)
{
<div class="ProjectWrapper">
<h3>#item.Name</h3>
<div class="column">
<button class="createTaskButton" id="#item.ProjectID">Create New Task</button>
<div id="tasks-#item.ProjectID">
#Html.Action("Tasks", "Project", new { id = item.ProjectID })
</div>
</div>
</div>
}
</div>
//... the rest of the view
And finally,
// this should happen inside the callback of your .ajax() method
$('#tasks-'+projectID).load('/project/tasks/'+ projectID);