I have a .Net method which does some validation on an object, and then, I need to display the issues to the user.
I am trying to use a jquery message box I found:
The jquery function:
function ShowPopup() {
$.msgBox({
title: "Unable to save",
content: "An error has occured while saving the object."
});
}
I need to call that from a .Net method, passing it a List of strings. Is that possible? And then set the content property to be the list of errors?
My .Net saving method, which may trigger this popup, looks like this:
protected void btnSave_Click(object sender, EventArgs e)
{
var o = new UserDto
{
DisplayName = txtName.Text,
Email = txtEmail.Text,
Username = txtUsername.Text,
Password = txtPassword.Text,
TimeZoneId = ddZones.SelectedValue,
Id = Session["SelectedUserId"] == null ? 0 : int.Parse(Session["SelectedUserId"].ToString())
};
var result = new UserService(Common.CurrentUserId()).SaveUser(o);
if (result.Success == false)
{
// Show an error.
return;
}
Response.Redirect("users.aspx");
}
If success is false, I want to pass it a list of errors, and show that popup.
The jQuery function is from here.
Try this
if (result.Success == false)
{
// Show an error.
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "close", "ShowPopup(parm1,parm2);", true);
return;
}
Hope it will helps you
You can use ClientScriptManager http://msdn.microsoft.com/es-es/library/asz8zsxy.aspx to inject your javascript into the page.
protected void btnSave_Click(object sender, EventArgs e)
{
var o = new UserDto
{
DisplayName = txtName.Text,
Email = txtEmail.Text,
Username = txtUsername.Text,
Password = txtPassword.Text,
TimeZoneId = ddZones.SelectedValue,
Id = Session["SelectedUserId"] == null ? 0 : int.Parse(Session["SelectedUserId"].ToString())
};
var result = new UserService(Common.CurrentUserId()).SaveUser(o);
if (result.Success == false)
{
// Define the name and type of the client scripts on the page.
String csname1 = "MessageBoxScript";
Type cstype = this.GetType();
// Get a ClientScriptManager reference from the Page class.
ClientScriptManager cs = Page.ClientScript;
// Check to see if the startup script is already registered.
if (!cs.IsStartupScriptRegistered(cstype, csname1))
{
StringBuilder cstext1 = new StringBuilder();
cstext1.Append("<script type=text/javascript> $.msgBox({title: 'Unable to save',content: 'An error has occured while saving the object.'}); </");
cstext1.Append("script>");
cs.RegisterStartupScript(cstype, csname1, cstext1.ToString());
}
return;
}
Response.Redirect("users.aspx");
}
Another option is to save your errors in a session variable like:
C#
Session["Errors"] = "My errors";
Javascript:
var errors = '<%=Session["errors"]%>';
if(errors){
$.msgBox({
title: "Unable to save",
content: errors
});
}
I'm assuming that your btn_Save method fires in response to a client event, such as the user clicking the Save button. I'm also assuming you're using MVC. If that's the case, then the best way to accomplish what you're looking for is to make the Save button on the client fire a $.click event. In the click event, you call your MVC controller Save method using ajax. This way, the Save method can return JSON from the server, and you can display the returned messages on the client. Something like this:
Server:
[HttpPost]
public ActionResult Save(object myData)
{
return Json(new {message="Hello World"});
}
Client:
$('#saveBtn').click(function()
{
$.post('#Url.Action("Save")',
{myData: data},
function(result){
if (result){
showPopup(result);
}
}
)
})
you can call your jQuery method with ScriptManager this way :
if (result.Success == false)
{
ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "tmp", "<script type='text/javascript'>ShowPopup();</script>", false);
return;
}
Related
I am new to MVC, I looked at other solutions to my problem on web but still I can't find what is wrong with my code, I'm using code (as is) from umbraco website, I'm trying to call a function and pass a var from js, I don't understand what is the problem..., tried to solve it with online examples but getting the same error... help
//c#
public class MokedLoginController : SurfaceController
{
[HttpGet]
[Route("umbraco/surface/MokedLogin/DoLogin/{id}")]
public void DoLogin([FromBody]int member)
{
var _member = Services.MemberService.GetById(member);
if (_member != null)
FormsAuthentication.SetAuthCookie(_member.Username, false);
}
}
//js
angular.module('umbraco').controller('MokedLoginController', [
'$scope',
'$http',
'editorState',
'contentResource',
function ($scope, $http, editorState, contentResource) {
// Check if you are creating a new member
$scope.isNew = editorState.current.id <= 0;
// Define the login as member function
$scope.loginAsMember = function () {
// ### Setup cookie ????
var url = '/umbraco/surface/MokedLogin/DoLogin/{id}';
// Get the current member id using the editorState
var _memberId = editorState.current.id;
// Do Login
$http.post(
url, _memberId
).then(
function (response) {
// ### Redirect ????
// Get the redirect page from config
var urlPageRedirect = $scope.model.config.memberRedirectPage;
// Check if page is set in the config
if (urlPageRedirect)
{
contentResource.getNiceUrl(urlPageRedirect).then(function (data) {
window.open(data, '_blank') // Get the first url
});
} else {
// Open the root page
window.open('/', '_blank');
}
},
function (error) {
console.log(error.data);
}
);
};
}
]);
// Do Login
$http.post(
// the famouse exception that comes from ? and why ?
System.ArgumentException: The parameters dictionary contains a null entry for parameter 'member' of non-nullable type 'System.Int32' for method 'Void DoLogin(Int32)'
in 'ThePoolInsurance.Web.Controllers.MokedLoginController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
VS2013, WebForms, .NET 4.51
I want to use a hidden field to maintain the contents of my Knock Out view model across postbacks. So I took the KO code from http://knockoutjs.com/examples/cartEditor.html and then read http://www.codeproject.com/Articles/153735/Using-KnockoutJS-in-your-ASP-NET-applications for some ideas.
The end result is the following:
<asp:HiddenField ID="HiddenField1" runat="server" />
<script type='text/javascript' src="http://knockoutjs.com/examples/resources/sampleProductCategories.js"></script>
<script type="text/javascript">
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function () {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function () {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
self.category.subscribe(function () {
self.product(undefined);
});
};
var Cart = function () {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function () {
var total = 0;
$.each(self.lines(), function () { total += this.subtotal() })
return total;
});
// Operations
self.addLine = function() {
self.lines.push(new CartLine());
SaveList();
};
self.removeLine = function(line) {
self.lines.remove(line);
SaveList();
};
self.save = function () {
var dataToSave = $.map(self.lines(), function (line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
self.SaveList = function () {
var myHidden = document.getElementById('<%= HiddenField1.ClientID %>');
if (myHidden)//checking whether it is found on DOM, but not necessary
{
var dataToSave = $.map(self.lines(), function (line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined;
});
alert("Saving - " + JSON.stringify(dataToSave));
myHidden.value = JSON.stringify(dataToSave);
}
};
};
var stringViewModel = document.getElementById('<%=HiddenField1.ClientID %>').value;
var viewModel;
if (document.getElementById('<%=HiddenField1.ClientID %>').value == '') {
alert('Nothing In Hidden Field');
viewModel = new Cart();
} else {
viewModel = ko.utils.parseJson(stringViewModel);
for (var propertyName in viewModel) {
viewModel[propertyName] = ko.observable(viewModel[propertyName]);
}
}
ko.applyBindings(viewModel);
$(document.forms[0]).submit(function () {
alert('In Submit');
viewModel.SaveList();
});
</script>
So basically when the page loads we create a new instance of the Cart. And when the form is posted we successfully have the cart serialized to HiddenField1 and I can see the expected value in the code behind:
protected void btnSave_OnClick(object aSender, EventArgs aE)
{
if (HiddenField1.Value == null)
{
}
}
however after the postback the contents of stringViewModel
var stringViewModel = document.getElementById('<%=HiddenField1.ClientID %>').value;
is always blanl / empty? Why is that?
And then assuming I have the correct JSON is the following the correct way to apply it back to the view model?
viewModel = ko.utils.parseJson(stringViewModel);
for (var propertyName in viewModel) {
viewModel[propertyName] = ko.observable(viewModel[propertyName]);
}
EDIT: I tried a few things with no luck
Added all JS code to jQuert OnReady() handler
Tried using instead of ASP:HiddenField
In all cases in PostBack I can see the value assigned to the hidden field by SaveList(), but when the page is displayed again (after postback) the value of the hidden field is an empty string
For the first part, what you're doing is correct. Use the console (press F12 in your browser) to examine the hidden field, and check if it has the value. If you see it in the server side, it should be in the client side. You can also run js code, and set breakpoints to discover what the problem is. You can also add a PreRender handler in the server side, and add a breakpoint and debug to check that the Value has not been deleted in the server side (this event happens just before the page is rendered to be sent to the browser).
For the second part, the fastest way to do what you need is to use knockout mapping, which creates a model from a JavaScript object, or from JSON. You need to use this: ko.mapping.fromJSON. This will create a new viewmodel, which you can directly bind, from your JSON. (As you can read in the docs, you can customize how the view model is created).
However, what you're doing is quite strange. You normally use Knockout with Web API, or Web Services, or Page methods, without reloading the page. The model is recovered, and updated, changed, etc. through one of those technologies, using AJAX.
I want to set the Image URL of Image control using client side code and save the image to the server using C# code. Here is what i have implemented:
<asp:Button ID="btnImageUpload" OnClick="btnImageUpload_Click" runat="server" Text="Preview" CausesValidation="false" OnClientClick="Image_View();"/>
C# Code:
protected void btnImageUpload_Click(object sender, EventArgs e)
{
if (Directory.Exists(#"C:\\Images"))
SaveImage_Server();
else
{
Directory.CreateDirectory(#"C:\\Images");
SaveImage_Server();
}
}
public void SaveImage_Server()
{
try
{
if (FlUpldImage.PostedFile.ContentLength > 0)
{
String fn = Convert.ToString(DateTime.Now) + Path.GetFileName(FlUpldImage.FileName);
if (fn.Contains('/'))
{
fn = fn.Replace("/", "");
}
if (fn.Contains(':'))
{
fn = fn.Replace(":", "");
}
if (fn.Contains(" "))
{
fn = fn.Replace(" ", "");
}
String Saved_ImagePath = #"C://Images/" + fn; // making the path with created dynamically folder name
FlUpldImage.SaveAs(Saved_ImagePath);
HidnLocalImageURL.Value = Saved_ImagePath;
}
}
catch (Exception re)
{
}
}
JavaScript
function Image_View() {
// __doPostBack('<%= btnImageUpload.ClientID %>', '');
// var clickButton = document.getElementById("<%= btnImageUpload.ClientID %>");
// clickButton.click()
var idFlUpload = '<%= FlUpldImage.ClientID %>';
var fu1 = document.getElementById(idFlUpload);
var idImgCntrl = '<%= imgCorrect.ClientID %>';
var ImgCntrl = document.getElementById(idImgCntrl);
alert("You selected " + fu1.value);
ImgCntrl.setAttribute('src', fu1.value);
}
Now my issue is that once the server side code is executed the page gets refreshed and the link set to Image control using JS gets reset to default value.
How can i get this working wherein the image also gets saved and Image URL property also gets set through JS.
If there is any other way to implement this than please let me know. Thanks in Advance!
You have to set it on server too. You can use hidden field to save the url and access that hidden field on server to get the url to set mgCntrl.ImageUrl
In html
<input type="hidden" runat="server" id="hdnImageSrc" />
On Client javascript
hdnImageSrc = document.getElementById('<%= hdnImageSrc.ClientID %>');
mgCntrl.setAttribute('src', fu1.value);
hdnImageSrc.value = fu1.value;
On server side code
mgCntrl.ImageUrl = hdnImageSrc.Value;
i am using AjaxRequest.Get() method from AjaxRequest.
following is the inline javascript in analysis.aspx
function getAnalysis(type) {
var innerHtml;
AjaxRequest.get(
{
'url': 'getAnalysis.aspx?type=' + type
, 'onSuccess': function (req) { innerHtml = req.responseText; }
}
);
document.getElementById("div_analysis").innerHTML = innerHtml;
}
when getAnalysis(type) is called in analysis.aspx everything goes fine - ajax request is properly submitted and response is send properly. But at the end value of innerHTML remains undefined.
Following is the code of getAnalysis.aspx -
protected void Page_Load(object sender, EventArgs e)
{
if(type == "somwthing") str = load();
Response.Clear();
Response.CacheControl = "no-cache";
Response.Write(str);
Response.End();
}
When i debugged javascript using google chrome, i found that value of innerHMTL is undefined, although everything went fine.
So i dont understand why AjaxRequest class is not accepting text output from Reponse.Write().
P.S. : I have also tried Response.ContentType = "text/Html"; and Reponse.Fluch().
please guide me thnx in advance.
You need to set the div contents in the onsuccess function since it is called asynchronously when the AJAX request completes
function getAnalysis(type) {
var innerHtml;
AjaxRequest.get(
{
'url': 'getAnalysis.aspx?type=' + type
, 'onSuccess': function (req) { document.getElementById("div_analysis").innerHTML = req.responseText; }
}
);
}
I've seen this question asked a few ways and the solutions are generally for other languages and don't apply to ASP.NET MVC 2.
I am using Jquery & Jquery forms to auto-save user data at a set interval. I still want the application to be able to time out, but the auto-saves via jquery forms keep refreshing the server.
My initial idea to fix this was pretty simple. I've already got an ActionFilter I use to see if the session expires. Well, the session won't ever expire; however, I just keep track of how many auto saves occurr based on a value in session and when it reaches a limit (specified in the web.config), it does a:
filterContext.Result = new RedirectResult("~/Account.aspx/LogOn");
Well, this doesn't work because the auto save is doing an ajaxFormSubmit to call the action in the first place. I've tried changing the action to redirect to the login page, but the same thing happens....it just doesn't do a redirect. The only thing the action can return is a Json result. In my latest version (code below) I'm setting the json return value to false and calling a redirectToLogin() function to send the page over to the login page. It doesn't work and i'm not sure why.
Any thoughts on this would be most helpful.
Excerpt of code that sets up the interval for autosaving on the view (placed just before the form is closed):
<%
double sessionTimeoutInMinutes = double.Parse(ConfigurationManager.AppSettings["SESSION_TIMEOUT_IN_MINUTES"].ToString());
double maxContiguousAutoSaves = double.Parse(ConfigurationManager.AppSettings["MAX_CONTIGUOUS_AUTO_SAVES"].ToString());
double autoSaveInterval = (sessionTimeoutInMinutes / maxContiguousAutoSaves) * 60 * 1000;
%>
<%= Html.Hidden("autoSaveInterval", autoSaveInterval) %>
<script type="text/javascript">
$(document).ready(function() {
var autoSaveFrequency = $('[id=autoSaveInterval]').val();
//alert(' Auto Save Interval in miliseconds: ' + autoSaveFrequency);
setInterval(
"initAutoSave('AutoSaveGoals', 'message')"
, autoSaveFrequency);
});
</script>
"AutoSaveGoals" goals is the name of one of my actions. It handles the post, updates certain items in session, and calls the repository.update. It is defined below:
[HttpPost]
public ActionResult AutoSaveGoals(Data data)
{
Data sessdata = Data();
sessdata.MpaGoals = data.Goals;
sessdata.MpaStatus = data.MpaStatus;
sessdata.StartPeriodDate = data.StartPeriodDate;
sessdata.EndPeriodDate = data.EndPeriodDate;
sessdata.AssociatePassword = data.AssociatePassword;
try
{
_repository.update(sessdata);
}
catch (Exception e)
{
LogUtil.Write("AutoSaveGoals", "Auto Save Goals Failed");
LogUtil.WriteException(e);
}
if (!autoLogOffUser(RouteData.GetRequiredString("action")))
return Json(new { success = true });
else
return Json(new { success = false });
}
The initAutoSave function is javascript that uses Jquery & Jquery Forms plugin. Here it is:
function initAutoSave(targetUrl, messageDivId) {
var options = {
url: targetUrl,
type: 'POST',
beforeSubmit: showRequest,
success: function(data, textStatus) {
//alert('Returned from save! data: ' + data);
if (data.success) {
var currDateAndTime = " Page last saved on: " + getCurrentDateAndTime();
$('[id=' + messageDivId + ']').text(currDateAndTime).show('normal', function() { })
}
else {
alert('redirecting to login page');
redirectToLogin();
//$('[id=' + messageDivId + ']').text(' An error occurred while attempting to auto save this page.').show('normal', function() { })
//alert('ERROR: Page was not auto-saved properly!!!!');
}
}
};
$('form').ajaxSubmit(options);
}
I try doing a javascript redirect in redirectToLogin() but it doesn't seem to get the url or something behind the scenes is blowing up. Here is how it's defined:
function redirectToLogin() {
window.location = "Account.aspx/LogOn";
}
best way to solve this is to have your code always return an Json result, i use a model called StandardAjaxResponse that has an ID, a Message and an answer answer is always false unless my code completes in the correct way and sets this to true. Any errors from try / catch are placed into the message field, so if !data.Answer and the Message is equal to not loggged in the you can then location.href to the login page, without getting the login page as your ajax response.
for example:
public class AjaxGenericResponse{
public bool Answer {get;set; }
public int Id {ge; set; } // this is for cases when i want an ID result
public string Mesage {get;set;} // this is so i can show errors from ajax
}
the controller / action
public JsonResult DoAutoSave(Data data){
var JsonResults = new AjaxGenericResponse{Answer=false};
// do code here to save etc
// no matter what always return a result, even if code is broken
return Json(model);
}
your Javascript:
$.ajax({
url:"",
dataTYpe: 'json',
success:function(data){
if(data.Answer) {
// all is good
} else {
if(data.Message === "logout') { href.location=('login'); } else { alert(data.Message); }
}
}
});
thats one solution anyway!
Stupid me. Thanks for your response minus, but I think our solutions coincided for the answer. My issue was I didn't have the right url to redirect to in the redirectToLogin method. I've made minor tweaks, and presto, its redirecting.
Javascript changes:
function redirectToLogin(url) {
window.location = url;
}
function initAutoSave(targetUrl, messageDivId) {
var options = {
url: targetUrl,
type: 'POST',
beforeSubmit: showRequest,
success: function(data, textStatus) {
//alert('Returned from save! data: ' + data);
if (data.success) {
var currDateAndTime = " Page last saved on: " + getCurrentDateAndTime();
$('[id=' + messageDivId + ']').text(currDateAndTime).show('normal', function() { })
}
else {
alert('redirecting to login page');
redirectToLogin(data.url);
//$('[id=' + messageDivId + ']').text(' An error occurred while attempting to auto save this page.').show('normal', function() { })
//alert('ERROR: Page was not auto-saved properly!!!!');
}
}
};
$('form').ajaxSubmit(options);
}
Action changes
if (!shouldAutoLogOffUser(RouteData.GetRequiredString("action")))
return Json(new { success = true, url = "" });
else
return Json(new { success = false , url = Url.Action("LogOff","Account").ToString() });
The shouldAutoLogOffUser checks a session variable that was updated by an action filter to track the # of contiguous auto saves and handles the logic to see if that value has exceeded the max # of contiguous autosaves allowed. The action filter checked the actionname for 'AutoSave' and if it found it, the counter was incremented. Otherwise the counter was reset to 0 (a non autosave post occurred).
One more random question. If this application were loaded in an IFrame and the window.location call is made, would the IFrame content be changed or the entire page (the container in essence) be changed? Our company is looking to run some of our asp.net mvc 2 apps in IFrame's via websphere portal (yeah, I know....it's not my choice).
Now this is just absurd...So, I was looking over my applications (I've got several going to QA soon) and noted that I've already solved this very question with a much better solution - it was ALL handled in an ActionFilter. I wanted this from the getgo when I asked this question, but to have already implemented it, forgot about that, AND ask again on Stack Overflow...well, I hope my memory issues helps somebody with this. Below is the full action filter code. As always, I'm open to criticism so mock it, revise it, copy it, etc, etc.
public class UserStillActiveAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
int sessionTimeoutInMinutes = int.Parse(ConfigurationManager.AppSettings["SESSION_TIMEOUT"].ToString());
int maxContiguousAutoSaves = int.Parse(ConfigurationManager.AppSettings["MAX_CONSEC_SAVES"].ToString());
int autoSaveIntervalInMinutes = int.Parse(ConfigurationManager.AppSettings["AUTO_SAVE_INTERVAL"].ToString());
string actionName = filterContext.ActionDescriptor.ActionName;
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
HttpContext currentSession = HttpContext.Current;
LogAssociateGoalsSessionStatus(filterContext.HttpContext, actionName);
if (actionName.ToLower().Contains("autosave"))
{
int autoSaveCount = GetContigousAutoSaves(filterContext.HttpContext);
if (autoSaveCount == maxContiguousAutoSaves)
{
var result = new RedirectResult("~/Account.aspx/LogOff");
if (result != null && filterContext.HttpContext.Request.IsAjaxRequest())
{
//Value checked on Logon.aspx page and message displayed if not null
filterContext.Controller.TempData.Add(PersistenceKeys.SessionTimeOutMessage,
StaticData.MessageSessionExpiredWorkStillSaved);
string destinationUrl = UrlHelper.GenerateContentUrl(
result.Url,
filterContext.HttpContext);
filterContext.Result = new JavaScriptResult()
{
Script = "window.location='" + destinationUrl + "';"
};
}
}
else
{
RefreshContiguousAutoSaves(filterContext.HttpContext, autoSaveCount + 1);
}
}
else
{
RefreshContiguousAutoSaves(filterContext.HttpContext, 1);
}
}
private int GetContigousAutoSaves(HttpContextBase context)
{
Object o = context.Session[PersistenceKeys.ContiguousAutoUpdateCount];
int contiguousAutoSaves = 1;
if (o != null && int.TryParse(o.ToString(), out contiguousAutoSaves))
{
return contiguousAutoSaves;
}
else
{
return 1;
}
}
private void RefreshContiguousAutoSaves(HttpContextBase context,
int autoSavecount)
{
context.Session.Remove(PersistenceKeys.ContiguousAutoUpdateCount);
context.Session.Add(PersistenceKeys.ContiguousAutoUpdateCount,
autoSavecount);
}
private void LogAssociateGoalsSessionStatus(HttpContextBase filterContext, string actionName)
{
AssociateGoals ag = (AssociateGoals)filterContext.Session[(PersistenceKeys.SelectedAssociateGoals)];
bool assocGoalsIsNull = false;
bool assocGoalsInformationIsNull = false;
if (ag == null)
{
assocGoalsIsNull = true;
assocGoalsInformationIsNull = true;
}
else if (ag != null && ag.AssociateInformation == null)
assocGoalsInformationIsNull = true;
}
}
always use double quote in java script and jquery to avoid browser specific issues
like
dataTYpe: 'json' must be as "dataTYpe:"json"