#Ajax.ActionLink - passing value of text-area to controller, and a data-something attribute - ajax

This is the story:
I am making a commenting system, and when a user wants to add a comment they need to put data in a text area. I want to take that value typed by the user and make an #Ajax link which is to send that as a parameter to a controller.
I am using ASP.NET MVC5, and in my View() I have the following:
<textarea class="textArea" rows="3"></textarea>
<br />
#Ajax.ActionLink("Send",
"AddComment",
new { parametar = 0 , Contents = GetText() },
new AjaxOptions
{
UpdateTargetId = "beforeThis",
InsertionMode = InsertionMode.InsertBefore,
HttpMethod = "GET"
},
new { #class = "postavi btn btn-primary" })
I tried inserting under this the following:
<script type="text/javascript">
function GetText() {
return "hello there!";
}
</script>
I have in error saying that:
the name GetText does not exists in the current Context
(this is in the parameters of the #Ajax.ActionLink)
It seems I cannot integrate javascript (which could fetch me this value and razor code) How do I work this out???
PS> I have searched around for this, and either the answers for much earlier versions of MVC or the answers did not worked when I tried the same.

Make sure that you import this namespace:
using System.Web.Mvc.Ajax

You might add an event handler to the ajax link to update a custom route value.
#Ajax.ActionLink("Click", "Send", new {id = "xxx"}, new AjaxOptions(){}, new { onclick = "addParameter(this)" })
function addParameter(e) {
e.href = e.href.replace("xxx", "HelloWord");
}

What you are doing now is that you want the razor to call your JavaScript code and this is impossible. This is because Views will be rendered to HTML by Razor before they are sent to the client and Razor doesn't know about the JavaScript code, it only knows C#. All JavaScript code runs on the browser.
I suggest you use the POST method to send your comments.
You can use this code to send them:
#using (Ajax.BeginForm("AddComment", new { parametar = 0 }, new AjaxOptions()
{
UpdateTargetId = "beforeThis",
InsertionMode = InsertionMode.InsertBefore,
HttpMethod = "POST",
Url = Url.Action("AddComment")
}))
{
#Html.TextArea("Contents")
<input type="submit" value="Send" class="postavi btn btn-primary" />
}

Related

Why Does This AJAX.Helper Post call get a Enity Framework Error, but the "Get" doesn't?

