I have a page hierarchy as the following
I want to execute a PageMethod if I click the 'SAVE' button, so I coded like the following
On Button Click I called
OnClientClick="return btnSaveAS_Clicked()"
Called the following on PageLoad of the inner user control
private void RegisterJavaScript()
{
StringBuilder jScript = new StringBuilder();
jScript.Append("<script type='text/javascript'>");
jScript.Append(#"function btnSaveAS_Clicked() {
var txtConditionName = document.getElementById('" + txtConditionName.ClientID + #"').value;
PageMethods.Combine('hello','world', OnSuccess);
function onSuccess(result)
{
alert(result);
}
}");
jScript.Append("</script>");
Page.ClientScript.RegisterStartupScript(this.GetType(), "conditions_key", jScript.ToString());
}
Coded page method as
[WebMethod]
public static string Combine(string s1, string s2) {
return s1 + "," + s2;
}
But it gives the following error...
You cannot define page methods in ascx pages. You have to define them in your web form. If you want to have a page method, defined in your user control, you'd have to define a forwarding page method in you aspx page like below (source):
in user control:
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static string MyUserControlPageMethod()
{
return "Hello from MyUserControlPageMethod";
}
in aspx.cs page:
[WebMethod]
[ScriptMethod]
public static string ForwardingToUserControlMethod()
{
return WebUserControl.MyUserControlMethod();
}
and in aspx page:
function CallUserControlPageMethod()
{
PageMethods.ForwardingToUserControlPageMethod(callbackFunction);
}
Alternatively, you could use ASMX services and jquery ajax methods (jQuery.ajax, jQuery.get, jQuery.post) to call your methods asynchronously (sample).
Another option would be defining http handlers and call them via jQuery as well (tutorial).
Related
I am adding a JavaScript function in WebView like this (Kotlin):
val webView = findViewById(R.id.webview) as WebView
webView.getSettings().setJavaScriptEnabled(true)
webView.addJavascriptInterface(this, "android")
webView.getSettings().setBuiltInZoomControls(false)
webView.loadUrl(url)
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
webView.loadUrl("javascript:(function captchaResponse (token){" +
" android.reCaptchaCallbackInAndroid(token);" +
" })()")
}
}
The function works fine, but the problem is that it runs immediately, when I add it in WebView. I only want to include it as a JavaScript function and it should be called only from the HTML, when the user will fill the reCAPTCHA. How can I do that?
In order to run your reCaptchaCallbackInAndroid exposed method from JavaScript, when the user submitted a successful reCAPTCHA response, first make sure, to actually listen to the reCAPTCHA callback via g-recaptcha tag attributes:
<div class="g-recaptcha"
data-sitekey="{{your site key}}"
data-callback="myCustomJavaScriptCallback"
></div>
or via the reCAPTCHA v2 JavaScript API:
grecaptcha.render(
'g-recaptcha-element-id', {
sitekey: '{{your site key}}',
callback: 'myCustomJavaScriptCallback'
}
)
then, when the page finished loading in the WebView, add your JavaScript callback function to the window object using webView.loadUrl:
webView.loadUrl("""
javascript:(function() {
window.myCustomJavaScriptCallback = function(token) {
android.reCaptchaCallbackInAndroid(token);
}
})()
""".trimIndent())
and finally, when the user submits a successful reCAPTCHA response, your myCustomJavaScriptCallback will be called and through that, your exposed reCaptchaCallbackInAndroid method too with the reCAPTCHA token.
Since you're using Kotlin, in this case, you can just simply use multiline string literals.
Since you're exposing a method to JavaScript, make sure to know the security concerns.
In case you'll need additional JavaScript injection in the future (more method exposure, DOM manipulation, etc.), check out this post.
In your case:
Set reCAPTCHA to call your captchaResponse JavaScript function via tag attribute:
<div class="g-recaptcha"
...
data-callback="captchaResponse"
...
></div>
or via its API:
grecaptcha.render(
'...', {
...
callback: 'captchaResponse'
...
}
)
and add your captchaResponse callback function to window:
webView.loadUrl("""
javascript:(function() {
window.captchaResponse = function(token) {
// your code here before the Android callback...
android.reCaptchaCallbackInAndroid(token);
// ...or after the Android callback
}
})()
""".trimIndent())
Test:
Here's a simple, Empty Activity in Android Studio (using Kotlin) with a basic LinearLayout (an EditText and a Button within the layout) and the MainActivity.kt:
package com.richrdkng.injectjsintowebview
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.webkit.JavascriptInterface
import kotlinx.android.synthetic.main.activity_main.*
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sendButton.setOnClickListener { loadWebpage() }
}
#Throws(UnsupportedOperationException::class)
fun buildUri(authority: String) : Uri {
val builder = Uri.Builder()
builder.scheme("https")
.authority(authority)
return builder.build()
}
#JavascriptInterface
fun reCaptchaCallbackInAndroid(token: String) {
val tok = token.substring(0, token.length / 2) + "..."
Toast.makeText(this.applicationContext, tok, Toast.LENGTH_LONG).show()
}
fun loadWebpage() {
webView.getSettings().setJavaScriptEnabled(true)
webView.addJavascriptInterface(this, "android")
webView.getSettings().setBuiltInZoomControls(false)
webView.loadUrl("https://www.richrdkng.com/recaptcha-v2-test/")
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
webView.loadUrl("""
javascript:(function() {
window.onCaptchaSuccess = function(token) {
android.reCaptchaCallbackInAndroid(token);
}
})()
""".trimIndent())
}
}
}
}
then using a simple reCAPTCHA v2 test website, the window.onCaptchaSuccess function is called upon a successful reCAPTCHA submission and the reCAPTCHA token is partially displayed in a Toast using an Android Emulator:
Full disclosure: I made the reCAPTCHA v2 test website to prepare/test/debug similar situations.
Try injecting the script like this,
function addCode(code){
var addedScript= document.createElement('script');
addedScript.text= code;
document.body.appendChild(addedScript);}
now call the function like,
val codeToExec = "function captchaResponse (token){" +
"android.reCaptchaCallbackInAndroid(token);" +
"}";
now exec loadurl like,
webview.loadUrl("javascript:(function addCode(code){
var addedScript= document.createElement('script');
addedScript.text= code;
document.body.appendChild(addedScript);})(codeToExec));
I need to call confirmation message box from codebehind as the user select data from dropdown list and when the selected data is 1 for example a confirmation box will appear to the user to confirm his action
so I did that as below in the code behind I called this JavaScript method:
if (dropdownlist1.SelectedValue == 1)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "CallConfirmBox", "CallConfirmBox();", true);
}
The script function:
<script type="text/javascript">
function CallConfirmBox() {
if (confirm("هل تريد ان تفصل الباليت؟")) {
alert("سيتم فصل الباليت!");
PageMethods.getdata(onSuccess, onError);
function onSuccess() {
alert(data);
}
function onError() {
alert(errorMessage);
}
}
} else {
//CANCEL – Do your stuff or call any callback method here..
alert("done!");
}
}
And I've added the below line at the beginning of the HTML code:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"> </asp:ScriptManager>
and Here is the code behind function that is called from script :
[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static void getdata()
{
int nRowsCheck = cMDP.Update_Segregation_PalletPart(nPalletNo);
if (nRowsCheck != 0)
{
nRowsCheck = 0;
nRowsCheck = cMDP.Update_Segregation_Pallet(nPalletNo, nUserID);
if (nRowsCheck != 0)
{
nRowsCheck = 0;
nRowsCheck = cMDP.Delete_Segregation_PalletPart_Delete(nPalletNo);
if (nRowsCheck != 0)
{
nRowsCheck = 0;
nRowsCheck = cMDP.Delete_Segregation_Pallet_Delete(nPalletNo);
}
}
}
}
But I've got the below error:
Page Methods is undefined when run the script !!
Please help as I need some support
First, you'll have to remove one } before the else in your JavaScript.
Change in your code-behind:
if (dropdownlist1.SelectedValue == "1")
For the main problem: Page Methods is undefined:
It seems from your comment that you're using a User Control (ascx). Page Methods cannot be used in a User Control. Please refer to these questions:
PageMethods is not defined
ASP.NET AJAX Page Methods from UserControl
The easiest solution is to use an aspx WebForm instead of an ascx User Control. That's what I've tested and worked.
Or you can use a WebService, as specified in the following question:
Alternate way to use page method inside user control asp.net
But the link to the sample is not working anymore.
Or you can try to use this project that tries to bring ASP.NET AJAX Page Methods to UserControls:
Control Methods for ASP.NET AJAX
You have two problems:
Change you javascript code:
PageMethods.getdata(onSuccess, onError);
function onSuccess(data)
{
alert(data);
}
function onError(data)
{
alert(data);
}
And you code behind getdata method must be a public static string function:
[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static string getdata()
{
//Do some things
return " Operations done successfully!";
}
since i didn´t find any solution that helped me, i thought i asked.
I need a JavaScriptfunction with calls a method in my code-behind, and since i´m really new to this, i dont understand what am i doing wrong.
On my Master Page (Site.Master) i enabled PageMethods:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
And in the Content of my Page i have put the Script:
function reply_click(clicked_id) {
alert(clicked_id);
PageMethods.javascriptTest(clicked_id);
And now my method in the code-behind:
[WebMethod]
public void javascriptTest(int buttonID)
{
Test2.Text += buttonID + "***";
// Use the ID for DB access
}
I need that ID for later, when i have to do stuff in my database, but i´m always getting PageMethods undefined errors and i dont know why :/
EDIT: The Solution was indeed to make the WebMethod static, i just made a workaround, so i could use all the details i need for my db access
JavaScript:
function reply_click(clicked_id, clicked_name) {
// Schulungsdaten holen
var grid = document.getElementById("<%= SignGridView.ClientID %>");
var row = grid.rows[0];
var appointmentData = row.cells[clicked_id].innerText;
// Userdaten holen
var userID = document.getElementById("<%= UserData.ClientID %>").innerText;
PageMethods.javaScriptUserSignIn(appointmentData, userID, clicked_name, OnSucceeded, OnFailed);
location.reload();
}
function OnSucceeded(response) {
alert(response);
}
function OnFailed(error) {
alert(error);
}
Code-Behind:
[WebMethod]
public static string javaScriptUserSignIn(string appointmentData, string userID, string status)
{
string result = "";
SignIn sign = new SignIn();
result = sign.SignToTraining(appointmentData, userID, status);
return result;
}
Your javascriptTest method needs to be static
Try This:
[System.Web.Services.WebMethod]
public static void javascriptTest(int buttonID)
{
Test2.Text += buttonID + "***";
// Use the ID for DB access
}
I am calling a simple JS function to set values of some html contents, but its not working
Here is the JS function
function SetEdits(name,email,pic,date)
{
document.getElementById("myPic").src=pic;
document.getElementById("fullname").value=name;
document.getElementById("email").value=email;
}
and here is the code from android activity
edit.loadUrl("edit.html");
edit.loadUrl("javascript:SetEdits('"+name+"','"+email+"','"+picture+"','"+date+"')");
its not settings these fileds.. is there any problem with the synax where i am calling this function in native activity?
You're probably ending up evaluating the JavaScript before the "edit.html" page has loaded. Try this:
// I'm assuming the real path is something like file:///android_asset/edit.html
edit.loadUrl("edit.html");
edit.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
if (Uri.parse(url).getPath() == "edit.html") {
view.loadUrl("javascript:SetEdits('" + name+"','" + email + "','" +
picture + "','" + date + "')");
}
}
Have you enabled the javascript for the webview ?
You have to setup a javascript interface between your app and html.
Here is some details Webapp guid
On the click of a button, I call a JavaScript function. After getting the value, I need to perform some stuff from the value obtained in the code-behind. How should I call code-behind?
My aspx:
function openWindow(page) {
var getval = window.showModalDialog(page);
document.getElementById("<%= TxtInput.ClientID %>").value = getval;
//After this I need to perform stuff 'Upload(TxtInput.value)' into database from the code-behind
}
The button calling the function is set up in the following manner:
<button class="doActionButton" id="btnSelectImage" runat="server" onclick="openWindow('../rcwksheet/popups/uploader.htm')">Select Image</button>
My desired code behind (VB):
Public Sub btnSaveImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelectImage.ServerClick
Dim inputFile As String = Me.TxtInput.Value
//do more stuff here
End Sub
So:
Is there a way to call code-behind from the JavaScript?
Can I somehow use the "onclick" property of a button to first go to a JavaScript and then to the code-behind?
Trigger a code-behind call "onchange" of the TxtInput.Value?
yes there is a way.
first, you can use javascript to submit the form after your return value is set in TxtInput.
function openWindow(page) {
var getval = window.showModalDialog(page);
document.getElementById("<%= TxtInput.ClientID %>").value = getval;
document.forms[0].submit();
}
then in your code behind, you can handle TxtInput's value in page load event.
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
if (this.Input.Value != string.Empty)
{
this.Input.Value += "blah";
}
}
}
note: you may need Identifying control that caused postback
You can put the server side code into a web service, make a service reference in an asp:ScriptManager on your aspx page and then you can call/execute the web service from javascript by calling:
WebServiceClassName.MethodName(javascriptvariable, doSomethingOnSuccess)
Here is a link on doing that:
http://msdn.microsoft.com/en-us/magazine/cc163499.aspx
You can call the __doPostBack Event.
function openWindow(page) {
var getval = window.showModalDialog(page);
document.getElementById("<%= TxtInput.ClientID %>").value = getval;
__doPostBack('btnSelectImage', getval);
}
And on the server side in your code behind, you can get the value:
In the PageLoad method:
if (Request.Form["__EVENTTARGET"] == "btnSelectImage")
{
//get the argument passed
string parameter = Request["__EVENTARGUMENT"];
//fire event
btnSaveImage_Click(this, new EventArgs());
}