The title attempts to summarize the problem, but here's a more detailed summary: our web page is a collection of usercontrols, which visually render as rectangular reporting widgets, which are set in AJAX updatepanels. We are giving the user the ability to drag and drop the widgets to pre-set "zones" on the page.
The drag and drop functionality works fine. We use AJAX calls to a web service to update a database with the user's new settings for persistence.
The "however" happens when we do a postback from one of these widgets. The postback is sent to the server, it renders an update, which is sent back to the client (all via AJAX, because of the updatepanel). We then get a "Could not find UpdatePanel with ID..." message on the client, because the document hierarchy has changed, but the control IDs have not been updated on the client.
We tried Rick Strahl's solution to this link text, which allowed us to create static control IDs on the client. This breaks the postback functionality, though... the isPostBack property is not set, I'm assuming because the server can't match the control ID with a known hierarchy element.
We're thinking about possibly resetting the control ID on the client side after it's dragged and dropped, using Javascript. Obviously, this would require duplicating .Net's naming algorithm--not smart, we're thinking. Maybe we can use a separate updatepanel and ask the server to send us the new control ID after it's dropped?
Obviously, we're running out of ideas.
I realize this is probably too long, and I'll happily edit, provide code samples, etc. to help you help us. Thank you in advance.
Just out of interest, have you inspected the id of the UpdatePanel that posts back, and is the id one that is expected? You can hook into the client page lifecycle of ASP.NET AJAX like so to inspect the id of the control initiating the postback
<script type="text/javascript">
function pageLoad(sender, args)
{
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
//fires when an async postback is initialized
function InitializeRequest(sender, args)
{
alert(args._postBackElement.id)
}
//fires when an async postback is complete
function EndRequest(sender, args)
{
alert(sender._postBackSettings.sourceElement.id)
}
}
</script>
You could use ASp.Net's built in system for draggable page elements called WebParts.
The system works with postbacks and can be easily implemented with Visual Studio
Have a search for webparts tutorials such as:
http://www.ondotnet.com/pub/a/dotnet/2005/01/10/liberty.html
Hope this helps
Related
I want to make this scenario in javascript:
I have a main html pageA that contain an iframe with child html pageB.
PageB contain js code that submit results to the server using Ajax.
is there a way to make a listener in js code of pageA that can detect if result was submitted?
could you suggest me the best way to achieve this result?
Best regards,
I don't know much about iframes but this sounds like something you could do reasonably easy using Web sockets.
Essentially a Web socket will keep a live connection to the server, such that the server can inform the client of something happening (they're often used in chat applications for example). This differs to the usual whereby a request has to be issued from the client.
So in your example PageA could listen on a Web socket and when PageB sends a request the server then informs PageA via the Web socket.
By using Window.postMessage API.
Please check this out. https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
If one domen, from iframe:
window.parent.bla-bla();
If different domains:
Change fragment location in child iframe, for exam add #exicutebla-bla()
Detect iframe location in parent document, if location #exicutebla-bla() execute blba-bla()
Or
Use this: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
var myForm= document.getElementById('myframeId').contentWindow
.document.getElementById('myformid');
function detectSubmit() {
alert("submit event fired");
}
myForm.addEventListener(myiframe , 'submit', detectSubmit, false);
Note this will not detect script fired submit.
Cross domain issues may arise if the iframe source is that.
Lots of assumptions here due to the questions vague nature.
my web page has an optional contact panel that user can add input text for any contact, like cellphone or email,when user click create contact button, it make an input text with attributes like unique id(for example txtrelat1) or runat="server"(in client-side but web page has an input text with id="txtrelat0" by default) and when user click submit button ,calls register method in server-side by onserverclick event,
main question is,when i use form1.FindControl("txtrelat0"),it's find and i can convert it to HtmlInputText but when i want form1.FindControl("txtrelat1") it's not find and return null?
thank's all
FindControl finds server controls in the page or control currently executing. It deals only with server controls. The code behind can still read values posted from the inputs you add. You could call Request.Form["x"].
The downside is that if you add additional controls to the page and then do a postback the server page isn't going to "remember" the elements you added. They'll just disappear after the postback.
Mixing those types of client/server behaviors with webforms isn't fun. You might find it easier to do it with all server controls. Just set Visible="false" or "true" in your server code in response to server events. Or you could do it all on the client using API calls.
Even though I don't like webforms that much, when I have to work in a webforms project it's often easier to do things the webforms way with server controls.
I'm working on a project that uses IP Payments to process transactions. The project involves a web form written in ASP with Code-Behind written in C#.
IPP offers an iFrame implementation, where you can put an iFrame in your page and display a small IPP page with fields for entering credit card information. The idea behind this is that the credit card info will only be handled by IPP and never by the server running the page, thus there is no requirement to ensure that card data is kept secure.
In order to display the IPP page in the iFrame though, a session needs to be initiated with IPP. The server initiates the session, and passes in a SessionID variable. Upon a successful session initiation, a Secure Session Token is returned to the server. The server then needs to "force" the client's browser to GET or POST the SessionID and the SST (Secure Session Token) to the IPP website. This is where my problem is.
I wrote a Javascript function in the ASPX page that would accept two parameters - the SessionID and SST - and send them to the IPP website. I'm now trying to call this Javascript function from my C# code upon successful initiation of the IPP session. However, I have been completely unable to do so.
I've done a lot of searching, and the one answer I keep coming across is to use either RegisterStartupScript or RegisterClientScriptBlock. The problem is, these seem to insert text directly into the page, rather than calling an existing function. Assuming I inserted my function into the page via one of those functions rather than writing it into the page myself, it still doesn't solve my problem of how to call said function.
Now it is possible that I'm going about this the wrong way, and there's a much better way to get the client's browser to GET/POST the SessionID and SST; if so, please tell me. I'm inexperienced with web programming and am thus learning as I go and making up solutions along the way that are quite likely not ideal.
Thanks in advance.
I think this should work:
Lets say you have something like this in your HTML:
<html>
<head>
<script>
function sendValuesToIPP(sessionId, sst){
//do stuff
}
</script>
</head>
</html>
If you do this in your C# code it should work
ClientScriptManager.RegisterStartupScript(
this.Type,
"some_key_you_want_to_identify_it",
string.Format("sendValuesToIPP('{0}','{1}')", SessionID, SST),
true);
Keep in mind that I'm assuming you have SessionID and SST properties server side, you can get them from wherever you want and just add them to the string that will actually call the function when registered in your ASPX.
I am working on a MVC project that is supposed to have one page only, with two zones. On one zone I have a Google Map with markers, and the second zone is populated with the selected marker's details.
The details view has a button that when clicked should change the entire view into edit mode without refreshing the page or redirecting it. I have used two views, for details and edit and with the help of ajaxForm function I am switching back and forth between these two views. I'm adding the ajaxForm on documentready for edit view.
<script type="text/javascript">
// wait for the DOM to be loaded
$(document).ready(function() {
// bind 'myForm' and provide a simple callback function
$('#currentDiv').ajaxForm(function(data) {
$('#currentDiv').html(data);
});
});
</script>
The problem appears when on server-side an error appears while trying to save data from edit view and I want to return to the same edit view with the errors displayed. The ajaxForm handler is not added any more and even if the new values that will try to be saved are ok, the detail view is loaded in another page.
Unfortunately, the use of ajaxForm creates some other problems because I don't have control over the cases when the ajax call fails.
Any ideas on how could I fix this? Is it some other solution to switch between those two views without using ajaxForm and without refreshing the page?
I think there are a couple of different questions that you are asking.
First off, you add jquery handlers to deal with the case when you get a 500 type error from the server.
Something like the following. I suggest taking a look at the docs for more info.
$(document).ajaxError(function(event,jqXHR,ajaxSettings,thrownError){
if (jqXHR.status != 0){
window.location = <error page>
}
}
The second problem seems to stem around error handling of known errors (say invalid input). In this case I suggest the following workflow.
1) User clicks on edit button, taken to edit screen
2) User enters in data, use client side validation to do initial check
3) User submits, user is then taken to the view screen and is shown a
success or error message.
The server response could look like:
public ActionResult Edit(EditModel model){
if (!ModelState.IsValid)
{
return Json(new {successful = false, message = "Failed.."});
}
...
}
On the client side, your form callback should now handle the message and the fact it was successful or not. In my implementation, I used knockoutjs to create a "message" area that I could update and clear. (I created templates, etc).
Remember to use client side validation for the easy field validation stuff.... This will save a trip back to the server.
Yours could be quite simple, by popping up the message returned from the server.
Lastly, document ready only fires when the original document is done loading, never again for an ajax call (at least that is my understanding). Just put that code that is the document.ready at the bottom of the edit page. It will fire after the html it is targeting has already been rendered.
Hope that helps!
I have begun to move away from the asp.net views available in ASP.Net MVC due to some incompatibilities and/or unnecessary complexities when trying to achieve functionalities expected of AJAX enabled sites of the day.
I would recommend moving towards a design where you use "dumb" HTML files, use jQuery to download them using AJAX and drop them into a container (personally I use a div) and then use another AJAX call to gather the data from a controller. There are a number of advantages to this approach:
It establishes a real (not fake) separation between client side and server side code.
Html files can be cached on the client cutting down on the amount of data transmitted.
Binding of the Html elements becomes a client side task achieved using jQuery offloading processing cycles from the server.
Controllers essentially become collections of web methods which means they can be untilized by iPhone and Android apps making mobile deployment easier.
I realize this probably isn't the exact answer you're looking for and this may not be an option for you but my hope is that it will help someone at some point make a decision to move away from mixing HTML and server side code.
My page has a submit button on it (server-side button).
Here's my code for the click event:
protected void SubmitButton_Click(object sender, EventArgs e)
{
db.SaveSomething();
Page.ClientScript.RegisterStartupScript("someScriptWhichReliesOnServerData");
Response.Redirect("SomeOtherPage.aspx");
}
Now, the problem is, i register the JavaScript using Page.ClientScript.RegisterStartupScript, but this will have no effect as the page is not being re-rendered on postback (which is where the script WOULD be executed), because instead a Response.Redirect happens.
The only solution i can think is to make the page i redirect to "aware" that im trying to execute some JavaScript, be it QueryString, HttpContext.Current.Items, or (gulp) Session.
QueryString - not an option, as it's JavaScript im trying to execute.
HttpContext.Current.Items - also not an option because im doing a Response.Redirect (which loses the request-level data, and i also cannot use Server.Transfer because this doesn't play nice with URL Rewriting).
Session - of course, but not ideal.
Any other ideas/suggestions?
EDIT for Clarification:
The JavaScript im executing is a call to a Facebook client-side API to publish to the user's wall. It has to be done client-side. I pass to the script things like "title", "message", "action links", etc. Basically a bunch of JSON. But the key here is that this data is created on postback, so i cant just execute this function on client-side click.
So what im trying to accomplish is on submit button click, execute some javascript and do a redirect (does not have to be in that order, just both need to happen).
I think what you are experiencing is the unfortunate clashing of two different paradigms here. On the one side you have an AJAX style API you want to take advantage of, and on the other side you have the ASP.Net page postback model.
Now, while these two are not mutually exclusive, it can present some challenges. I agree with Dan that your best bet is to bend a little more towards the AJAX approach instead of the other way around.
A nice feature in ASP.Net is the ability to turn a single static method in your page into a pseudo web service. You can then use the ScriptManager to generate client-side proxy classes to call that method for you, but you can use whatever client side library you want.
A very simple example:
In your codebehind for you Page
[WebMethod]
public static Person GetPerson(Int32 id, String lastName)
{
return DataAccess.GetPerson(id, lastName);
}
If you were using the ASP.Net AJAX library to handle this for you, then you would need to enable page methods to generate the client-side proxies.
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
Then you could call that from client-side script like so:
function CallGetPerson()
{
var id = $get("txtPersonId").value;
var lastName = $get("txtLastName").value;
// PageMethods is a class that is part of the ASP.Net AJAX
// client-side libraries and will contain your auto-generated
// proxy methods for making XHR requests.
PageMethods.GetPerson(id, lastName, OnGetPersonComplete);
}
function OnGetPersonComplete(result)
{
faceBookApi.DoSomeStuffWithJson(result);
window.location = "NewPage.aspx";
}
Now again, this is a contrived example, and what you are posting to the server may be very complicated, but you get the general idea of what can be accomplished using the built in framework components.
I hope this helps.
If you use Response.Redirect, the java script you registered at the previous line will not executed. I think what you want to do after clicking the submit button is:
Save something
Execute javascript
Redirect to another page
Here you can use:
protected void SubmitButton_Click(object sender, EventArgs e)
{
db.SaveSomething();
Page.ClientScript.RegisterStartupScript("someScriptWhichReliesOnServerData");
Page.ClientScript.RegisterStartupScript("window.location.href=XXXXXX");
}
That is, using javascript to redirect the page instead of Response.Redirect.
Could you run the JavaScript on the second page?
Other than that, your options are somewhat limited. You could use AJAX to get the data you need from the server and then redirect. That would improve the UX since at the very least you wouldn't have extra page loads to run your intermediary JavaScript.
Another option would be to use Server.Transfer(...), which works similarly to Response.Redirect, but it doesn't send a redirect header to the client. It simply tells the server "stop running the current page and start executing a new page". Context.Items will remain in scope between the 2 classes because you're only transferring the responsibility of responding to the request, not the entire context of the request.
You could also combine these 2 solutions. Use Server.Transfer to keep Context.Items values in scope and then render the JS on the second page using whatever values you kept from the first page.