MVC - Use #Html.ActionLInk to fire Ajax to trigger ActionResult - javascript

I've done a lot of research on this. I can't find anything that really fits my situation. I'm a new programmer. I'm working on getting better with JavaScript but it's my weak spot.
I have two databases - employees and breaks. I attached a picture to make this make more sense:
The break list from the database is the list you see in the table in the image. The dispatcher dropdown contains all employee names. Drop the name down, hit submit - it adds to the database and displays here. Works great.
Now I'm trying to use #Html.ActionLink to make the names clickable. That needs to fire another JavaScript event to enter DateTime.Now into the TimeCleared field to essentially delete the break from the list.
I'm doing something wrong, though (or a lot of things wrong). Either it doesn't update the database and time stamp that TimeCleared field, I get a "This request has been blocked because sensitive information could be disclosed to third-party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet." error or other errors based on what I try.
Part of the View:
<div class="container_lists">
<div class="container_break col-md-6">
#*start the break list table*#
<h5 style="text-align:center">Break List</h5>
<table class="table-bordered col-lg-12">
#*populate the table with only those breaks that lack a TimeCleared value*#
#if (Model != null)
{
foreach (var item in Model)
{
if (item.TimeCleared == null)
{
<tr>
#*Make each name clickable to fire JavaScript which activates ActionResult DeleteBreak*#
<td class="breakIdNumber">
#Html.ActionLink(item.DisplayName, "DeleteBreak", new { id = item.BreakId }, new { onclick = "return confirm('Remove from the break list?');" })
</td>
</tr>
}
}
}
</table>
Part of the controller:
public ActionResult DeleteBreak(BreakModels breakmodels)
{
try
{
breakmodels.TimeCleared = DateTime.Now;
db.SaveChanges();
return Json(new { success = true});
}
catch (Exception ex)
{
return Json(new { success = false});
}
}
Ajax:
#*Activate the DeleteBreak ActionResult*#
<script>
$(document).ready(function () {
$("#RemoveBreak").click(function () {
var model = {};
model.BreakId = Number($("#breakIdNumber").val());
console.log("model", model);
$.ajax({
type: "POST",
url: "/Home/DeleteBreak",
dataType: 'json',
data: JSON.stringify(model),
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.success)
window.location.href = "/Home/Index";
else
alert("Something went wrong");
},
error: function () {
alert("Something went wrong");
}
});
});
});
</script>

Related

ASP Index.cshtml is calling IndexAsync twice and second time Session Variables are gone