As a learning project, I have a MVC & Typescript project and a Web 2.0 & entity framework project, the MVC project is trying to talk to the Web 2.0 project and I have a weird error.
This is my Web API 2.0 Player Controller:
public class PlayerController : ApiController
{
// GET api/<controller>/5
public Player Get(int? id)
{
if (id == null || id == -1)
{
var player = new Player();
LeaderBoardContext.Current.Players.Add(player);
LeaderBoardContext.Current.SaveChanges();
return player;
}
return LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == id);
}
// PUT: api/Scores/5
[ResponseType(typeof(void))]
public IHttpActionResult PostPlayer(LearningCancerAPICalls.Models.Player player)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var model = LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == player.PlayerId);
LeaderBoardContext.Current.Entry<Player>(player).State = EntityState.Modified;
try
{
LeaderBoardContext.Current.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
}
return StatusCode(HttpStatusCode.NoContent);
}
}
Its gone through a few iterations by this point, at one point it was initialising its own DB context at the top of the file but that was mysteriously null during the post. So now i'm using the style that we use in other projects which looks like this:
public static LeaderBoardContext Current
{
get
{
try
{
//added because 'HttpContext.Current.Items["_EntityContext"] ' was mysteriously comming back null....
if (HttpContext.Current.Items["_EntityContext"] == null)
{
HttpContext.Current.Items["_EntityContext"] = new LeaderBoardContext();
}
var obj = HttpContext.Current?.Items["_EntityContext"] as LeaderBoardContext;
return obj;
}
catch (Exception) //should only get here if using background task
{
return null;
}
}
}
So the first weirdness is in the post the context insisted on being null, but forcing it not to be null through the convoluted method above hasn't improved the situation much. Notice the first EF call that I have now put in to basically be the same as the GET:
var model = LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == player.PlayerId);
I have called the GET in both styles (with -1, with valid ID) and it works fine, but the POST has so far led to this error:
Which I would usually associate with a badly initialised EF project, but the GET works! it does exactly what it should do. I have even tried posting to a EF scafold controller with a different model and had the same problem!
The major difference between the two (apart from GET/POST) is the way I call them, this is how I use the GET:
var playerId = -1;
var activeUser:Player;
function initPlayerOnGameStart() {
if (host === undefined) {
host = 'http://localhost:52316';
}
if (playerId === undefined) {
playerId = -1;
}
var uri = host + '/api/Player/' + playerId;
jQuery.getJSON(uri).done(data => {
activeUser = data;
playerId = activeUser.PlayerId;
});
}
In a pure Typescript Json call. To do the POST I am experimenting with AJAX.Helper:
#model LearningCancerAPICalls.Models.Player
<a id="contact-us">Share Score!</a>
<div id="contact-form" class="hidden" title="Online Request Form">
#using (Ajax.BeginForm("", "", null, new AjaxOptions
{
HttpMethod = "POST", Url = "/api/Player",
OnSuccess ="OnSuccess",
OnFailure ="OnFailure"
}, new { id = "formId", name = "frmStandingAdd" }))
{
#Html.LabelFor(m => m.PlayerName);
#Html.TextBoxFor(m => m.PlayerName);
#Html.LabelFor(m => m.Email);
#Html.TextBoxFor(m => m.Email);
#Html.HiddenFor(m => m.PlayerId);
#Html.Hidden( "PlayerId");
<input type="submit" name="submit" value="Ok" />
}
</div>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script>
function OnSuccess() {
alert('Success');
}
function OnFailure(ajaxContext) {
alert('Failure');
}
</script>
Where I set PlayerID from the typescript. This successfully calls the post but crashes on the first use of EF. The other peculiar thing is that if I put a debug on the post. The model doesnt seem correct, as in, when I hover over it, it shows itself as a Player model, there has been no casting error, but it does not let me expand its properties. If I use variables or the imediate window to inspect variables then they are all fine. But I thought it was worth mentioning.
I am going to try a pure ajax call later to see if it resolves it, but I don't understand why the Ajax.helper would be at fault here, it technically does its job and the error is not related to the model that I can see.
UPDATE 1
So I tried the pure ajax call:
Html:
Name: <input type="text" name="fname" id="userName"><br />
<button onclick="postJustPlayer()"> Ok </button>
Typescript
function postJustPlayer() {
let level = jQuery("#chooseGridLevel").val();
let name = jQuery("#userName").val();
let uri = host + '/api/Player';
let player: Player = <Player>{};
player.Email = "Testing";
player.PlayerName = name;
jQuery.post(uri, player);
}
And this WORKS!?? I have no idea why the pure jQuery works, surely as far as EF is concerned it does the exact same thing? why would an AJAX.helper post be any different...
Solved it! This was a true puzzle, only solved when I delved into the network data (tools ftw).
For other newbies to web stuff I will explain how I found the route of this problem. In Chrome Dev Tools there is a Network tab that will show your web requests & responses. So by opening it after clicking my OK Button I can see this for my pure AJAX call:
I could then compare this to when I clicked "Submit" on my ajax form:
I Copy and paste these both into KDiff3, which highlighted one VERY important difference the local host address!
You will notice in the pure ajax request I specified the host, this is because as I mentioned, my web api project and my website project are separate, therefore they are on separate hosts!
So, in reality, the AJAX helper call should never have worked, but as it happens the day before I decided I needed a model from my API project in my website project and at the time thought "I probably shouldn't include my API project as a reference in my main website, but just for now....". So this lead to the API call with the wrong host being valid! With of course the fundamental difference that EF was not set up on THAT host.
So poor old ajax helper got plenty of my cursing for an error that only a special kind of idiot set up could lead to. Changing ajax helper to use the full path:
#model LearningCancerAPICalls.Models.Player
<a id="contact-us">Share Score!</a>
<div id="contact-form" class="hidden" title="Online Request Form">
#using (Ajax.BeginForm("", "", null, new AjaxOptions
{
HttpMethod = "POST", Url = "http://localhost:52316/api/Player",
OnSuccess ="OnSuccess",
OnFailure ="OnFailure"
}, new { id = "formId", name = "frmStandingAdd" }))
{
#Html.LabelFor(m => m.PlayerName);
#Html.TextBoxFor(m => m.PlayerName);
#Html.LabelFor(m => m.Email);
#Html.TextBoxFor(m => m.Email);
#Html.HiddenFor(m => m.PlayerId);
#Html.Hidden( "PlayerId");
<input type="submit" name="submit" value="Ok" />
}
</div>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script>
function OnSuccess() {
alert('Success');
}
function OnFailure(ajaxContext) {
alert('Failure');
}
</script>
Solved the problem! Thank you for anyone who scratched their head over this one, hopefully, this breakdown of a weird bug will be useful to someone.

how to include AntiForgeryToken in an ajax action link in mvc?

