MVC / AJAX send data to controller and load response in same view - javascript

I have a page with three form fields (2 textbox, 1 dropdown), a submit button and a 'refresh' link. I want to be able to click the link and pass two form textbox values to a controller action, and get a list of values to populate the dropdown box. I do not want to submit the form at this stage.
At the moment, I have managed to call the controller action from the link click, but I cannot pass the two form field values in for some reason. Also, the return JSON just takes me to a new page instead of populating my dropdown list. Any pointers would be great as I am new to javascript and MVC. My code is below;
Controller
public ActionResult Find(AddressFormViewModel model)
{
...
var temp = new List<OptionModel>();
temp.Add(new OptionModel {Id = item.Id, Value = item.desc});
return Json(temp, JsonRequestBehavior.AllowGet);
}
HTML
#Html.TextBoxFor(x => Model.HouseNameInput, new { id = "HouseNameInput" })
#Html.TextBoxFor(x => Model.PostCodeInput, new { id = "PostCodeInput" })
#Html.ActionLink("Find","Find", "Address", new { houseInput = Model.HouseNameInput, postcodeInput = Model.PostCodeInput }, new { htmlAttributes = new { #class = "Find" } })
#Html.DropDownListFor(x => Model.AddressOption, Enumerable.Empty<System.Web.Mvc.SelectListItem>(), "-- Loading Values --", new {id = "AddressOptions"})
And lastly, my Javascript method which is retrieving the data from the controller action but not populating the dropdown list (it displays the results in a new page). It is also not successfully sending the form values to the controller action.
$(function () {
$('.Find').click(function (evt) {
$.ajax({
type: 'POST',
url: '#Url.Action("Find","AddressFormSurface")',
cache: false,
async: true,
dataType: "json",
contentType: "application/json; charset=utf-8",
data: {
houseNameInput: $("#HouseNameInput").value,
postCodeInput: $("#PostCodeInput").value
},
success: function (data) {
if (data.exists) {
var ddl = $('#AddressOptions');
ddl.empty();
data.each(function () {
$(document.createElement('option'))
.attr('value', this.Id)
.text(this.Value)
.appendTo(ddl);
});
}
},
error: function (req) {
}
});
// we make sure to cancel the default action of the link
// because we will be sending an AJAX call
return false;
});
});

