ASP.Net MVC passing data from script to new view - javascript

Hi everyone and thanks for reading this message at first.
I am currently struggling with an ASP.Net MVC Framework project for passing data between views.
I have a controller Model with Index View and a javascript that helps me getting ids of objects clicked on a 3d model rendered in a canvas. Here is the view :
<div class="col-md-10">
<canvas id="viewer"></canvas>
</div>
<div class="col-md-2">
<btn id="AddEventObjects" class="btn btn-eiffage-red">Create a task</btn>
<table id="selectedElements" class="table table-striped">
<thead><tr><th>Selected parts</th></tr></thead>
</table>
</div>
<script type="text/javascript">
var viewer = new xViewer('viewer');
var selectedIds = [];
viewer.on('loaded',
() => {
viewer.start();
});
viewer.on('pick', function (args) {
if (args == null || args.id == null) {
return;
}
var id = args.id;
//If the id was previously clicked then remove it from the list and remove the highlight
if (selectedIds.includes(id)) {
var index = selectedIds.indexOf(id);
selectedIds.splice(index, 1);
} else {
selectedIds.push(id);
}
//Add elements to the table
var table = document.getElementById('selectedElements');
var oldtbody = document.getElementById('selectedElementsBody');
if (oldtbody) {
oldtbody.remove();
}
var tbody = document.createElement('tbody');
tbody.id = "selectedElementsBody";
for (var i = 0; i < selectedIds.length; i++) {
var row = document.createElement('tr');
var cell = document.createElement('td');
cell.textContent = selectedProperties[i];
row.appendChild(cell);
tbody.appendChild(row);
table.appendChild(tbody);
}
});
viewer.load('../Content/3d/Maintenance.wexbim');
</script>
With the script under I would like to open another window passing the selectedIds array :
<script type="text/javascript">
$('#AddEventObjects').click(function () {
$.ajax({
url: "#(Url.Action("AddEventObjects", "Planning"))",
type: "GET",
dataType : "json",
data: { selectedObjects: selectedIds},
cache: false,
async: true,
traditional: true,
success: function (data) {
window.location = "/Planning/AddEventObjects";
},
error: function () {
alert("error");
}
});
});
</script>
Knowing that my controller Planning has an action called AddEventObjects:
public ActionResult AddEventObjects(string[] selectedObjects) {
ViewBag.Title = "Ajout intervention";
var addEventObjectsViewModel = new AddEventObjectsViewModel {
Title = "",
StartTime = "",
EndTime = "",
AllUsers = _context.Users.ToList(),
SelectedUsers = new List<ApplicationUser>(),
PostedUsers = new PostedUsers(),
ObjectsIds = selectedObjects.ToList(),
};
addEventObjectsViewModel.PostedUsers.SelectedIds = addEventObjectsViewModel.SelectedUsers.Select(x => x.Id).ToArray();
return View(addEventObjectsViewModel);
}
I would like it to open the following view that displays the selectedIds :
#model Maintenance.Web.Models.AddEventObjectsViewModel
using (Html.BeginForm("AddEvent", "Planning", FormMethod.Post, new { #class = "form-horizontal", role = "form" })) {
#Html.AntiForgeryToken()
<h4>Créer une nouvelle intervention</h4>
<div class="form-horizontal col-md-12">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-row col-md-12">
<div class="col-md-4">
<div class="form-group">
#Html.LabelFor(m => m.ObjectsIds, htmlAttributes: new { #class = "control-label" })
<table class="table table-striped" style="width:100%; margin-top:20px">
<thead>
<tr>
<th>Id</th>
</tr>
</thead>
#if (Model != null) {
foreach (var objectId in Model.ObjectsIds) {
<tr>
<td>#objectId</td>
</tr>
}
}
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<div class="col-md-10">
<input type="submit" class="btn btn-eiffage-red" value="Ajouter" />
</div>
</div>
</div>
}
With a more basic question : how can I pass an array from a javascript in a view to another view?
Thanks a lot for your help.

If you are passing an array of data, there are a few ways. The easiest of ways is to do the following. Join the array IDS into a comma separated string:
var idList = data.PostedUsers.SelectedIds.join(); //comma sep list
window.location = "/Planning/AddEventObjects?ids=" + idList;
This would work with what you have very simply; it will build a URL like:
/Planning/AddEventObjects?ids=1,2,3,4
In the backend, you have a "string ids" parameter, and split it by comma, and use the IDs however you need to.

Thanks Brian Mains!
I went with passing data in the url as you suggested.
I just used Json serialized data instead of coma separated values :
<a id="CreateEvent" class="btn" href="">Créer une intervention</a>
...
var createLink = "/Planning/AddEventObjects?ids=" + JSON.stringify(model.ids);
$('#CreateEvent').attr("href", createLink);
And then in my controller :
public ActionResult AddEventObjects(string ids) {
if (ids == null) {
return HttpNotFound();
}
string[] objectIds = JsonConvert.DeserializeObject<string[]>(ids);
}

Related

Can't obtain values from controls through javascript in razor page

I have a razor page where evrything is displaying fine, but I need to be able to read the values inside a few controllers to pass them as parameters in an call to prefilter some data:
#page
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#model MyApp.Pages.IndexModel
#{
ViewData["Title"] = "MyApp";
}
<div class="col-12 border p-3 mt-3">
<h3>Filters</h3>
<div class="col-12">
<select id="portMultiselect" name="lsPorts" asp-items="#Model.Ports" multiple></select>
<input id="searchString" type="text" name="searchString">
</div>
</div>
#* A "REFRESHABLE" TABLE GOES HERE...*#
#section scripts{
#* REFRESH SCRIPT *#
<script type="text/javascript">
$(function () {
setInterval(loadTable, 60000);
loadTable();
});
function loadTable() {
var select1 = document.getElementById("portMultiselect");
var selectedPorts = [];
for (var i = 0; i < select1.options.length; i++) {
if (select1.options[i].selected) selectedPorts.push(select1.options[i].value);
}
var searchString = document.getElementById('searchString').value;
if (searchString != "" || selectedPorts.length != 0) {
debugger;
}
fetch('/Index?handler=IndexPartial', {
data: {
searchString: searchString,
selectedPorts: selectedPorts
}
})
.then((response) => {
return response.text();
})
.then((result) => {
document.getElementById('refreshable').innerHTML = result;
});
}
</script>
}
As you can see, I'm trying to capture the selected values in my multiselect and in a text input to pass as parameters in the refresh script.
I'm correctly arriving to the expected endpoint, but Im never getting any values (It's always empty and zero) I even added a debugger in the Javascript code that I'm never hitting.
Why can't I read those values?
EDIT:
I have seen other ways of dealing with these, such as databindings, but as mentioned here, the only way to avoid page reload is javascript and AJAX, so I still need to get these values from the javascript.
At the end, I found a solution to my predicament as follows:
I changed the way I render the selectPicker, following the examples shown in this page:
#page
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#model MyApp.Pages.IndexModel
#{
ViewData["Title"] = "MyApp";
}
<div class="col-12 border p-3 mt-3">
<h3>Filtros</h3>
<div class="row">
<div class="col-6">
<p>Puertos</p>
#Html.DropDownListFor(x =>
x.selectPort,
(IEnumerable<SelectListItem>)ViewData["MyPorts"],
new
{
#id = "portMultiselect",
#class = "form-control selectpicker",
#Value = #Model.Ports,
data_live_search = "true",
multiple = "multiple"
})
</div>
<div class="col-6">
<p>Nombre de variable</p>
<input id="searchString" type="text" name="searchString">
</div>
</div>
</div>
This comes with certain changes to the model you're working with, you can follow instructions to bind data as T.Trassoudaine commmented, here
for this to work you need to add the specified references in your _Layout (for the bootstrap-select), you can check all the things you need to add here
And finally, you will need to work with AJAX in javascript to pass the parameters back:
<script type="text/javascript">
$(function () {
setInterval(loadTable, 1000);
loadTable();
});
function loadTable() {
var select1 = document.getElementById("portMultiselect");
var selectedPorts = [];
for (var i = 0; i < select1.options.length; i++) {
if (select1.options[i].selected) selectedPorts.push(select1.options[i].value);
}
var searchString = document.getElementById('searchString').value.toUpperCase();
var searchPorts = "";
if (selectedPorts.length != 0) {
searchPorts = selectedPorts.join(",");
}
$.ajax({
url: '/?handler=IndexPartial',
data: {
searchString: searchString,
searchPorts: searchPorts
},
success: function (data) {
document.getElementById('refreshable').innerHTML = data;
}
})
}
</script>