I have the following code:
#Ajax.ActionLink("Delete", "Delete",
new { id = item.ID, RequestVerificationToken=*What comes here?*},
new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "formsIndex" })
I want to add the verification token to the link without using javascript in client side, it seems like a redundant dependancy since i already own that value in server. Is there a proper way to do that?
From the MSDN documentation (my emphasis)
HtmlHelper.AntiForgeryToken Method
Generates a hidden form field (anti-forgery token) that is validated when the form is submitted.
You need a form element to generate the anti-forgery token.
#Ajax.BeginForm("Delete", new { id = item.ID }, new AjaxOptions { UpdateTargetId = "formsIndex" }))
{
#Html.AntiForgeryToken()
<input type="submit" value="Delete" /> // style to look like a link if that's what you want
}

mvc3 partialview target by div tag

I have an issue with a partialview, for some reason when I do a Post on it; it gives me another copy of my form; how can I make that behavior go away . This is what that partialview looks like:
// this is all inside my partialview
<div style=" float:left;">
#using (Ajax.BeginForm("posting", "post", null, new AjaxOptions
{
UpdateTargetId = "glober",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST"
}))
{
// taken out
}
</div>
<div id="glober">
#foreach (var item in Model.Mymodel)
{
}
</div>
as you can see this is a POST and I only want to update the part with the id of "glober" which it does but for some reason when I do the post it also gives me a second copy of the form elements. If inside my ajax form I have 1 textbox called firstname then after submitting it I get 2 textboxes that says firstname, any help would be great.
Part of my controller is this were i call out the partial
var iefeeds = sqlConnection.Query<thread>("Select * from postings").ToList();
return PartialView("_mypartial");
I think you have returned View rather than PartialView in the controller. So you'll see 2 pages overlapping in response of ajax Post.

MVC3 - Ajax loading icon

I would like to show an AJAX loading icon during an ActionResult request that can take a few seconds to process.
What is the best approach to accomplished this?
I only want to display the icon after the built it validation passes (I am using MVC3, EF Code First, so the validation is automatically put on the page).
There may be further validation/exceptions during the ActionResult, in which case a message is displayed to the user, and I'd then want the loading icon to disappear again.
Define your link as an Ajax action link and specify the ID of a spinning GIF somewhere on your page.
<div id="result"></div>
<img id="spinner" src="../content/ajaxspinner.gif" style="display: none;">
#Ajax.ActionLink("Link Text", "ActionName", "ControllerName", null, new AjaxOptions{UpdateTargetId = "result", LoadingElementId = "spinner"}, null)
or if it is a form:
#using(Ajax.BeginForm("Action", "Controller", null, new AjaxOptions{UpdateTargetId = "result", LoadingElementId = "spinner"}, null))
{
#Html.TextBox("Data")<br/>
<input type="submit" value="Submit" />
}
Put the image in a div tag like this:
<div id="busydiv" style="display:none;"><img src="busything.gif" /></div>
and then create your link like this:
#Ajax.ActionLink("Link Text", "ActionName", "ControllerName", null, new AjaxOptions { LoadingElementDuration = 1000, LoadingElementId = "busyDiv", HttpMethod = "Post", UpdateTargetId = "targetDiv", OnFailure = "PostFailure", OnSuccess = "PostSuccess", OnComplete = "PostOnComplete" }, null)
or in a form do this:
#using (Ajax.BeginForm("TestAjax", new AjaxOptions { LoadingElementDuration=1000, LoadingElementId="dave", HttpMethod = "Post", UpdateTargetId = "targetDiv", OnFailure = "PostFailure", OnSuccess = "PostSuccess", OnComplete = "PostOnComplete" }))
Obviously omitting those AjaxOptions that you don't need, as per the documentation here: http://msdn.microsoft.com/en-us/library/system.web.mvc.ajax.ajaxoptions.aspx
Just my two cents:
The solution posted by Chris is valid and will work BUT you must add a reference to the two javascript libraries below. Please note that the order matters:
<script src="~/scripts/jquery-1.8.0.js"></script>
<script src="~/scripts/jquery.unobtrusive-ajax.js"></script>
When you create an MVC application pre-loaded with bundling and all these nu-get packages this will probably not be a problem for you but if you were like me and created an empty ASP.NET MVC application you might run into issues.

MVC 2.0 Ajax: auto-submit on dropdown list causes normal postback