You have a number of errors in your script which will cause it to fail.
You specify contentType: "application/json; charset=utf-8", but do
not stringify the data (the option should be removed)
You need to use .val() (not .value) to get the values of the
inputs
The data you receiving does not contain a property named exists so
the if block where you append the options will never be hit
In addition it is unnecessary to generate your link using #Html.ActionLink() (your adding route values based on the initial values of the model). Instead just create it manually
Find
and change the script to
var ddl = $('#AddressOptions'); // cache it
$('#find').click(function () { // change selector
$.ajax({
type: 'GET', // its a GET, not a POST
url: '#Url.Action("Find","AddressFormSurface")', // see side note below
cache: false,
async: true,
dataType: "json",
data: {
houseNameInput: $("#HouseNameInput").val(),
postCodeInput: $("#PostCodeInput").val()
},
success: function (data) {
if (!data) {
// oops
return;
}
ddl.empty();
$.each(data, function(index, item) {
$(document.createElement('option'))
.attr('value', item.Id)
.text(item.Value)
.appendTo(ddl);
// or ddl.append($('<option></option>').text(item.Value).val(item.Id));
});
},
error: function (req) {
....
}
}
});
Side note: Also check the name of the controller. Your Html.ActionLink() suggests its AddressController but your script is calling AddressFormSurfaceController

Related

Ajax serialized form with values not getting passed correctly to my controller's action

I set up a javascript alert to confirm that my form.serialize is working correctly, and it is. The issue is that my controller action is not associating any of the data from the form to the model.
Javascript alert with the passed form values
The first value in this alert is StartDate with a value of 02/25/2020, but in the screenshot of the controller below it is not binded to the dailyReport object's StartDate value.
Screenshot of the controller and passed object
Ajax
$(function () {
$('#submit').on('click', function (evt) {
alert($('#reportForm').serialize());
evt.preventDefault();
//Ajax form post
$.ajax({
type: 'POST',
data: $('#reportForm').serialize(),
url: '#Url.Action("Daily","Reports")',
contentType: 'application/json; charset=utf-8',
success: function (data) {
if (data.success) {
alert("Data Success");
} else {
console.log(data);
//Toggle the error modal and display error messages
$('#errorsModal').modal('toggle');
//Add <br> tags when there is a linebreak in the string. This will add the line breaks into the HTML.
$('#errorsModal .modal-body p').html(data.message.replace(/(?:\r\n|\r|\n)/g, '<br>'));
}
}
});
});
});
Controller
[HttpPost]
public IActionResult Daily(Daily dailyReport)
{
var dr = new ReportDaily();
var rc = new ReportDailyCriteria();
dr.Preview(rc, IntPtr.Zero, out Notification notification);
if (notification.HasErrors)
{
return Json(new
{
success = false,
message = notification.GetConcatenatedErrorMessage(Environment.NewLine + Environment.NewLine)
});
}
return Json(new { success = true });
}
Switching from using 'application/json; charset=utf-8' to 'application/x-www-form-urlencoded; charset=utf-8' fixed the issue.

Remove autocomplete selected item from the list in asp.net and Ajax

I am in the biggest problem
**PLEASE DONT REPORT MY QUESTION DUPLICATE BECAUSE I DID NOT GET ANSWER FOR ASP.NET IN GOOGLE.
I am using jquery Autocomplete textbox in asp.net using web service.
my code
$('input.txtE').autocomplete({
source: function (request, response) {
$.ajax({
url: "WebServices.asmx/GetNames",
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: "{ 'txtInput' : '" + request.term + "','userName':'" + userName + "'}",
dataFilter: function (data) { return data; },
success: function (data) {
mydata = data.d;
response($.map(data.d, function (item) {
return {
label: item.split('/')[0],
val: item.split('/')[1]
}
}))
},
error: function (result) {
alert("Error");
}
});
},
multiselect: false,
minLength: 1,
delay: 0,
select: function (e, ui) {
$(hfId).val(ui.item.val);
}
});
<input type="hidden" id="hfId"/>
And my API return data in array format
 ["Abhishek/128", "Abyss/71", "athansiah/53", "blvsian/138", "DesmondH/91", "destined2hold/62", "dnbdesigns/94", "Dvus_lotus/85", "gserranof/47", "Illusions/89", "isaacwu111/111", "js/39"]
What I need if a user selected remove him from the autocomplete list so we can't select him again.
Please help me to short out it.
Preparation
In first, you need to store setected values. It is possible by using a global variable, hidden input control or arbitrary data associated with your control. In the following example I create an array that is associated with autocomplete control and then store selected values to the array:
$('#my-control').autocomplete({
create: function( e, ui ) {
// initialize array
$(this).data('selected', []);
},
select: function( e, ui ) {
// store unique selected values
var selected = $(this).data('selected');
if(!~selected.indexOf(ui.item.value)) {
selected.push(ui.item.value);
}
},
// another options here
});
Now it is possible to consider the selected values for list filtering.
Server-side solution
The best way is to filter the list on API server side, because it reduces transferred data amount. Just send the stored values through an AJAX request, using data option:
var $control = $('#my-control');
$control.autocomplete({
source: function (request, response) {
$.ajax({
// some AJAX options
data: {
term: request.term,
selected: $control.data('selected') // send stored values
}
});
},
// some autocomplete options here
});
Then you have to implement server-side filtration in accordance to selected query string parameter.
For example
public class AutocompleteSourceController : ApiController
{
[HttpGet]
public JsonResult<IEnumerable<MyClass>> GetItems(
[FromUri]string term,
[FromUri]int[] selected)
{
// Load data
// Fliter by term substring
// Exclude selected items
// Return the result
}
}
Client-side solution
Another way is to filter responded list on client side, using success AJAX callback. In my example I will use fake online REST API server. The server ignores the term field of query string, so I also have to implement it on client-side.
$control = $('#my-input');
$control.autocomplete({
create: function(e, ui) {
$(this).data('selected', []);
},
source: function(request, response) {
$.ajax({
url: "https://jsonplaceholder.typicode.com/users",
type: "GET",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(data) {
var items = data
// filter by term
.filter(function(user) {
return ~user.name.toLowerCase().indexOf(request.term.toLowerCase());
})
// exclude stored selected values
.filter(function(user) {
return !~$control.data('selected').indexOf(user.id);
})
// cast to an objects with label and value properties
.map(function(user) {
return {
label: user.name,
value: user.id
}
});
response(items);
},
error: function(result) {
alert("Error");
}
});
},
multiselect: false,
minLength: 1,
delay: 0,
select: function(e, ui) {
e.preventDefault();
$ctrl = $(this);
var selected = $control.data('selected');
if (!~selected.indexOf(ui.item.value)) {
// store selected value
selected.push(ui.item.value);
// set label instead of value
$ctrl.val(ui.item.label);
}
},
});
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
<input id="my-input" type="text">
Type L to the input control. The first item will be Leanne Graham, select it. Then clean the input field and type L again, there will no Leanne Graham in the dropdown menu. Select Ervin Howell, then clean the input field and type L again. There will be neither Leanne Graham nor Ervin Howell in the dropdown menu.
If you want to consider only current selected value, you could store only latest value instead of an array and modify the success callback and the select event handler.
Try to remove selected value from array using jQuery.
x = jQuery.grep(x, function(val) {return val != Item;});

Json.stringify allows HTML elements

I am trying to post values from MVC view to controller.
Request validation feature is enabled for application.
But when i tried to pass values with HTML tags to controller, I am not getting any exception.
here is my ajax post:
Group.Name = model.Name();
Group.Id = model.ID();
$.ajax({
type: 'POST',
url: /IndexController/SaveGroup',
async: true,
cache: false,
dataType: "json",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ Group: group }),
success: function (data /*, textStatus, request*/) {
try {
}
catch (error) {
showExceptionWindow('Jquery Error:' + error);
}
},
error: function (request /*, status, error*/) {
handleException(request.responseText);
}
});
}
Controller Code:
[HttpPost]
public async Task<ActionResult> SaveGroup(Group group)
{
when i tried to insert html tags,the values are passing to controller action method and getting saved.
When request validation feature is enabled,html elements should not be passed to controller.
How to make sure it is getting blocked at controller.
MVC validation dosent work since you've changed the submit button to prevent default mvc use the jquery plugin Validate.js just go through i,this code should work
var form = $("#YourFormID");
form.validate();
form.submit(function (e) {
e.preventDefault();
if (form.valid()) {
//Your ajax call
}
})
Seems you have a typo as there group does not seem to be a valid object it is undefined:
data: JSON.stringify({ group: Group }), // <-----It should have to be this Group here
And at your backend:
[HttpPost]
public async Task<ActionResult> SaveGroup(Group group) // group is {}
{
Or as Group is already an object then you can stringify it directly:
data: JSON.stringify(Group), // <-----It should have to be this Group here
[HttpPost]
public async Task<ActionResult> SaveGroup(Group Group) // group is {}
{
Why not using an HTML parser to detect HTML elements injection? This can be a clean JS solution
var containsHTML = /<[a-z][\s\S]*>/i.test("<p>HTML text to be parsed</p>")
if(containsHTML==true){
//There are HTML tags inside the string
}
else{
//You're good to go
}

Retrieving event and htmlInput element from a foreach using javascript or jquery

I managed to retrieve a dynamic element ID from inside a foreach and send it to a controller this way:
#using (Html.BeginForm("DeleteConfirmed", "Gifts", FormMethod.Post, new { #class = "form-content", id = "formDiv" }))
{
foreach (var item in Model.productList)
{
<input type="button" value="Delete" onclick="DeleteButtonClicked(this)" data-assigned-id="#item.ID" />
}
}
and here's the relevant script, pointing to the controller's ActionResult method in charge for item deletion:
function DeleteButtonClicked(elem) {
var itemID = $(elem).data('assigned-id');
if (confirm('sure?')) {
window.location.href = "/Gifts/DeleteConfirmed/" + itemID;
}}
Now, this works just fine, as itemID is correctly retrieved.
As I would like to add a #Html.AntiForgeryToken() to the form, the idea is to change the MVC controller's Actionmethod into a JsonResult adding a little Ajax to the script, allowing me to pass both itemID and token.
Something like:
function DeleteButtonClicked(elem) {
event.preventDefault();
var form = $('#formDiv');
var token = $('input[name="__RequestVerificationToken"]', form).val();
var itemID = $(elem).data('assigned-id');
if (confirm('sure?')) {
$.ajax({
type: 'POST',
datatype: 'json',
url: '#Url.Action("DeleteConfirmed", "Gifts")',
data: {
__RequestVerificationToken: token,
id: itemID
},
cache: false,
success: function (data) { window.location.href = "/Gifts/UserProfile?userID=" + data; },
error: function (data) { window.location.href = '#Url.Action("InternalServerError", "Error")'; }
});
}
dynamic }Some
but I have no idea on how to add the 'event' to the element (this => elem) in <input type="button" value="Delete" onclick="DeleteButtonClicked(this)" data-assigned-id="#item.ID" /> that I am using to identify the item inside the foreach loop, in order to pass it to the script.
Above script obviously fails as there's no 'event' (provided this would end to be the only mistake, which I'm not sure at all).
Some help is needed. Thanks in advance for your time and consideration.
What you want to do is use jQuery to create an event handler:
$('input[type="button"]').on('click', function(event) {
event.preventDefault();
var form = $('#formDiv');
var token = $('input[name="__RequestVerificationToken"]', form).val();
var itemID = $(this).data('assigned-id');
if (confirm('sure?')) {
$.ajax({
type: 'POST',
datatype: 'json',
url: '#Url.Action("DeleteConfirmed", "Gifts")',
data: {
__RequestVerificationToken: token,
id: itemID
},
cache: false,
success: function (data) { window.location.href = "/Gifts/UserProfile?userID=" + data; },
error: function (data) { window.location.href = '#Url.Action("InternalServerError", "Error")'; }
});
}
});
Just make sure you render this script after your buttons are rendered. Preferably using the $(document).onReady technique.
Try the 'on' event handler attachment (http://api.jquery.com/on/). The outer function is shorthand for DOM ready.
$(function() {
$('.some-container').on('click', '.delete-btn', DeleteButtonClicked);
})

How to retrieve the elements of a dropdownlist in jquery and send it with ajax to an MVC Controller in ASP.Net?

I have a select item as follows:
<select id="id_category">
<option> </option>
</select>
In run time there is a tree view used to fill up the select menu as follows:
<script>
$(document).ready(function () {
$('#data').jstree({
"plugins": ["checkbox"]
});
$("#data").on("changed.jstree", function (e, data) {
if (data.selected.length) {
$("#id_category").empty();
$(data.selected).each(function (idx) {
var node = data.instance.get_node(data.selected[idx]);
var s = document.getElementById('id_category');
s.options[s.options.length] = new Option(node.text, '1');
});
}
else
$("#id_category").empty();
});
});
</script>
and the html for the tree is not important now as it works well.
Now, I want when a user click on a button with HTML as follows:
<input id="btn3" type="button" value="Test 3" />
an ajax will be run to send all the items in the select to a controller in MVC as follows:
$("#btn3").click(function () {
$.ajax({
url: "/Products/Test03",
datatype: "text",
data: $.map($('#id_category')[0].options, function( elem ) { return (elem.value || elem.text); }),
type: "POST",
success: function (data) {
$('#testarea').html(data);
},
error: function () {
$("#testarea").html("ERROR");
}
});
});
and the controller:
[HttpPost]
public string Test03(Object str1)
{
// call with two parameters and return them back
this.myRetrievedData = str1;
return str1.ToString();
}
The above did not work with me, when I click on Test3 button nothing happened.
I am not sure how to pass the retrieved items to the function in the controller. Could anyone tell me how to do that?
The below logic must work for you. Many thanks to Mr.Stephen Muecke for assistance.
$("#btn3").click(function () {
var optionsData= $.map($('#id_category')[0].options, function(elem) {
return (elem.value || elem.text);
}); // create a variable to hold all the options array.
$.ajax({
url: "/Products/Test03",
datatype: "text",
data: JSON.stringify(optionsData), //pass this variable to post request as 'options'
contentType: "application/json; charset=utf-8",
type: "POST",
success: function (data) {
$('#testarea').html(data);
},
error: function () {
$("#testarea").html("ERROR");
}
});
});
Then you can have your controller as below.
[HttpPost]
public string Test03(IEnumerable<string> options ) // change here to this
{
//your logic goes here
}
I think it's because you have not added [HttpPost] attribute in your controller function

Categories

Resources