C# MVC5 BulkData Insert doesn't work on partial view

I have a problem with inserting bulk data from partial view in MVC5. It works completely fine when its not a partial view. I am using this example: http://www.dotnetawesome.com/2014/08/how-to-insert-multiple-record-to-database-at-a-time-aspnet-mvc4.html
This is the original code from the controller:
public ActionResult BulkData()
{
// This is only for show by default one row for insert data to the database
List<ContactInfo> ci = new List<ContactInfo> {new ContactInfo{ ID = 0, ContactName = "", ContactNo=""} };
return View(ci);
}
I change it to(because I want to use the functionality in bootrap modal popup):
public ActionResult BulkData()
{
// This is only for show by default one row for insert data to the database
List<ContactInfo> ci = new List<ContactInfo> {new ContactInfo{ ID = 0, ContactName = "", ContactNo=""} };
return PartialView(ci);
}
After changes it doesn't work. I can't understand why. I also added all scripts from layout to partial view, but it also didn't help. This is the code from the view:
#model List<MVCBulkInsert.ContactInfo>
#{
ViewBag.Title = "Insert Bulk Data";
}
<style>
th {
text-align:left;
}
td {
padding:5px;
}
</style>
<div style="width:700px; padding:5px; background-color:white;">
#using (Html.BeginForm("BulkData","Save", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
if (ViewBag.Message != null)
{
<div style="border:solid 1px green">
#ViewBag.Message
</div>
}
<div>Add New</div>
<table id="dataTable" border="0" cellpadding="0" cellspacing="0">
<tr>
<th>Contact Name</th>
<th>Contact No</th>
<th></th>
</tr>
#if (Model != null && Model.Count > 0)
{
int j = 0;
foreach (var i in Model)
{
<tr style="border:1px solid black">
<td>#Html.TextBoxFor(a=>a[j].ContactName)</td>
<td>#Html.TextBoxFor(a=>a[j].ContactNo)</td>
<td>
#if (j > 0)
{
Remove
}
</td>
</tr>
j++;
}
}
</table>
<input type="submit" value="Save Bulk Data" />
}
</div>
#* Here I will add Jquery Code for validation / dynamically add new rows / Remove rows etc *#
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
<script language="javascript">
$(document).ready(function () {
//1. Add new row
$("#addNew").click(function (e) {
e.preventDefault();
var $tableBody = $("#dataTable");
var $trLast = $tableBody.find("tr:last");
var $trNew = $trLast.clone();
var suffix = $trNew.find(':input:first').attr('name').match(/\d+/);
$trNew.find("td:last").html('Remove');
$.each($trNew.find(':input'), function (i, val) {
// Replaced Name
var oldN = $(this).attr('name');
var newN = oldN.replace('[' + suffix + ']', '[' + (parseInt(suffix) + 1) + ']');
$(this).attr('name', newN);
//Replaced value
var type = $(this).attr('type');
if (type.toLowerCase() == "text") {
$(this).attr('value', '');
}
// If you have another Type then replace with default value
$(this).removeClass("input-validation-error");
});
$trLast.after($trNew);
// Re-assign Validation
var form = $("form")
.removeData("validator")
.removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(form);
});
// 2. Remove
$('a.remove').live("click", function (e) {
e.preventDefault();
$(this).parent().parent().remove();
});
});
</script>
}
Where can be the problem?
The problem was that partial views don't recognize scripts sections.