I am trying to add Ajax functionality to my MVC application. I want a form to post back asynchronously. Here's the form code:
using (Ajax.BeginForm("SetInterviewee", "Date", routeValues, new AjaxOptions { UpdateTargetId = "divInterviewee" }))
and I want it to automatically post back when a dropdown list selected value changes:
<%= Html.DropDownList("interviewees", Model.interviewees.intervieweeLists.intervieweesList, "-- select employee --", new { #class = "ddltext", style = "width: 200px", onchange = "this.form.submit();" })%>
However, when I try this out, the program posts back normally, not a partial postback as I was expecting. Here's what I think the problem is: onchange = "this.form.submit();" in the dropdown list.
I think that this somehow causes a normal postback instead of the asynchronous postback.
Here's what MVC generates for HTML for the form tag:
<form action="/SetInterviewee/2011-1-26/2011-1/visit" method="post" onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));" onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: 'divInterviewee' });">
I think that with "this.form.submit()" the "onsubmit" event handler is not being called. The thing is, I don't understand why. Wouldn't "onsubmit" catch any event that submits the form?
UPDATE: I went to jquery, thusly:
$(function () {
$('#interviewees').change(function () {
var form = $('#intervieweeForm');
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function (result) {
$('#selectedInterviewee').val(result);
}
});
});
});
This is causing many problems, among them:
-- It still does not seem to do an asyncrhonous postback. In my controller action method, I have the following code: "if (Request.IsAjaxRequest())" which returns false.
-- I can't seem to do model binding any more. My route looks like :
http://localhost:1986/Interviews/2011-2-25/2011-2/visit
but the route that apparently ends up being sent is
http://localhost:1986/SetInterviewee/2011-2-25/2011-2?
Count=5&Keys=System.Collections.Generic.Dictionary`2+KeyCollection
[System.String,System.Object]
&Values=System.Collections.Generic.Dictionary`2+ValueCollection
[System.String,System.Object]
causing the model binding not to work -- "visit" is supposed to be a "mode" parameter, but it's not there so "mode" defaults to "phone", which upsets the whole applecart.
It is the serialize command that is causing this? I don't understand why it would append it to the querystring when the method is POST.
There are other things -- among them, the fact that my action must return a ViewResult, so how can I possibly just return a string, which is all I need using ajax ... but I will defer that concern until I get the routing/binding thing straightened out!
UPDATE: "SetInterviewee" is indeed the correct route to post to, but the routeValues parameter should copy the route values from the current view -- I would think. Here's the code for the form:
RouteValueDictionary routeValues = ViewContext.RouteData.Values;
using (Html.BeginForm("SetInterviewee", "Date", routeValues, FormMethod.Post, new { id = "intervieweeForm" }))
So I know this is quite an old question, but I've been messing around with a similar issue and seem to come to a workaround that might prove useful in the future.
Inside your form, add a submit button. Something like:
<input type="submit" name="submit" value="save" style="display: none;" />
Make sure that you have specified the name attribute as it seems to matter in this case. Here is the code I have an it is currently working with full model binding:
<% using (Ajax.BeginForm("SaveStatus", "Finding", new { FindingId = Model.FindingId },
new AjaxOptions {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "StatusWindow",
OnBegin = "function(){ jQuery('#SaveStatusForm').block({ Message: 'Saving' }); }",
OnComplete = "function(){ jQuery('#SaveStatusForm').unblock(); }",
OnFailure = "HandleMSAjaxFail",
}, new { id = "SaveStatusForm" })) { %>
<div>
<%: Html.DropDownListFor(Status => Status.SelectedTagId, Model.AvailableStatuses, null, new Dictionary<string, object> { { "onchange", "jQuery('#SaveStatusForm').submit();" } })%>
<input type="submit" name="submit" value="save" style="display: none;" />
</div>
<% } %>
Granted this is my code and not tied to your example, but you can get the idea from what is going on. Originally I had the dropdownlist just doing a submit and when it fired I was getting all sorts of quirky responses - including a full synchronous postback. When I added the submit button, the MS ajax code seems to work beautifully. Give it a shot!
I would recommend you to use jquery and get rid of all Ajax.* helpers and MSAjax scripts.
So:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<% using (Html.BeginForm("SetInterviewee", "Date", routeValues, FormMethod.Post, new { id = "myform" })) { %>
...
<% } %>
<%= Html.DropDownList(
"interviewees",
Model.interviewees.intervieweeLists.intervieweesList,
"-- select employee --",
new { id = "interviewees", #class = "ddltext", style = "width: 200px" }
)%>
and then in a separate javascript file:
$(function() {
$('#interviewees').change(function() {
var form = $('#myform');
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function(result) {
$('#divInterviewee').html(result);
}
});
});
});
Now we have successfully separated HTML markup from javascript. It is unobtrusive javascript.

Resources