For my company, we are building a web application for an invoicing system which utilises a notification bar, similar to that of Facebook, whereby the user can drop down a menu which displays the status of transactions on the system while a total number of outstanding transactions displays next to it. Please see the image for details.
http://img210.imageshack.us/img210/4379/alertdrop.png
We are retrieving the data for this using the following code for the table within the drop-down menu:
<table id="alertDropTable" style="margin-top:10px;">
#{
Dictionary<string, int> dic = ViewBag.statusCount;
if (dic != null)
{
for (int i = 0; i < dic.Count; i++)
{
if (dic.Values.ElementAt(i) > 0)
{
<tr>
<td width="100%" style="padding-bottom:4px; padding-top:4px; padding-left:10px; padding-right:10px; vertical-align:middle;">
You have <strong><a style="background-color:#878787; border-radius:5px; color:White; padding:3px;">#dic.Values.ElementAt(i)</a></strong> #dic.Keys.ElementAt(i) transaction(s).
</td>
</tr>
}
}
}
}
</table>
And the following for the span, which displays the total:
<div style="float: left;">
<img src="#Url.Content("~/Content/images/alert_notification.png")" name="alert" alt="alert"/>
#{
Dictionary<string, int> dicheader = ViewBag.statusCount;
int diccount = 0;
if (dicheader != null)
{
for (int i = 0; i < dicheader.Count; i++)
{
if (dicheader.Values.ElementAt(i) > 0)
{
diccount = diccount + #dicheader.Values.ElementAt(i);
}
}
}
}
</div>
<div id="alertTotalDiv" style="float:left;margin-top:6px; margin-left:5px;"><span id="alertTotal" style="vertical-align:middle; background-color:#878787; border-radius:5px; color:White; font-family:Georgia; font-size:20px; padding:3px; padding-left:5px; padding-right:5px;margin-top:0px;">#diccount</span></div>
This code is currently stored in the global "_layout.cshtml" file. Please excuse the roughness of the code, this is very much an early version. However, this is working fine in terms of retrieving the data on a page load. However, the system requires this information to be automatically updated every few seconds without refreshing the entire page. In essence, making a call to the controller to bring back the current data and update the <table> and <span> with the current values.
I have been asked to create an Ajax function which retrieves the data from the "AlertController" and updates the view accordingly. Please find the contents of this controller below:
public class AlertController : Controller
{
/// <summary>
/// Gets or sets the user service contract.
/// </summary>
/// <value>The user service contract.</value>
public IUserServiceContract UserServiceContract { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="BaseController"/> class.
/// </summary>
protected AlertController()
{
this.UserServiceContract = Gateway.Instance.Resolve<IUserServiceContract>();
}
/// <summary>
/// Get the AlertTypes
/// </summary>
/// <returns></returns>
public virtual void ViewAlerts()
{
Gateway.Instance.Logger.LogInfo(string.Format("Overview Controller View: Fetching list of alerts."));
try
{
if (this.UserServiceContract != null)
{
var allAnnouncements = this.UserServiceContract.GetAnnoucements();
var userAlertSettings = this.UserServiceContract.GetUserAlert();
ViewBag.statusCount = userAlertSettings;
ViewBag.announcements = allAnnouncements.ToList();
}
}
catch (Exception ex)
{
Gateway.Instance.Logger.LogInfo(ex);
throw new Exception(string.Format("Home Controller View Error: {0} occured while fetching alerts.", ex.Message), ex);
}
}
I am stumped, but have been given the following example of an Ajax function, which is used to perform a different task entirely, to aid me:
$.ajax({
url: '#Url.Action("ViewAlerts", "Alerts")',
data: { ownerIds: ownerIds },
traditional: true,
dataType: 'json',
success: function (result) {
for (i = 0; i < ownerIds.length; i++) {
$(".ownersTable tr[id='tablerow+" + ownerIds[i] + "']").remove();
}
},
error: function (xhr, ajaxOptions, thrownError) {
$("#confirmDiv").alertModal({
heading: '#Language.Fail',
body: '#Language.AlertRemoveOwnerFailed' + thrownError
});
}
});
Thus far, the only thing I've managed to get working was a set interval function, which makes an alert every 5 seconds!
Any guidance on this?
Okay, this is what you are going to need to do, first of all:
$.ajax({
url: '#Url.Action("ViewAlerts", "Alerts")',
data: { ownerIds: ownerIds },
traditional: true,
dataType: 'json',
success: function (result) {
for (i = 0; i < ownerIds.length; i++) {
$(".ownersTable tr[id='tablerow+" + ownerIds[i] + "']").remove();
}
},
error: function (xhr, ajaxOptions, thrownError) {
$("#confirmDiv").alertModal({
heading: '#Language.Fail',
body: '#Language.AlertRemoveOwnerFailed' + thrownError
});
}
});
Why is Url.Action in quotes? Just put #Url.Action ... I don't see a reason for the quotes and it may be breaking your call.
Second of all don't use ViewBag. It shouldn't be really used to hold 'data' (in my opinion). You should use a model. So this is what you can do:
Create the part of the page you want to update into a "Partial View" that is strongly typed to a model that contains the status and announcements and whatever else you need.
Use Jquery to 'Load' the Controller method that will get the data and return this 'Partial View', and load it into a Div on your screen example:
$('#div-to-load-into').load('/myactionurl/', function () { //Do something when done });
So your controller is then called, gets the data and returns the partial view with the model you created!
Good luck!
---Edit--- YOU should do above because it would be easier and faster (and if you do get to redesign you will quickly understand that, but here is an idea of how to do what you want)
This is what you need to know,
url is the action that the Ajax is going to call. You need to put url: '/controller/action'
data is the data you are sending to that action { parameter-name: parameter } it looks like in your case your sending no data because your only polling for a refresh, so you don't need to include this
dataType is the data you are expecting to be returned, it could be 'html' or 'json' , in your case your returning nothing because your using the 'ViewBag'
success will be called if the ajax call was successfully called with no errors with the result of that in 'result', in your case you have no result, because your using the view bag.
Now I can't promise this will work because I have never tried it:
function(result)
{
var updated_values = #Html.Raw(Json.Encode(ViewBag.AlertStatus))
}
Inside your success function on the ajax try this, this may or may not work. I honestly don't know if the ViewBag will have the updated values or not. At this point you only need to replace the table values with your new ones! you'll have to do all that in javascript, and I suggest looking at functions like 'appendTo', 'replaceWith', 'html' ect that are in Jquery to figure out how to do that.
$.ajax({
url: 'controller/action',
success: function (result) {
var alert_info = #Html.Raw(Json.Encode(ViewBag.AlertStatus))
},
error: function (xhr, ajaxOptions, thrownError) {
//error handling
}
});
(function checkStatus() {
$.ajax({
url: '#Url.Action("ViewAlerts", "Alerts")',
data: { ownerIds: ownerIds },
traditional: true,
dataType: 'json',
success: function (result)
{
for (i = 0; i < ownerIds.length; i++)
{
$(".ownersTable tr[id='tablerow+" + ownerIds[i] + "']").remove();
}
},
complete: function() {
// Schedule the next request when the current one's complete
setTimeout(checkStatus, 5000);
}
});
})();
How to fire AJAX request Periodically?
In order to get data from an action to JavaScript, your action must return data. Right now your "action" is not really an action, as it returns void and sets ViewBag properties, which are not accessible from JavaScript. So your action needs to be something more like:
[HttpGet]
public ActionResult Alerts()
{
IEnumerable alerts;
// ...code which gets data into alerts
return JsonResult(alerts);
}
Obviously I don't know your domain, so I don't know how you would structure the data coming back, but the basics are there. The $.ajax call would point to the action route (in this case, probably '/Alert/Alerts'). The success function would have the data argument with the appropriate array of objects. From there you'd update your DOM with the data.
Related
This is the site.js code I am using to insert the PartialView into the main View.
$("#btn2").click(function () {
$.ajax({
url: "/Home/RefreshDoors",
datatype: "text",
type: "POST",
success: function (data) {
$('#DoorBox').html(data);
},
error: function () {
$("#DoorBox").html("ERROR");
}
});
});
I want to place the resulting table inside a box (div with the id="DoorBox") however as a result I get a raw view of the returned Door-Json-Objects:
(imgur-link to screenshot)
This is the div-code inside the view:
<div id="DoorBox">
</div>
This is the code from the HomeController I use to render the PartialView:
[HttpPost]
public PartialViewResult RefreshDoors()
{
return PartialView("_Doors", RefreshDoorsFunction().Result);
}
How do I get the code to insert the PartialView (just a table with the properties of the door-model displaying the doors)) to render within the div-box (without refreshing the page)?
Edit: Here is the code from the RefreshDoorsFunction():
public async Task<List<NewDoor>> RefreshDoorsFunction()
{
string token = await _auth.GetTokenAsync();
_doorList = SecureRestCall.GetDoorListAsync("https://exampleapi.azurewebsites.net", token);
return _doorList.Result;
}
I got the answer. Turns out I'm just stupid: I used the wrong button to test the ajax function (wrong id assigned to the button). It works now. Sorry for wasting some people's time.
I think this will be a weird one for you as I am at my wits end with this. On a screen I have in a table, I have a link being clicked that is setting off a javascript/ajax request. I have similar code in another screen that works perfectly as it heads down into the success part of the ajax call and runs code in the success portion of the call. For some reason though I can't seem to get this to work and when I debug it in chrome, I lose my breakpoints and it never seems to get into the success portion of the Ajax call.
#section scripts{
<script>
// Get the bond ID Data from the row selected and return that to the program.
function getIDData(el) {
var ID = $(el).closest('tr').children('td:first').text();
var iddata = {
'ID': ID
}
console.log(iddata);
return iddata;
}
// Submit the data to a function in the .cs portion of this razor page.
$('.updatelink').click(function () {
var bondid = JSON.stringify(getIDData(this));
$.ajax({
url: '/Maintenance/Bond_Maint?handler=UpdateandReloadData',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
type: 'POST',
dataType: 'json',
data: { bondid: bondid },
success: function (result) {
if (result.pass != undefined) {
document.forms[0].submit();
}
},
});
});
</script>
}
The ASP.net code behind that is calling does an update to the database and then passes back a variable containing Success as its message.
//-------------------------------------------------------------------------------
// Try to get and insert the data from a selected row and copy it
//-------------------------------------------------------------------------------
public ActionResult OnPostUpdateandReloadData(string bondid)
{
return new JsonResult(new { pass = "Success" });
}
I'm not sure how else to describe my issue other than when I debug my other code via the browser, it appears to take a different path than this code does and I cannot fathom why. For reference my other code looks like this:
#section scripts{
<script>
// Get the offender ID Data from the row selected and return that to the program.
function getIDData(el) {
var ID = $(el).closest('tr').children('td:first').text();
var iddata = {
'ID': ID
}
console.log(iddata);
return iddata;
}
// Submit the data to a function in the .cs portion of this razor page.
$('.copybtn').click(function () {
var offenderid = JSON.stringify(getIDData(this));
$.ajax({
url: '/Copy_Old_Account?handler=CopyData',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
type: 'POST',
dataType: 'json',
data: { offenderid: offenderid },
success: function (result) {
if (result.path != undefined) {
window.location.replace(result.path);
}
},
});
});
</script>
}
Any help would be appreciated.
Okay guys so first off, thank you everyone for responding to my question. Frank Writte and Alfred pointed me into the right direction by looking for the status in the network tab for my calls. I found out that I was getting cancellations for my requests. After looking into that I found this article What does status=canceled for a resource mean in Chrome Developer Tools? that has an answer from FUCO that gave me what I needed to do. Apparently I needed to add event.preventDefault(); in front of my ajax call and all of a sudden my code worked. I'm not sure I completely understand why this works but I can't complain about the results. Again thank you everyone for trying to help. This one has been boggling my mind all morning.
How to auto refresh a partial view?
public PartialViewResult Chat(string people)
{
if (User.Identity.IsAuthenticated)
{
var model = new MessageVM()
{
realReceiver = people,
messageList = db.messages.Where(x => x.sender == User.Identity.Name || x.sender == people).ToList().Take(30)
};
return PartialView("_Chat", model);
How to auto refresh this partialview
Just to test quickly, change your controller action for Chat from POST to GET. Then call it by pasting the address in your browser address bar. You can include the value for people parameter like this at the end of the URL:
?people=valueForPeople
Check the returned HTML and ensure that is what you are expecting. Once you have confirmed the action is returning the HTML you want, then you can change back to POST if you prefer. Then use the jQuery code below.
One option is to setup a timer on the client side which will call your controller and then you can do whatever you need with the returned data.
window.setInterval(function() {
// send get request to server
$.ajax({
url: '/Chat',
type: "POST", // or use GET
data: whateverYourArgumentsAre, // people
success: function (partialViewHtml) {
$("#divLt").html(partialViewHtml);
});
},
error: function () {
alert('Something went wrong');
}
});
}, 5000); // Every 5 seconds, 5000 ms
Html.Action("Messages","Chat", new { people= "give some data"})
I've a Method in the code behind of my aspx page, I need to call Two methods from Javascript, the problem that I'm Having is that I was trying to do it with a Json request and a WebMethod, but this method has to be static and the page components and other methods cannot be accessed from this method.
I was trying something Like:
javascript Function
function Func(Value) {
var conf=confirm('Sure? '+valor)
if (conf==true)
{
BlockAction();
}
}
function BlockAction() {
$.ajax({
type: "POST",
url: 'frmVentaTelefonica.aspx/BlockAction',
data: "",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$("#divResult").html("success");
},
error: function (e) {
$("#divResult").html("Something Wrong.");
}
})};
Code-behind code:
[WebMethod]
public static void BlockAcction()
{
try
{
frmVentaTelefonica venta = new frmVentaTelefonica();
venta.ConsultarVentaTelefonica();
venta.ImprimirTiquetes();
}
catch (Exception e)
{
throw;
}
}
I want to call those two methods when the confirm is true.
Update:
In need to accesses to two methods like this:
public void ConsultarVentaTelefonica()
{
DatosImpresion = new List<Impresion>();
IServicioVentas servicioVentas;
servicioVentas = SATWebServiceLocator<IServicioVentas>.ObtenerServicio();
string Tiquetes = string.Empty;
foreach (GridDataItem dataItem in gridInfoVentaTelefonica.MasterTableView.Items)
{
if ((dataItem.FindControl("CheckBox1") as CheckBox).Checked)
{
Tiquetes = Tiquetes + (dataItem["Tiquete"]).Text + ",";
}
}
Tiquetes = Tiquetes.TrimEnd(Tiquetes[Tiquetes.Length - 1]);
Tiquetes = " " + Tiquetes + " ";
DataSet dsResultado = servicioVentas.EntregaTelefonica(sessionR8A.Turno.IdTurno, Tiquetes);
if (dsResultado.Tables.Count > 0 && dsResultado.Tables[0].Rows.Count > 0)
Just run it when is true, those methods update in the database and print a ticket(first reading a grid checked items)
If you are trying to update the UI controls, or read their values, then what you are describing is the UpdatePanel control. A page webmethod cannot update any control and refresh the UI (unless through JavaScript). If you want to update the state of the page async, UpdatePanel is what you are looking for.
If you are trying javascript just because you dont want to refresh the page, then go for Update Panel . The answer for your question is 'No' you cant access non-static methods like how you want to do.
The reason it supports only static methods is that page instantiation is not done, if you want to use non static web methods then go for web service(.asmx).
I've googled this up and checked all over StackOverflow but I must be missing something... I have unobtrusive jQuery that hijaks a simple button click. It counts up the checkboxes and adds each checked boxes value to an array. The list is correct when I use an alert box in jQuery but the array never makes it to the controller side. The code flows to the controller but I break on var resolutionViewModel=new ResolutionViewModel(); and check trans - the argument is null. I'm new to jQuery and could really use the help here.
jQuery
// Return the selected transactions
function resolveTransactions() {
$('#btnResolve').click(function() {
var selectedTransactions = new Array();
$('input[name="chkTransaction"]:checked').each(function() {
selectedTransactions.push(this.value);
});
if (selectedTransactions.length > 0) {
$.ajax({
type: 'POST',
dataType: 'json',
url: 'http://localhost/AuditLog/Home/ResolutionFormDisplay',
contentType: 'application/json; charset=utf-8',
data: {trans : selectedTransactions},
traditional: true,
success: function (data) { alert(data); },
error: function(xhr, status, errorThrown) { alert("Error: " + errorThrown); }
});
}
});
};
Controller side
[HttpPost]
public PartialViewResult ResolutionFormDisplay(List<string> trans)
{
var resolutionViewModel = new ResolutionViewModel();
// fill Usernames dropdown selector in ViewModel
// fill Status dropdown selector in ViewModel
// fill list of transactionIds in ViewModel
return PartialView("_ResolutionDialog", resolutionViewModel);
}
Try having your controller accept a List, rather than just a single string (since you're not passing a single string):
[HttpPost]
public PartialViewResult ResolutionFormDisplay(List<string> value)
{
var resolutionViewModel = new ResolutionViewModel();
// fill Usernames dropdown selector in ViewModel
// fill Status dropdown selector in ViewModel
// fill list of transactionIds in ViewModel
return PartialView("_ResolutionDialog", resolutionViewModel);
}
Posted JSON needs to have named properties matching parameters in your controller method. Check the 'network' tab in Chrome dev tools and see exactly what you're posting, it's probably something like this:
"{\"value\":\"...\"}"
There is no value property to pass to your controller method's value parameter. I think the best would be just to get rid of the `JSON.stringify" and accept a list like Colin's answer, but if you want to take it as a string, the JSON string needs to be the value property of an object, not the other way around:
data: {value : JSON.stringify(selectedTransactions)},
Try passing your array as follows:
data:"{'trans':" + JSON.stringify(selectedTransactions)+"}"
Your method should be as follows:
public void Method(List<string> trans)
{
//Your implementation
}
SOLUTION:
The $.ajax postback was not sending properly formatted data to the controller. I discovered this by using the network tab in IE and looking at the Request Body of the POSTed http. It looked like this:transaction_table_length=10&chkTransaction=22&chkTransaction=23 -- It should have looked like this: {"trans":["22","23"]}. To solve this issue I stringified the property name and array as shown below, changed the dataType to 'text', and made the parameter on the controller action method take a String[] trans.
jQuery
// Return the selected transactions
function resolveTransactions() {
$('#btnResolve').click(function() {
var selectedTransactions = new Array();
$('input[name="chkTransaction"]:checked').each(function() {
selectedTransactions.push(this.value);
});
if (selectedTransactions.length > 0) {
$.ajax({
type: 'POST',
dataType: 'text',
url: 'http://localhost/AuditLog/Home/ResolutionFormDisplay',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ trans:selectedTransactions }),
traditional: true,
success: function (data) { alert(data); },
error: function(xhr, status, errorThrown) { alert(" Error: " + errorThrown); }
});
} else {
alert('You must select (check) at least one transaction to apply a resolution.');
return false;
}
return false;
});
};
MVC 4 controller action
[HttpPost]
public PartialViewResult ResolutionFormDisplay(string[] trans)
{
var resolutionViewModel = new ResolutionViewModel();
// fill Usernames dropdown selector in ViewModel
// fill Status dropdown selector in ViewModel
// fill list of transactionIds in ViewModel
return PartialView("_ResolutionDialog", resolutionViewModel);
}