mvc post using javascript and display result without complete postback [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a mvc page where the user select values from 3 different dropdown lists and then enter a number in a textfield, based on those selections and the entered number I want to do some calculations and then display the result to the user without the whole page being posted again. I understand that this can be solved using javascript, but I'm not to good in writing javasript so I could use some help here on what I need to add in order to get this to work. When I click the sumbmit button the page reloads and it does not enter the "DoCalculation" method... What am I doing wrong here?
<form name="myForm">
<div class="form-section col-md-12">
<h3 class="title_contanier">1: </h3>
#Html.DropDownList("PrintType", ViewData["printType"] as List<SelectListItem>, new { #class = "form-control" })
</div>
<div class="form-section col-md-12">
<h3 class="title_contanier">2: </h3>
#Html.DropDownList("Papper", new SelectList(string.Empty, "Value", "Text"), "-", new { #class = "form-control" })
</div>
<div class="form-section col-md-12">
<h3 class="title_contanier">3: </h3>
#Html.DropDownList("PapperType", new SelectList(string.Empty, "Value", "Text"), "-", new { #class = "form-control" })
</div>
<h3 class="title_contanier">Antal: </h3>
<input type="text" placeholder="Skriv in antal" name="Qty" id="Qty">
<button type="button" id="submitBtn">skicka</button>
<span id="resultMessage"></span>
</form>
<script type="text/javascript">
jQuery(document).ready(function ($) {
$('#PrintType').change(function ()
{
$.getJSON('/Home/GetPapperByTypeId/?typeId=' + $('#PrintType').val(), function (data)
{
var items = '<option>Välj papper..</option>';
$.each(data, function (i, printtype)
{
items += "<option value='" + printtype.Value + "'>" + printtype.Text + "</option>";
});
$('#Papper').html(items);
});
});
$('#Papper').change(function ()
{
$.getJSON('/Home/GetOptions/?ppai=' + $('#Papper').val() + '&tid=' + $('#PrintType').val(), function (data)
{
var items = '<option>Välj option</option>';
$.each(data, function (i, pappertype)
{
items += "<option value='" + pappertype.Value + "'>" + pappertype.Text + "</option>";
});
$('#PapperType').html(items);
});
});
});
</script>
<script type="text/javascript">
jQuery(document)
.ready(function($) {
$('#submitBtn').on("click", function () {
var papper = $('#Papper :selected').val();
var papperType = $('#PapperType :selected').val();
var qty = $('#Qty').val();
var request = {
"method": "POST",
"url": "#Url.Content("/Home/DoCalculation/")",
"data": { "Order": { "Papper": papper, "PapperType": papperType, "Qty": qty } }
}
$.ajax(request)
.success(function(response) {
if (response.success == true) {
$('#resultMessage').text(response.result);
}
});
});
})
</script>
public ActionResult Index()
{
ViewData["printType"] = Repository.GetAllPrintingTypes();
return View();
}
public class PapperOrder
{
public string Papper { get; set; }
public string PapperType { get; set; }
public int Qty { get; set; }
}
public ActionResult DoCalculation(PapperOrder order)
{
var papper = order.Papper;
var papperType = order.PapperType;
var qty = order.Qty;
var model = new CalculatedPrice { Totalsum = qty };
return Json(model, JsonRequestBehavior.AllowGet);
}
You can do it by simple JQuery AJAX request .
var papper = $('#Papper :selected').val();
var papperType = $('#PapperType :selected').val();
var qty = $('#Qty').val();
var request = {
"method" : "POST",
"url" : "#Url.Content("ControllerName/DoCalculation")",
"data" : { "Order":{ "Papper" : papper,"PapperType":papperType,"Qty" : qty}},
}
$.ajax(request)
.success(function(response){
//do whatever you want to do with data
})
You can also make things easier by creating a model on your server side, call it PapperOrder
public class PapperOrder {
public string Papper {get;set;}
public string PapperType {get;set;}
public int Qty {get;set;}
}
Now update your controller as follows
public ActionResult DoCalculation(PapperOrder order){
var Papper = order.Papper;
var PapperType = order.PapperType;
var Qty = order.Qty;
// do further calculations here
}
As you asked how to display the calculated result in success method than follow the following points.
You must return Json from your controller action "DoCalculation" like below
public ActionResult DoCalculation(PapperOrder order){
//after calculation
return Json(new {success = true, result = "12 (or whatever your calculated value is)"});
}
Now inside your AJAX success method you can do anything, I suppose that you want to display the result inside a div so create that div
<div id="result"></div>
and inside your success method
success:function(response){
if(response.success == true){
$('#result').text(response.result);
}
}
First of all instead of Html.BeginForm use Ajax.BeginForm
#using (Ajax.BeginForm("DoCalculation", "YourControllerName", null new AjaxOptions { OnSuccess = "yourHandleResponseFunction"}, new { id = "myForm", name = "form_search" }))
{
<div class="form-section col-md-12">
<h3 class="title_contanier">1: </h3>
#Html.DropDownList("PrintType", ViewData["printType"] as List<SelectListItem>, new { #class = "form-control" })
</div>
<div class="form-section col-md-12">
<h3 class="title_contanier">2: </h3>
#Html.DropDownList("Papper", new SelectList(string.Empty, "Value", "Text"), "-", new { #class = "form-control" })
</div>
<div class="form-section col-md-12">
<h3 class="title_contanier">3: </h3>
#Html.DropDownList("PapperType", new SelectList(string.Empty, "Value", "Text"), "-", new { #class = "form-control" })
</div>
<h3 class="title_contanier">Antal: </h3>
<input type="text" placeholder="Skriv in antal" name="Qty" id="Qty">
<button type="submit" class="btn_submit_quick_search btn_submit_search pull-right" name="btn_submit_section_search_id_mls">calculate</button>
<span id="resultMessage"></span>
}
<script>
function yourHandleResponseFunction(data)
{
//process your data here
$('#resultMessage').html(data.Totalsum);
}
</script>
Of course response data structure has to match to the one that you sent from server:
public ActionResult DoCalculation(PapperOrder order)
{
var papper = order.Papper;
var papperType = order.PapperType;
var qty = order.Qty;
var model = new CalculatedPrice { Totalsum = qty };
return Json(model, JsonRequestBehavior.AllowGet);
}

Dependent multiselect dropdown using chosen and select2 plugins

This is the code I have written in View :
<div class="col-lg-12" style="margin-bottom: 20px;">
<div class="form-group">
<label class="col-sm-3 control-label" style=" margin-top: 14px; ">Domains <font size="3" color="red">*</font></label>
<br />
<div class="col-sm-4" style="width:50%;">
#Html.ListBoxFor(m => m.SelectedDomains, Model.AllDomains,
new { #class = "chosen", multiple = "multiple", id = "drpDomains", style = "width: 350px;",onchange="FillDomain();" })
</div>
</div>
</div>
<div class="col-lg-12" style="margin-bottom: 20px;">
<div class="form-group">
<label class="col-sm-3 control-label" style=" margin-top: 14px; ">Domains new categories <font size="3" color="red">*</font></label>
<br />
<div class="col-sm-4" style="width:50%;">
#Html.ListBoxFor(m => m.SelectedDomainCategories, Enumerable.Empty<SelectListItem>(),
new { #class = "select2", multiple = "multiple", id = "multidomaincategory", style = "width: 350px;" })
</div>
</div>
</div>
<link href="~/Scripts/MultiSelect/chosen.css" rel="stylesheet" />
For Domains, I have used Chosen plugin, and for categories, i have used select2 plugin
<script type="text/javascript">
$(".chosen-deselect").chosen({ allow_single_deselect: true });
$(".chosen").chosen().change();
$(".chosen").trigger('liszt:updated');
</script>
<script>
function FillDomain() {
$("#drpDomains option[value='']").removeAttr("selected");
var selectArr = [];
$('#drpDomains').each(function () {
selectArr.push($(this).val());
});
var a = JSON.stringify(selectArr);
var reference = this;
$.ajax({
url: #Url.Content("~/MyTemplate2/FillIndustry1"), //FillIndustry1 is a method in Controller
type: "POST",
dataType: "JSON",
data: { Domain: a },
success: function (DomainCategories) {
$("#multidomaincategory").html("");
$("#multidomaincategory").removeAttr("selected");
var s = JSON.stringify(DomainCategories);
var t = JSON.parse(s);
for (var key in t) {
$("#multidomaincategory").append("<option value=" + t[key]["Value"] + ">" + t[key]["Text"] + "</option>");
}
},
error: function (data) {
alert("failure error" + data);
var t = window.JSON.parse(data.d);
alert("failueee" + t);
}
});
//I'm trying to remove all the selected items from dependent dropdown (#multidomaincategory) when all items from Domains(#drpDomains) are cleared
if ($("#drpDomains").val() == null || $("#drpDomains").val() == "") {
$("#multidomaincategory").removeAttr("selected");
$("#multidomaincategory").css('display', 'none');
}
}
</script>
Controller :
[HttpPost]
public ActionResult FillIndustry1(string Domain)
{
JArray jsonMembersArr = (JArray)JsonConvert.DeserializeObject(Domain);//convert SymptomString from json string to array
ProfessionalTrans objprofessionaltrans = new ProfessionalTrans();
string listdomains = "";
foreach (var a in jsonMembersArr)
{
listdomains = string.Join(",", a);
}
var DomainCategories = objprofessionaltrans.GetDepCategories(listdomains);
return Json(DomainCategories.ToList());
}
Data Access Layer(Transaction):
public IEnumerable<SelectListItem> GetDepCategories(string domains)
{
//GetDepCategories method - To get categories based on Domains
PTS_CommonEntities objentity = new PTS_CommonEntities();
List<SelectListItem> allskills = new List<SelectListItem>();
List<GetCatListbasedDomain> catnames = objentity.usp_GetCatListBasedOnDomains(domains).ToList();
foreach (var it in catnames)
{
allskills.Add(new SelectListItem { Value = it.CategoryID.ToString(), Text = it.CategoryName });
}
return allskills.AsEnumerable();
}
When I am clearing(closing) the selected items in Domains, the respective Categories are cleared from list, but not in the text box
Image Before Clearing
Image After Clearing the Domains
As you can see, the list is being cleared, but the selected items are still being shown in the UI.
Can someone please find out why the items are being displayed even after clearing them???
Because you are trying to clear the wrong element. #multidomaincategory is the select2 list that holds all of the values, there is a dynamic span class that gets rendered to the page right after this element, look at the html that select2 produces in your browser. Try:
$('#multidomaincategory').next().find('li').html('');
They are cleared from the list because $("#multidomaincategory").html(""); clears the html of the list of categories, not the rendered text elements in the text box.
Although a better way: $('#multidomaincategory').select2('data', null)

Similar MVC actions called by javascript, AntiForgery works on one, not the other

I have a javascript function I use to do an Ajax call to my controller function. The javascript is generic enough I can use it for multiple controls. I have two areas that use the script. One works, one doesn't. I believe it's the footprint of the MVC controller that is being called.
The javascript looks like this:
$(Document).on("click",".delete-link",function (event) {
var deleteLink = $(this);
deleteLink.hide();
var confirmButton = deleteLink.siblings(".delete-confirm");
confirmButton.show();
var cancelDelete = function () {
removeEvents();
showDeleteLink();
};
var deleteItem = function () {
removeEvents();
confirmButton.hide();
var url = '/' + confirmButton.attr('data-delete-controller') + '/' + confirmButton.attr('data-delete-action') + '/' + confirmButton.attr('data-delete-id');
$.post(
url,
AddAntiForgeryToken({ id: confirmButton.attr('data-delete-id') }))
.done(function () {
var parentRow = deleteLink.closest(".removable-row");//"tr:first, li:first");
parentRow.fadeOut('fast', function () {
parentRow.remove();
});
}).fail(function (data) {
alert("error");
});
return false;
};
var removeEvents = function () {
confirmButton.off("click", deleteItem);
$(document).on("click", cancelDelete);
$(document).off("keypress", onKeyPress);
};
var showDeleteLink = function () {
confirmButton.hide();
deleteLink.show();
};
var onKeyPress = function (e) {
//Cancel if escape key pressed
if (e.which == 27) {
cancelDelete();
}
};
confirmButton.on("click", deleteItem);
$(document).on("click", cancelDelete);
$(document).on("keypress", onKeyPress);
return false;
});
AddAntiForgeryToken = function (data) {
data.__RequestVerificationToken = $('input[name=__RequestVerificationToken]').val();
return data;
};
So the MVC view and controller action that work are defined like this:
<div class="row">
#Html.HiddenFor(model => model.CustomFieldOptionId)
#Html.HiddenFor(model => model.CustomFieldId)
#Html.HiddenFor(model => model.SortOrder, new { #class = "SortOrder" })
#Html.HiddenFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.OptionLabel, "", new { #class = "text-danger" })
<div class="col-md-2">
#Html.LabelFor(model => model.OptionLabel, htmlAttributes: new { #class = "control-label" })
</div>
<div class="col-md-7">
#Html.EditorFor(model => model.OptionLabel, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="col-md-3">
<input type="button" value="Delete" class="btn delete-link" />
<div class="btn btn-primary delete-confirm" style="display: none"
data-delete-id="#Model.CustomFieldOptionId"
data-delete-controller="customforms"
data-delete-action="_OptionEditorRowDelete">Confirm Delete</div>
</div>
</div>
Controller:
[HttpPost, ActionName("_OptionEditorRowDelete")]
[ValidateAntiForgeryToken]
public ActionResult _OptionEditorRowDelete(int id)
{
var custFieldOption = db.CustomFieldOptions.Find(id);
if (custFieldOption == null) return null;
custFieldOption.IsActive = false;
db.Entry(custFieldOption).State = EntityState.Modified;
db.SaveChanges();
return null;
}
The one that is not working is defined like this:
#foreach (var item in Model) {
<tr>
<td>
#Html.HiddenFor(modelItem => item.ProfileId)
#Html.DisplayFor(modelItem => item.ProfileIdentifierValue)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsPrimary)
</td>
<td>
#Html.ActionLink("Edit", "profileemailsedit", new { id = item.ProfileIdentifierId }) |
#Html.ActionLink("Delete", "_ProfileEmailsDelete", new { id = item.ProfileIdentifierId }, new { #class = "delete-link" })
<a class="delete-link" href="#Url.Action("_ProfileEmailsDelete", new { id = item.ProfileIdentifierId })">Delete</a>
<input type="button" value="Delete" class="btn delete-link" />
<div class="btn btn-primary delete-confirm" style="display: none"
data-delete-id="#item.ProfileIdentifierId"
data-delete-controller="profiles"
data-delete-action="_ProfileEmailsDelete">Confirm Delete</div>
</td>
</tr>
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _ProfileEmailsDelete(int id)
{
var profIdentifier = db.ProfileIdentifier.Find(id);
if (profIdentifier == null) return null;
profIdentifier.IsActive = false;
db.Entry(profIdentifier).State = EntityState.Modified;
db.SaveChanges();
return null;
}
As you can see the controllers are very similar. However, the _ProfileEmailsDelete get's this javascript error:
POST http://localhost:63595/profiles/_ProfileEmailsDelete/168 500 (Internal Server Error)
Part of the server 500 error is:
[HttpAntiForgeryException]: The required anti-forgery form field
"__RequestVerificationToken" is not present. at
System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens(HttpContextBase
httpContext, IIdentity identity, AntiForgeryToken sessionToken,
AntiForgeryToken fieldToken) at
System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase
httpContext) at System.Web.Helpers.AntiForgery.Validate()
I'm not sure why the AntiForgery works with one and not the other.
The 500 error is your ajax response from the server, not your javascript. The actual problem is not jumping out at me, but most often when I have seen this type of behavior it ends up being something in the view rendering that causes it. For example trying to reference the values of a collection that is null in the view would act this way. Using the traffic analyzer features of the browser developer tools can sometimes help shed light on the real problem.
The first example was in a partial view. The parent view had this:
#Html.AntiForgeryToken()
I added that to the View for the second example, and then the javascript could properly get the token to pass back with the $.post command.

Categories

Resources