I've looked through some examples, but they don't seem to be helping.
I have an index page that redirects to another controller on button click. The controller gathers database records before displaying its view, so it needs to be async.
This action always happens twice. (Developer system, one user, so it isn't some multiuse conflict)
I thought it might be a double click issue since there is an async call being made. But I changed my code to account for this and it still happens.
Here is the Button:
<div class="col-md-4">
<button type="submit" id="ViewHoursbutton" name="ViewHours" class="btn btn-primary button-bottom" >View Hours</button>
</div>
Here is the button click script:
$(document).ready(function ()
{
$("#ViewHoursbutton").one("click", function ()
{
window.location.href = "/ETime?EmployeeID=" + employeeID;
});
});
Here is my controller with the IndexAsync:
public class ETimeController : BaseController
{
private List<TrackingItems> _trackingItems = new List<TrackingItems>();
private Employee _OnEmployee; // The employee we are working with
[HttpGet]
public async Task<IActionResult> IndexAsync(string EmployeeID)
{
if (EmployeeID == null)
{
// return error 205
return NoContent();
}
TrackingItems TrackingDB = new TrackingItems();
// grab a month of data or so.
var trackingItems = await TrackingDB.GetTrackingItems(
EmployeeID,
DateTime.Today.AddDays(-30),
DateTime.Today.AddDays(1));
dynamic DynModel = new ExpandoObject();
_OnEmployee = GetSessionObject("CurrentEmployee");
if (LMenuVModel == null)
{
LMenuVModel = GetSessionMenu();
}
DynModel.MenuViewModel = LMenuVModel;
DynModel.Employee = _OnEmployee;
if (trackingItems.Count > 0)
{
DynModel.TrackingItems = trackingItems;
_trackingItems = trackingItems;
}
else
{
DynModel.TrackingItems = null;
DynModel.TrackingItems = trackingItems;
}
return View(DynModel);
}
}
One thing really weird (and nasty) is the second time through, the Session object has disappeared. In Fact, when I inspect it using breakpoints, I see that the HttpContext.Session.SessionID has changed. But I don't think it can be timeout, since it happens every time at the same place in my code.
I only mention it in case it helps debug this behavior.
Thanks in advance!
I'm not sure this is the best way of handling this, but it seems to be working. I'm going to put this up and if no one comes up with a better way, I will close it as the answer.
There was NOTHING I could find that worked to stop the multiple calls into the method. So I changed the pattern.
The overview was I had one view (EMPLOYEE) that was to redirect to the other(ETIME). When I just had Javascript do it, the Javascript was executing twice, in different Sessions -- IDK how that is possible, but that's what it looks like. So, in a rough diagram it was doing this:
So, I changed it to use Ajax to call into the EMPLOYEE controller, and pass the info back to the EMPLOYEE Ajax script which then redirected to the ETIME controller and view.
It still gets called twice, but now I can catch to "false" call, and ignore it with a 205 error. so, it SEEMS to run better now.
Changes to code looks like this:
Button Definition:
<div class="col-md-4">
<button type="button" id="ViewHoursbutton" name="ViewHours" class="btn btn-primary button-bottom">View Hours</button>
</div>
Employee Controller:
[HttpPost]
public IActionResult GotoHours(string employeeID)
{
if (employeeID == null || employeeID == "undefined")
{
return NoContent();
}
// Pass the EmployeeID back to the AJAX Success section
// which will do the redirect
var retVal = Json(new { EmployeeID = employeeID });
return retVal;
}
AJAX Script:
<script type="text/javascript">
var employeeID = '#Model.Employee.EmployeeID';
$(document).ready(function ()
{
$("#ViewHoursbutton").off("click").click(function ()
{
event.stopPropagation();
$.ajax({
type: "POST",
url: "/Employee/GotoHours",
data: { employeeID: employeeID },
dataType: "json",
success: function (response)
{
// handle the success by making it redirect
window.location.href = "/ETime/Index?EmployeeID=" + response.EmployeeID;
},
error: function (jqXHR, textStatus, errorThrown) {
// handle the error response here, if necessary
}
});
});
You can see in the Ajax script I threw everything but the kitchen sink at the button to stop it from double clicking and double sending, but nothing worked.
Anyway... I'll be curious to see if anyone has a better way. I am not deeply experienced in HTML/Ajax ways. But this seems to work.

event.preventDefault() and redirect asp mvc/jQuery

What am trying to do is to post on form submit to a action and catch response and that works fine.Problem is when RedirectToAction gets called, it just stays on that same view(it doesn't redirect),or in case model is not valid, it doesn't show model validation. So i guess the problem is with url, but how can I correct it?
jQuery
$("form").on("submit", function (e) {
e.preventDefault();
var form = $(this);
var formURL = form.attr("action");
$.ajax({
type: "POST",
url: formURL,
data: $(this).serialize(),
success: function (response) {
if (response !== null && response.success == false) {
alert(response.responseText);
}
}
});
});
c# asp mvc
public ActionResult Add(SomeModel model) {
if (ModelState.IsValid) {
if (true) {
return Json(new { success = false, responseText = "Some error" }, JsonRequestBehavior.AllowGet);
}
return RedirectToAction("Details", new { id = id });
}
//gets called but it doesn't show validation.
return View(model);
}
public ActionResult Details(int id) {
//gets called but it doesn't show the view.
return view(model);
}
Because you're posting your form with an Ajax POST and your in your success function you have alert(response.responseText), you are NOT going to receive a View.
What you need to do is in success function, take the response from Details action and place it inside an HTML element on the page. Like below:
success: function (response) {
$("#div").html(response);
}
On another note, since you're not using a standard FORM and your posting with JavaScript, you wont get built in validation the models provide.

Using JavaScript to refresh or retrieve current information on button click

I'll preface this with I'm still new to JavaScript. So problem is in a larger application, our controller is passing in a list of information to the view where certain JavaScript functions rely on certain ViewModel properties. I've written a simple application to hopefully illustrate what I'm getting at.
Below is a sample controller that's passing in List to the Index page:
public ActionResult Index() {
List<int> activeIds = new List<int>();
SqlConnection sqlConn = new SqlConnection(connection_String);
sqlConn.Open();
string sqlStr = "SELECT * FROM dbo.[JS-Test] WHERE Active = 1";
SqlCommand sqlCmd = new SqlCommand(sqlStr, sqlConn);
SqlDataReader sqlDR = sqlCmd.ExecuteReader();
if(sqlDR.HasRows) {
while (sqlDR.Read()) {
activeIds.Add((int)sqlDR["ID"]);
}
}
sqlDR.Close();
sqlCmd.Dispose();
sqlConn.Close();
return View(activeIds);
}
This returns the current "active" items in the database. The (rough) view is as follows...
#model List<int>
#{
ViewBag.Title = "Index";
}
<p>Current Recognized Count: #Model.Count() </p>
Print
<script>
$(document).ready(function () {
$('#printBtn').click(function () {
var numberOfActiveIds = #Model.Count();
$.ajax({
type: "POST",
url: "/Home/PostResults",
data: { ids: numberOfActiveIds},
success: function (results) {
if(results == "Success") {
window.location.href = '/Home/Results';
}
}
});
});
});
</script>
The issue is getting the current number of active items from the database when the button is clicked. Let's say that the user remains idle on the page after it loads for a few minutes. When their page originally loaded, the model returned 5 items listed as active... but while they've been waiting 3 additional items were switched to active in the database for a total of 8. However, when the user finally clicks the button it'll submit 5 items instead of the current 8.
I'm unable to run the query to get the current number of active items in the "/Home/PostResults" ActionResult due to the nature of how the larger application is set up. Is there a way I could refresh the page (getting the updated model) before the rest of the function carries out using values of the refreshed model?
If you have any additional questions, please let me know and I will gladly comply. I've looked at other questions and answers on SO but I haven't found one that quite works for my situation. Thanks!
Edit #1
So, I've added this function to the Home controller which just returns the list count as Json.
public ActionResult GetIds(){
List<int> activeIds = new List<int>();
SqlConnection sqlConn = new SqlConnection(connection_String);
sqlConn.Open();
string sqlStr = "SELECT * FROM dbo.[JS-Test] WHERE Active = 1";
SqlCommand sqlCmd = new SqlCommand(sqlStr, sqlConn);
SqlDataReader sqlDR = sqlCmd.ExecuteReader();
if (sqlDR.HasRows) {
while (sqlDR.Read()) {
activeIds.Add((int)sqlDR["ID"]);
}
}
sqlDR.Close();
sqlCmd.Dispose();
sqlConn.Close();
return Json(activeIds.Count());
}
The view script now looks like this...
<script>
$(document).ready(function () {
$('#printBtn').click(function () {
var numberOfActiveIds = #Model.Count();
$.ajax({
type: "GET",
url: "/Home/GetIds",
success: function(response) {
numberOfActiveIds = response;
$.ajax({
type: "POST",
url: "/Home/PostResults",
data: { ids: numberOfActiveIds},
success: function (results) {
if(results == "Success") {
window.location.href = '/Home/Results';
}
}
});
}
});
});
});
</script>
I'm currently getting the following error...
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
Edit #2
I had to set the JsonRequestBehavior to AllowGet for it to work properly. Thanks again, everyone!
gforce301 mentioned to GET the current actives via an ajax call to an additional, separate method making the query to the database and THEN ajax post the returned "actives". Is that possible?
Yes this is possible. That's why I mentioned it. Irregardless of other peoples opinions on how they think you should do this, I understand that you may be limited on why you can't do it their way even if they don't.
The code below is a restructuring of your code. It chains 2 ajax calls together, with the second one depending on the success of the first. Notice the comment block in the success handler of the first ajax call. Since I don't know what the response will be, I can't fill in the part on how to use it. This accomplishes your goal of having the user only make a single button click.
<script>
$(document).ready(function () {
$('#printBtn').click(function () {
var numberOfActiveIds = #Model.Count();
$.ajax({
type: 'GET',
url: '/path/to/get/activeIds',
success: function(response) {
/*
Since I don't know the structure of response
I have to just explain.
use response to populate numberOfActiveIds
now we just make our post ajax request.
*/
$.ajax({
type: "POST",
url: "/Home/PostResults",
data: { ids: numberOfActiveIds},
success: function (results) {
if(results == "Success") {
window.location.href = '/Home/Results';
}
}
});
}
});
});
});
</script>
I can give you an idea, i hope it can help,
run another ajax 1st on btnclick to get the data(or datat count) again, if the record count is greater then current then update the view and don't PostResults and if its same then just PostResults
on ajax success you can reload the data or view
and on failure(when no new record) just do PostResults

How to export a model function from a controller to a view in Laravel 4

I am trying to display some data from my database that is dependent on some input from the user. I am using an ajax request to get the data, send it back to a function in my controller, and then export it back to my view. I would like to collect this data and display it without going to another view (I just hide the previous form and unhide the new form).
Here is the relevant code:
Javascript:
$('#submit_one').on('click', function(event) {
event.preventDefault();
if(! $(this).hasClass('faded')) {
var fbid = $("input[name='like']:checked").val();
//variable to be collected is fbid
request = $.ajax({
url: "http://crowdtest.dev:8888/fans/pick_favorite",
type: "post", success:function(data){},
data: {'fbid': fbid} ,beforeSend: function(data){
console.log(data);
}
});
to_welcome_two();
}
});
function to_welcome_two()
{
$('#welcome_one').addClass('hidden');
$('#welcome_two').removeClass('hidden');
}
Controller functions:
public function pick_favorite() {
$fbid=Input::get('fbid');
return Artist::specific_artist($fbid);
}
public function getWelcome() {
return View::make('fans.welcome')
->with('artists', Artist::artists_all())
->with('favorite_artist', Artist::favorite_artist())
->with('pick', FansController::pick_favorite());
}
Model function:
public static function specific_artist($fbid) {
$specific_artist = DB::table('artists')
->where('artists.fbid', '=', $fbid)
->get();
return $specific_artist;
}
The view is on the "welcome" page. My question is how do I display the model data in my view and make sure it is printing out the correct data from the fbid input?
I tried something like this:
#foreach($pick as $p)
<span class="artist_text">{{$p->stage_name}}</span>
<br>
<span class="artist_city">{{$p->city}}</span>
#endforeach
but this is not printing out anything. Any ideas?
i see lots of issues here.
Server side:
public function pick_favorite().... what does it do? it just returns some data.
in public function getWelcome() { , you wrote, FansController::pick_favorite(). supposing both are the same method, you are accessing a static method whilst the method is non static. you are getting an error for this but you are not seeing it because you didn't define fail().
and i don't see what the point of declaring a method which does nothing else then a model call which you can do directly.
e.g let's say i have a fooModel
public function index(){}
in controller, i can just write,
public function bar()
{
$model = new fooModel;
return View::make(array('param1'=>$model->index()));
}
or if i declare index() method in fooModel as static, then i can write,
public function bar()
{
return View::make(array('param1'=>fooModel::index()));
}
Client side:
now in your javascript,
$('#submit_one').on('click', function(event) {
event.preventDefault();
if(! $(this).hasClass('faded')) {
var fbid = $("input[name='like']:checked").val();
//variable to be collected is fbid
request = $.ajax({
url: "http://crowdtest.dev:8888/fans/pick_favorite",
type: "post", success:function(data){},
data: {'fbid': fbid} ,beforeSend: function(data){
console.log(data);
}
});
to_welcome_two();
}
});
function to_welcome_two()
{
$('#welcome_one').addClass('hidden');
$('#welcome_two').removeClass('hidden');
}
why it should print any data? you didn't asked the script to print anything. where is your .done or .success param in your code?
If you look at your console, you'l get lots of php errors, i am almost sure of.
an advice, you need to lear some basics. e.g. jquery ajax call.
a basic ajax call can be
var request = $.ajax({
url: "script.php",
type: "POST",
data: { id : menuId },
dataType: "html"
});
request.done(function( msg ) {
$( "#log" ).html( msg );
});
request.fail(function( jqXHR, textStatus ) {
alert( "Request failed: " + textStatus );
});
implement it in your code and then see what errors it throws.
Conclusion:
1st one will be (supposing rest of your codes are ok) the static error. if you want to call it as static, declare it as static. but a static function in controller? i don't see any purpose of it.
and then start the debug. your problem is both client and server side. deal one by one.

How can I pass a ViewModel property to an ajax post method?

function ResendEmailInvite(internalUserId, familyMemberId) {
theinternalUserId = internalUserId;
theFamilyMemberId = familyMemberId;
if(confirm('Are you sure you want to resend this family member's invite?')){
$.ajax({
type: "POST",
url:"/Admin/ResendFamilyMemberEmail",
data: {internalUserId : theinternalUserId, familyMemberId : theFamilyMemberId},
success: function(response){
alert(response);
},
error: function(){
alert("Error");
}
});
return false;
}
}
I am using ASP.net MVC 3.
This is an ajax/javascript method in my view.
As far as the syntax goes, is this correct?
The familyMemberId is going to be dynamic, however, the userId is not.
I want to pass the userId from my viewModel to this ajax call, how can I do this?
What you're wanting to do is get the data from the model in your controller into the view. This is what MVC is all about. From the MSDN MVC 4 Tutorial:
Controller:
You can define your model using the VS menu system and the Entity Framework so you're actually accessing the database.
public class YourController : Controller
{
private YourDBContext db = new YourDBContext();
public ActionResult YourAction(int user_id = 0)
{
User user = db.Users.find(user_id);
if(user == null) {
return HttpNotFound(); // Or unauthorized or whatever
}
return View(user);
}
//...
View:
#Model IEnumerable<MvcUser.Models.User>
<!-- other stuff -->
<script type="text/javascript>
// the rest of your script
function ResendEmailInvite(internalUserId, familyMemberId) {
theinternalUserId = #Model.userId;
theFamilyMemberId = familyMemberId;
if(confirm('Are you sure you want to resend this family member's invite?')){
$.ajax({
type: "POST",
url:"/Admin/ResendFamilyMemberEmail",
data: {internalUserId : theinternalUserId, familyMemberId : theFamilyMemberId},
success: function(response){
alert(response);
},
error: function(){
alert("Error");
}
});
return false;
}
}
This works because, as you pointed out, the userId is not dynamic after the page has loaded. You would need to create some other hook in your HTML for javascript to grab if you wanted really dynamic behavior.

Categories