I have the following code:
#Ajax.ActionLink("Settings", "SettingsPopup", "Settings",
new { area = "Customer" },
new AjaxOptions()
{
HttpMethod = "Get",
UpdateTargetId = "settings-content",
InsertionMode = InsertionMode.Replace,
OnSuccess = "settingsPopupLoaded",
AllowCache = true
},
new { #class = "profile-right__a icon-help" })
I need to add <i class="sub"></i> element inside this liks as:
<i class="sub"></i>
How to do this?
When you want to have customized markup but still want the ajaxy behavior. You can simply use jQuery to wire up that (That is what the ajax helpers also does)
<a class="ajaxy" targetid="settings-content"
href="#Url.Action("settingsPopup","Settings",new { area="Customer"})">
<span class="glyphicon glyphicon-user text-#userLevel"></span>
</a>
The javascript will be quite simply, simply look for the elements with the css class "ajaxy", make an ajax call using jQuery $.get method and update the DOM element with the result coming back.
function settingsPopupLoaded(e) {
console.log('settingsPopupLoaded', e);
}
$(function () {
$(".ajaxy").click(function (e) {
e.preventDefault();
var _this = $(this);
$.get(_this.attr("href"), function (res) {
var tId = _this.attr("targetid");
$("#" + tId).html(res);
settingsPopupLoaded(res);
});
});
});
You can also use $.load method if it is simply updating the DOM element with the response from the ajax call.
Related
I am having this problem while working on an eshop I am building, I want to simply do a post request to a controller (that is not returning a view) while also submiting a form.. I do not know what is wrong with this code
<script>
$(document).ready(function () {
console.log("sad");
$("a[data-form-method='post']").click(function (event) {
event.preventDefault();
var element = $(this);
var action = element.attr("href");
element.closest("form").each(function () {
var form = $("#form1");
form.attr("action", action);
form.submit();
});
});
});
</script>
Here is the form
using (Html.BeginForm("SendEmailToAdmin", "Home", FormMethod.Post, new { id = "form1" }))
{
#Html.Hidden("receiver", $"{user.Email}");
Customer Support
}
Here is the controller
[HttpPost]
[Route("/Home/SendEmailToAdmin")]
//[NonAction]
public JsonResult SendEmailToAdmin()
{
........
(some code
if is true )
return Json(new { status = "Thank you very much admin for showing up. Don't forget to send us the email of your feedback on your way out" }, JsonRequestBehavior.AllowGet);
}
(or else)
return Json(new { status = "Something went wrong, please try again" }, JsonRequestBehavior.AllowGet);
I have tried also using a button with the id of submitDemo
$('body').on('click', function (e) {
e.preventDefault();
alert("Handler for .click() called.");
$.post("~/Home/SendEmailToAdmin");
});
and also
$("#form1").submit(function (event) {
event.preventDefault();
$.post('#Url.Action("SendEmailToAdmin", "Home",new { id = email })');
document.signupform.submit();
});
have also tried using a variable for the button and then with onclick method and so on...
const button = document.getElementById('submitDemo');
EDIT : I HAVE TRIED THIS
I fount it at last.. here it goes!
Jquery:
$(document).ready(function () {
$("#submitBtn").click(function (event) {
console.log("sad");
event.preventDefault();
$.ajax({
type: "POST",
url: "#Url.Action("SendEmailToAdmin", "Home")",
data: "#email",
success: function () {
console.log("Done")
$("#form1").submit();
}
});
});
});
html in view : I added the btn outside of the form
and this way the submit form happens and also the post request!
using (Html.BeginForm("AdminSupport", "Home", FormMethod.Post, new { id = "form1" }))
{
#Html.Hidden("receiver", $"{user.Email}");
#*<button id="submitbutton" #user.Email=>Customer Support</button>*#
}
<button id="submitBtn" #*data-form-method="post"*#>Customer Support</button>
Not for the first time, I'm seeing that my Razor Pages seem to be handling GET/POST actions strangely when posting with ajax.
The latest example looks like this:
#inject IAntiforgery antiForgery
#{
ViewData["Title"] = "Disclaimers";
Layout = "~/Pages/Shared/_Blade.cshtml";
var token = antiForgery.GetAndStoreTokens(HttpContext).RequestToken;
}
$(".save-button").on("click", function(e) {
e.preventDefault;
const body = document.querySelector(".editor").innerText;
let disclaimer = {
clientid: parseInt($("#Disclaimer_Client_Id").val()),
description: $("#Disclaimer_Description").val(),
type: $("#Disclaimer_Type").val(),
markup: body
};
$.ajax({
method: "GET",
url: "./Create?handler=Create",
headers: {
"RequestValidationToken": "#token"
},
data: disclaimer,
dataType: "application/json",
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data);
}
});
});
I've done it this way because I'm using quilljs which employs a div for it's rich text editor. I can't use asp-for bindings on the div to bind it to the model.
public async Task<IActionResult> OnGetCreate(CreateDisclaimerViewmodel model)
{
var disclaimer = new Disclaimer
{
Created = DateTime.Now,
CreatedBy = User.Identity.Name,
Description = model.Description,
Markup = model.Markup,
Type = model.Type
};
if (model.ClientId > 0)
{
disclaimer.Client = await context.Clients.FindAsync(model.ClientId);
}
context.Disclaimers.Add(disclaimer);
await context.SaveChangesAsync();
return Redirect("/Disclaimers/Index");
}
With the code set up as using a GET method, it all works, but in this case, it should clearly be a POST.
Change it to a POST however and an empty response is returned with HTTP 400...
$(".save-button").on("click", function(e) {
e.preventDefault;
const body = document.querySelector(".editor").innerText;
let disclaimer = {
clientid: parseInt($("#Disclaimer_Client_Id").val()),
description: $("#Disclaimer_Description").val(),
type: $("#Disclaimer_Type").val(),
markup: body
};
$.ajax({
// Only the method changes here, everything else is above.
method: "POST",
url: "./Create?handler=Create",
headers: {
"RequestValidationToken": "#token"
},
data: disclaimer,
dataType: "application/json",
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data);
}
});
});
And the page model:
// Only the method changes (OnGetCreate becomes OnPostCreate).
public async Task<IActionResult> OnPostCreate(CreateDisclaimerViewmodel model)
{
var disclaimer = new Disclaimer
{
Created = DateTime.Now,
CreatedBy = User.Identity.Name,
Description = model.Description,
Markup = model.Markup,
Type = model.Type
};
if (model.ClientId > 0)
{
disclaimer.Client = await context.Clients.FindAsync(model.ClientId);
}
context.Disclaimers.Add(disclaimer);
await context.SaveChangesAsync();
return Redirect("/Disclaimers/Index");
}
This clearly should be a POST request but it simply won't work when using POST.
So what am I missing or misunderstanding? And since the solution can't be to use GET, what's the solution?
Shorten answer:
You use the wrong header name, it should be RequestVerificationToken:
headers: {
"RequestVerificationToken": "#token"
},
You are getting a 400 (Bad Request) response because the framework expects the RequestVerificationToken as part of the posted request. Be sure you have send it correctly.
Common way use ajax post in Razor Pages
Be sure your form tag does not have action attribute and then it will dynamically add a hidden input for token (You can F12 in browser to check whether your html contains input named __RequestVerificationToken, Ctrl+F and search for __RequestVerificationToken):
<form method="post">
//other elements...
<input class="save-button" type="button" value="CHANGE"/>
</form>
#section Scripts
{
<script>
$(".save-button").on("click", function(e) {
e.preventDefault;
//...
$.ajax({
// Only the method changes here, everything else is above.
method: "POST",
url: "?handler=Location",
headers: {
RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val()
},
data: disclaimer,
dataType: "application/json",
//...
});
});
</script>
}
Otherwise, you will need manually add it by using #Html.AntiForgeryToken() in the form:
<form method="post">
//other elements...
#Html.AntiForgeryToken()
<input class="save-button" type="button" value="CHANGE"/>
</form>
I am using ASP.NET Core 3.1 MVC to create a page with a form. The form has a dropdown and a textbox. The dropdown is populated with values from the database. The textbox will populate with a value from the same table and the dropdown, based on the selected dropdown value. My goal is to call a function from my controller inside of my view, is that possible?
My cshtml file:
<form method="post" asp-controller="Index" asp-action="Index" role="form">
<div class="form-group">
<select id="fileName" asp-items="#(new SelectList(ViewBag.message, "ID", "fileName"))" onchange="getUploadedFile()"></select>
<input />
</div>
</form>
My Model
public class myFiles
{
public int ID {get; set;}
public string fileName {get; set;}
public string uploadedFile {get; set;}
}
My controller has a function named GetUploadedFile() which runs a query to the database that returns the file name based on the ID. I originally thought I could reference the GetUploadedFile through my view(cshtml file) by adding the onchange handler and setting it as onchange="GetUploadedFile()". I have also tried to do an ajax call to get the UploadedFile.
My goal is to call a function from my controller inside of my view, is that possible?
Do you mean you want to add the myfiles' uploadfile value according to the dropdownlist selected value in the onchange getUploadedFile jquery method? If this is your requirement, I suggest you could try to use ajax to achieve your requirement.
You could write the ajax to post request to the mvc action, then you could get the value and set the result to the textbox.
Details, you could refer to below codes:
<form method="post" asp-controller="home" asp-action="Index" role="form">
<div class="form-group">
<input id="uploadedFile" type="text" class="form-control" />
<select id="fileName" asp-items="#(new SelectList(ViewBag.message, "ID", "fileName"))" onchange="getUploadedFile(this)"></select>
</div>
</form>
<script>
function getUploadedFile(Sle) {
$.ajax({
url: "/Home/GetUploadfileName",
data: { "FileID": Sle.value} ,
type: "Post",
dataType: "text",
success: function (data) {
console.log(data);
$("#uploadedFile").val(data);
},
error: function (data) {
alert(data);
}
});
}
</script>
Action method:
private List<myFiles> myfiletestdata = new List<myFiles>() {
new myFiles(){ ID=1, fileName="test1", uploadedFile="testuploadfile" },
new myFiles(){ ID=2, fileName="test2", uploadedFile="testuploadfile2" },
new myFiles(){ ID=3, fileName="test3", uploadedFile="testuploadfile3" },
};
[HttpPost]
public IActionResult GetUploadfileName(int FileID) {
//get the filename result accoding to ID
var result = myfiletestdata.Where(x=>x.ID== FileID).First();
return Ok(result.uploadedFile);
}
Result:
If I understand correctly, you just want to get the file name from the database when a value from the dropdown is selected.
What errors did you get when you tried the ajax call??
In your cshtml file, you can have something like this:
<script>
function getUploadedFile() {
var id = $('#fileName option:selected').val();
$.getJSON('/ControllerName/GetUploadedFile', { id: id }, function (result) {
var file = result.fileName;
.... do whatever with the result
to set value of the textbox:
$('#textBoxId').text(file);
});
}
</script>
Instead of getJSON, you could use ajax:
<script>
function getUploadedFile() {
var id = $('#fileName option:selected').val();
$.ajax({
url: 'ControllerName/GetUploadedFile',
type: 'GET',
dataType: 'json',
data: {
'id': id
}
})
.done(function (result) {
if (!result.errored) {
var file = result.fileName;
}
else {
}
});
}
</script>
Then in your controller, if you are not submitting the form and just want to update the value of the textbox, then it can just be:
[HttpGet]
public async Task<IActionResult> GetUploadedFile(int id)
{
Sample code:
var file = await GetFileFromDb(id);
return Json(new { fileName = file });
}
Also, you should consider using ViewModels instead of ViewBag.
I have a view that has a dropdown that is generated by a linq statement when the view is populated.
<div class="form-group">
#Html.LabelFor(m => m.OrderID, "Order ID")
<div>
#Html.DropDownListFor(m => m.OrderID, Model.Orders, "Select Order ID",
new { #id = "orderDropdown" })
</div>
</div>
I have 2 other fields in the view that need to be updated with the data retrieved from the database.
<div class="form-group">
#Html.Label("Final Weight")
<div id="finalWeight">
#Html.DisplayFor(m => m.FinalWeight)
</div>
</div>
<div class="form-group">
#Html.Label("Initial Weight")
<div id="initialWeight">
#Html.DisplayFor(m => m.InitialWeight)
</div>
</div>
This is the ajax that I got from the link below:
<script>
$("#orderDropdown").change(function (event) {
$.ajax({
url:"???" + $(this).val(),/* not sure what to use*/
data: { id: $(this).val()},
cache: false,
type: "GET",
dataType: "html",
success: function (data, textStatus, XMLHttpRequest) {
$("#divinitialWeight").html(data);
}
});
});
Here is the controller code
[HttpGet]
[OpenAction]
public async Task<float> GetInitialWeight(int sid)
{
var initialWeight = await Manager.FindInitialFilterWeightBySID(sid);
return initialWeight.MeanWeight;
}
The method is in a Data Access Layer that is only referenced in the main project. The way I would call it in the controller would be like below and pass it the orderId :
Entities.Manager.FindInitialWeight(orderId);
Entities.Manager.FindFinalWeight(orderId);
I came across this SO question and it's close to what I need but the only issue is the url: because the data retrieval method is not in my controller...it is in the data access layer that is only a reference. Also the orderId is being passed as a parameter.
How can I call that method from ajax and pass it the orderId from the url: of the ajax call?
You can call the controller method from JQuery like this
if the JQuery code is within the razor view
url: '#Url.Action("GetInitialWeight")',
data: { sid: $(this).val()},
I actually had to create a GET method in my controller that contacted the DAL with the passed parameter from the javascript
[HttpGet]
[OpenAction]
public async Task<ActionResult> GetInitialWeight(int sid)
{
var initialWeight = await Manager.FindInitialFilterWeightBySID(sid);
return Json(new { initialWeight.MeanWeight }, JsonRequestBehavior.AllowGet);
}
Then change the javascript as such
<script>
$("#sidDropdown").change(function (event) {
var url = "/Controller/GetInitialWeight/";
var data = { sid: $(this).val() };
var dataType = "json";
$.get(
url,
data,
function (response) {
$("div#initialWeight").text(response.MeanWeight)
console.log(response.MeanWeight);
}, dataType);
});
I'm trying to write CRUD operations using ajax. Here some code:
These are my View classes:
//PhotoSummary
#model PhotoAlbum.WEB.Models.PhotoViewModel
<div class="well">
<h3>
<strong>#Model.Name</strong>
<span class="pull-right label label-primary">#Model.AverageRaiting.ToString("# stars")</span>
</h3>
<span class="lead">#Model.Description</span>
#Html.DialogFormLink("Update", Url.Action("UpdatePhoto", new {photoId = #Model.PhotoId}), "Update Photo", #Model.PhotoId.ToString(), Url.Action("Photo"))
</div>
//Main View
#model PhotoAlbum.WEB.Models.PhotoListViewModel
#{
ViewBag.Title = "My Photos";
}
#foreach (var p in #Model.Photos)
{
<div id=#p.PhotoId>
#Html.Action("Photo", new {photo = p})
</div>
}
The sript:
$('.dialogLink').on('click', function () {
var element = $(this);
var dialogTitle = element.attr('data-dialog-title');
var updateTargetId = '#' + element.attr('data-update-target-id');
var updateUrl = element.attr('data-update-url');
var dialogId = 'uniqueName-' + Math.floor(Math.random() * 1000)
var dialogDiv = "<div id='" + dialogId + "'></div>";
$(dialogDiv).load(this.href, function () {
$(this).dialog({
modal: true,
resizable: false,
title: dialogTitle,
close: function () { $(this).empty(); },
buttons: {
"Save": function () {
// Manually submit the form
var form = $('form', this);
$(form).submit();
},
"Cancel": function () { $(this).dialog('close'); }
}
});
$.validator.unobtrusive.parse(this);
wireUpForm(this, updateTargetId, updateUrl);
});
return false;
});});
function wireUpForm(dialog, updateTargetId, updateUrl) {
$('form', dialog).submit(function () {
if (!$(this).valid())
return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$(dialog).dialog('close');
$(updateTargetId).load(updateUrl);
} else {
$(dialog).html(result);
$.validator.unobtrusive.parse(dialog);
wireUpForm(dialog, updateTargetId, updateUrl);
}
}
});
return false;
});
}
And here my Tag builder:
public static MvcHtmlString DialogFormLink(this HtmlHelper htmlHelper, string linkText, string dialogContentUrl,
string dialogTitle, string updateTargetId, string updateUrl)
{
TagBuilder builder = new TagBuilder("a");
builder.SetInnerText(linkText);
builder.Attributes.Add("href", dialogContentUrl);
builder.Attributes.Add("data-dialog-title", dialogTitle);
builder.Attributes.Add("data-update-target-id", updateTargetId);
builder.Attributes.Add("data-update-url", updateUrl);
builder.AddCssClass("dialogLink");
return new MvcHtmlString(builder.ToString());
}
So, I have major problem if the dialog was called twice without the calling page being refreshed:
it just redirects me to the action page.
The question is how to update #Html.Action without reloading the page?
Could anyone help me?
Your #foreach loop in the main view is generating a partial view for each Photo which in turn is creating a link with class="dialogLink".
Your script handles the click event of these links and replaces it with a new link with class="dialogLink". But the new link does not have a .click() handler so clicking on the new (replacement) link does not activate your script.
Instead you need to use event delegation to handle events for dynamically generated content using the .on() method (refer also here for more information on event delegation). Note also that your current use of $('.dialogLink').on('click', function () { is the equivalent of $('.dialogLink').click(function () { and is not using event delegation. It attaches a handler to elements that exist in the DOM at the time the page is loaded, not to elements that might be added in the future.
Change your html to
<div id="photos">
#foreach (var p in #Model.Photos)
{
<div class="photo">#Html.Action("Photo", new { photo = p })</div>
}
</div>
and then modify the script to
$('#photos').on('click', '.dialogLink', function() {
....
});
Side note: There is no real need to add an id=#p.PhotoId to the containing div element and you could use <div class="photo"> as per above, and then reference it by using var updateTargetId = $(this).closest('.photo'); and delete the builder.Attributes.Add("data-update-target-id", updateTargetId); line of code from your DialogFormLink() method