I created an easy login form in html with a submit button that when I clicked it, a Javascript's function check if the login is correct or not.
All put all files into a qrc file in QT and I wrote this code for run the program:
login.pro
QT += webenginewidgets core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = login
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
RESOURCES += \
login.qrc
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWebEngineWidgets>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void connectToJs(bool result, QWebEngineView *view);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWebEngineWidgets>
#include <QUrl>
#include <QtWebView/QtWebView>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QFile apiFile(":/qtwebchannel/qwebchannel.js");
if(!apiFile.open(QIODevice::ReadOnly))
qDebug()<<"Couldn't load Qt's QWebChannel API!";
QString apiScript = QString::fromLatin1(apiFile.readAll());
apiFile.close();
view->page()->runJavaScript(apiScript);
view->load(QUrl(QStringLiteral("qrc:/new/prefix1/index.html")));
connect(view->page(), SIGNAL(loadFinished(bool)), this, SLOT(connectToJs(bool, view)));
setCentralWidget(view);
}
void MainWindow::connectToJs(bool result, QWebEngineView * view) {
qDebug() << "connectToJs!" << result;
if (result) {
QWebChannel *channel = new QWebChannel(view->page());
view->page()->setWebChannel(channel);
channel->registerObject(QString("nameObject"), this);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
index.html
<html>
<head>
<title>Javascript Login Form Validation</title>
<script src="login.js"></script>
</head>
<body>
<div class="container">
<div class="main">
<h2>Javascript Login Form Validation</h2>
<form id="form_id" method="post" name="myform">
<label>User Name :</label>
<input type="text" name="username" id="username"/>
<label>Password :</label>
<input type="password" name="password" id="password"/>
<input type="button" value="Login" id="submit" onclick="validate()"/>
</form>
</div>
</div>
</body>
</html>
login.js
function validate(){
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if ( username == "Jack" && password == "login"){
alert ("Login successfully");
}
else{
alert("Error: the login is incorrect!");
}
}
var workoutObject;
if (typeof qt != 'undefined') {
alert("Qt is OK!!");
new QWebChannel(qt.webChannelTransport, function (channel) {
workoutObject = channel.objects.nameObject;
});
}
else {
alert("Qt is not defined!");
}
That I want now is pass the username and the password from html to QT when I click the button.
How can I implement the QWebChannel?
In order to pass args from HTML/JS to QT via QWebEngine you will have to use the QWebChannel. There are some prerequisites for this task:
First you will have to create Qt object to interact with HTML/JS
H file
class QJavaScriptProxy : public QObject
{
Q_OBJECT
private:
QString m_oUserName;
QString m_oPassword;
public:
// Ctor
QJavaScriptProxy(QObject * poParent = Q_NULLPTR);
// Expose function to HTML/JS
Q_INVOKABLE void setUserNameAndPassword(const QString & oUserName, const QString & oPass);
...
};
Cpp file
QJavaScriptProxy::QJavaScriptProxy(QObject * poParent) : QObject(poParent)
{
// Set object name will be used as JS variable
setObjectName("m_oQtProxy");
}
QJavaScriptProxy::setUserNameAndPassword(const QString & oUserName, const QString & oPassword)
{
//store user name and password
m_oUserName = oUserName;
m_oPassword = oPassword;
}
Then register this object in your MainWindow
QWebChannel * poChannel = new QWebChannel(view->page());
view->page()->setWebChannel(poChannel);
// Create proxy object
m_poQtProxy = new QJavaScriptProxy(this);
// Register object
channel->registerObject(m_poQtProxy->objectName(), m_poQtProxy);
Add the qwebchannel.js file and link it to your HTML resources
index.html
<script src="qwebchannel.js" type="text/javascript"></script>
In the JavaScript side
login.js
new QWebChannel(qt.webChannelTransport, function(channel){
// Set global Qt proxy object
window.qProxy = channel.m_oQtProxy;
});
// Pass user name and password to QT
// Note: you can call this function on button click.
function toQT(name, pass){
qProxy.setUserNameAndPassword(name,pass);
}
Related
I have a form in index.jsp file, which allows to log into my app. I need to catch the inserted login to use it in another file called mainPage.jsp using Java code. When I do:
String login = request.getParameter("login");
this string has null value. How can I catch the inserted value?
Here is my code from index.jsp with forms resaponsible for logging into my app:
<body>
<form id="log" method="post" onsubmit="return check()" action="mainPage.jsp">
<div align="center">
Login: <input type="text" id="login" name="login"/>
<br/></br>
Password: <input type="password" id="password"/>
<br/></br>
<button name="login" type="submit">Log in!</button>
</div>
</form>
<script type="text/javascript">
function check() {
var login = document.getElementById("login").value;
var password = document.getElementById("password").value;
var flag = false;
var _users = JSON.parse(users);
for (var i = 0; i < _users.length; i++) {
if (_users[i].login == login && _users[i].password == password) {
flag = true;
}
}
if (flag == false) {
document.getElementById('info').innerHTML = "Wrong login or password!";
}
return flag;
}
</script>
</body>
First problem is in using wrong method:
HttpRequest.getParameter. This method finds parameter in URL. For example in this url
https://google.com/search?q=java
request.getParameter("q") returns java.
In your example you used POST query. It means that parameters will be in your request body in www-form-urlencoded format. Request will look like
login=login&password=password
The second problem is in using ids instead of names. To transfer params in tag you need to use names, not ids. Also button with name parameter will send empty input. After pressing button you will see next result on server
login=login&login=
And it's what we not expected. In example below I used names to send params correctly. If you need css style - use classes or id parameters instead of html tag name
To parse it without external libraries we have to
Parse request body
Extract parameters
Send response to client
Simple example of this:
login.jsp
<%# page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Login page</title>
<style>
/* TODO: use classes of method to make styles */
label, input {
display: block;
}
</style>
</head>
<body>
<form method="post">
<label>Login:
<input type="text" name="login" />
</label>
<label>Password:
<input label="password" type="password" name="password"/>
</label>
<button type="submit">Log in!</button>
</form>
</body>
</html>
Servlet
#WebServlet(name = "login", value = "/login")
public class LoginServlet extends HttpServlet {
public static final String IS_AUTHENTICATED_PARAM = "isAuthenticated";
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
this.getServletContext().getRequestDispatcher("/login.jsp").include(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Parse body
String requestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
//System.out.println(requestBody); - uncomment to view what is in body
String login = getParamFromBodyUrlEncoded(requestBody, "login");
String password = getParamFromBodyUrlEncoded(requestBody, "password");
//In future you can setup secret cookie and check it in other pages
if(login == null || password == null) {
request.setAttribute(IS_AUTHENTICATED_PARAM, false);
} else {
request.setAttribute("isAuthenticated", isCredentialsCorrect(login, password));
}
this.getServletContext().getRequestDispatcher("/loginResult.jsp").include(request, response);
}
private String getParamFromBodyUrlEncoded(String requestBody, String paramName) {
String paramUrlEncoded = paramName + "=";//param format is like login=. We expect paramname like login
//Search for param
int paramWithNameStart = requestBody.indexOf(paramUrlEncoded);
if(paramWithNameStart == -1) {
return null;
}
//Set pointer after param name
int paramStart = paramWithNameStart + paramUrlEncoded.length();
//Param should end with & or end of string
int paramEnd = requestBody.indexOf("&", paramStart);
if(paramEnd == -1) {
paramEnd = requestBody.length();
}
return requestBody.substring(paramStart, paramEnd);
}
private boolean isCredentialsCorrect(String login, String password) {
if("admin".equals(login) && "password".equals(password)) {
return true;
} else {
return false;
}
}
}
loginResult.jsp
<%# page import="com.example.demo_jsp.LoginServlet" %>
<%# page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Login result</title>
</head>
<body>
<h1><%=(boolean)request.getAttribute(LoginServlet.IS_AUTHENTICATED_PARAM) ?
"Success authentication" : "Wrong login or password"%></h1>
</body>
</html>
So, I finally managed to do this in a quite simple way.
When I log in, I store login name in session and then extract it later in my program.
I do this by calling this part of code after logging into my app:
if (request.getParameter("login") != null) {
session.setAttribute("_login", request.getParameter("login"));
}
And then, I catch the name of the logged person by:
String login = session.getAttribute("_login").toString();
It works pretty well! :-D
I am working with VS, a web form application, and I want to generate in the code-behind (C#) a JavaScript function defined in a JavaScript file in the project,.
I have tried different ways ,such as this line of code:
Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "Function_Name", true);
However, it can't resolve the name of my function since it's "not defined" as it's shown as a JavaScript error. But it works fine with a simple line of JavaScript code put in the Function_Name field (like alert("something")).
Any help with this please?
C#
define your javascript inside the C# code as text
Type type = this.GetType();
String key = "CallMyFunction";
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsClientScriptBlockRegistered(type, key))
{
StringBuilder script = new StringBuilder();
script.AppendLine("<script type=\"text/javascript\">");
script.AppendLine(" function Function_Name() {");
script.AppendLine(" frmMain.Message.value = 'Hello World';");
script.AppendLine(" }");
script.AppendLine("</script>");
cs.RegisterClientScriptBlock(type, key, script.ToString(), false);
}
or read your javascript from a .js file
<script type="text/javascript">
function Function_Name() {
frmMain.Message.value = 'Hello World';
}
</script>
Type type = this.GetType();
String key = "CallMyFunction";
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsClientScriptBlockRegistered(type, key) && File.Exists(path))
{
string script = File.ReadAllText(path);
cs.RegisterClientScriptBlock(type, key, script, false);
}
HTML - Body
<body>
<form id="frmMain" runat="server">
<input type="text" id="Message" />
<input type="button" value="Click!" onclick="Function_Name()" />
</form>
</body>
If you need a one-liner:
Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "function Function_Name() { frmMain.Message.value='Hello World'; }", true);
or
Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "<script type=\"text/javascript\">function Function_Name() { frmMain.Message.value='Hello World'; }</script>", false);
EDIT:
Using includes
String includeKey = "MyInclude";
String includeFile = "/myInclude.js";
String scriptKey = "CallMyFunction";
String script = "Function_Name();"; //Function inside your included js file.
Type type = GetType();
ClientScriptManager cs = Page.ClientScript;
//register the js file containing the function
if (!cs.IsClientScriptIncludeRegistered(includeKey))
{
cs.RegisterClientScriptInclude(includeKey, includeFile);
}
//register the script to call the function
if (!cs.IsClientScriptBlockRegistered(scriptKey))
{
cs.RegisterClientScriptBlock(type, scriptKey, script, true);
}
I have a Windows Service written in C# that uses SignalR to self-host for each respective client. This windows service will receive some parameters from a C# MVC Web Application that will be retrieved via the Send() method in the MyHub class. I'm parsing out the message variable and doing things with it. So it looks something like this:
MyCustomService.cs
public partial class MyCustomService: ServiceBase
{
private IDisposable SignalR;
public MyCustomService()
{
InitializeComponent();
eventLog1 = new EventLog();
if (!EventLog.SourceExists("MySource"))
{
EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("Service started.");
string url = "http://localhost:8080";
SignalR = WebApp.Start(url);
eventLog1.WriteEntry("Server running on " + url);
}
protected override void OnStop()
{
eventLog1.WriteEntry(LogMessage.Message);
eventLog1.WriteEntry("Service stopped");
SignalR.Dispose();
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
// Do other stuff that is omitted for brevity
}
}
My web application running will send data from the server side to the client's local PC via the windows service shown above - when a user presses the Send button.
MyWebApp.html
<!DOCTYPE html>
<html>
<head>
<title>SignalR Simple Chat</title>
<style type="text/css">
.container {
background-color: #99CCFF;
border: thick solid #808080;
padding: 20px;
margin: 20px;
}
</style>
</head>
<body>
<div class="container">
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion"></ul>
</div>
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="Scripts/jquery-1.6.4.min.js"></script>
<!--Reference the SignalR library. -->
<script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="http://localhost:8080/signalr/hubs"></script>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
debugger;
//Set the hubs URL for the connection
$.connection.hub.url = "http://localhost:8080/signalr";
// Declare a proxy to reference the hub.
var chat = $.connection.myHub;
// Create a function that the hub can call to broadcast messages.
chat.client.addMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
</script>
</body>
</html>
What will happen is that MyCustomService will eventually be installed on multiple computers that are connected to the same network. So:
Computer A has a instance of MyCustomService running on http://localhost:8080
Computer B has a instance of MyCustomService running on http://localhost:8080
Computer C has a instance of MyCustomService running on http://localhost:8080
The problem is this:
How can I differentiate between clients? Will the multiple instances of MyCustomService conflict since they are all on the same network?
For example: If Computer A clicks the Send button, I don't want Computer B to do anything with that data but since Computer B's service is looking at http://localhost:8080 it will receive that information and will also have its own instance of it even know technically they will all be the same.
I want to be able to say:
Computer A has pressed Send then do stuff in the windows service running on Computer A
Tell the duplicate service running in Computer C "dont do anything your Computer C not Computer A!"
Tell the duplicate service running in Computer B "dont do anything your Computer B not Computer A!"
I tried to call a Javascript function from swift using below code but can't access the Javascript function
This is how I create the Javascript context object:
lazy var context: JSContext? = {
let context = JSContext()
guard let
JSPath = Bundle.main.path(forResource: "IAV", ofType: "html")
else {
print("Unable to read resource files.")
return nil
}
do {
let iav = try String(contentsOfFile: JSPath, encoding: String.Encoding.utf8)
_ = context?.evaluateScript(iav)
} catch (let error) {
print("Error while processing script file: \(error)")
}
return context
}()
//Set value to js
func setToken(Token:String)
{
let jsmethod = context?.objectForKeyedSubscript("setIAVToken")
let passParameter = jsmethod?.call(withArguments: [Token])
}
The content of html file is
sample IAV form
</head>
<body > <header> </header> <main>
<h1>Registration Form</h1>
<form id="myform" method="post">
<div id="mainContainer"> <input type="button" id="start" value="Add Bank"> </div>
var value="dhjhsd";
var setIAVToken = function(token) {
value= token;
}
$('#start').click(function() {
var iavToken = value;
alert(iavToken)
dwolla.configure('uat');
dwolla.iav.start('iavContainer', iavToken, function(err, res) {
console.log('Error: ' + JSON.stringify(err) + ' -- Response: ' + JSON.stringify(res));
});
}); </script> </html>
You should probably use WKWebView (which is the new way to load web content in a webview in iOS since it uses WebKit and has lots of improvements like better memory allocation than it does WebView).
In a swift file WebviewBridging.swift in iOS you could have something like
import UIKit
import WebKit
class WebviewBridging: UIViewController, WKNavigationDelegate {
var webView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
// Create a WKWebView instance
webView = WKWebView (frame: self.view.frame, configuration: webConfig)
view.addSubview(webView!)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let url = Bundle.main.url(forResource: "index", withExtension: "html")!
webView!.loadFileURL(url, allowingReadAccessTo: url)
}
func callJSFunctionFromSwift(){
webView!.evaluateJavaScript("changeBackgroundColor('red')", completionHandler: nil)
}
}
In an index.html file on your iOS project folder you could have something like:
<html>
<head>
</head>
<body>
<script>
function changeBackgroundColor(colorText) {
document.body.style.background = colorText;
}
</script>
</body>
</html>
Whenever you will call callJSFunctionFromSwift() in swift it will communicate with the WKWebView through XPC communication and evaluate your javascript code that will trigger the javascript function in index.html.
In case of objective c do the following:
#import <JavaScriptCore/JavaScriptCore.h> in header file.
Next use this code inside viewcontroller.
NSString *jsPath = [[NSBundle mainBundle] pathForResource:#"JSFileName" ofType:#"js"];
NSString *scriptString = [NSString stringWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil];
JSContext *context = [[JSContext alloc] init];
context = [[JSContext alloc] init];
[context evaluateScript:scriptString];
JSValue *function = context[#"setMessage"];
JSValue* result = [function callWithArguments:#[#"your custom string"]]; //pass the string whatever you want.
[result toString]; // This will give the value in string format.
Edit the html, use
<input type="button" id="start" value="Add Bank" onClick="setMessage()"> instead of <input type="button" id="start" value="Add Bank">
Also add <input type="hidden" id="token" value="Token value"> inside the form to pass the token value.
In the javascript method:
<script>
function setMessage() {
var iavToken = document.getElementById("token").value;
alert(iavToken)
dwolla.configure('uat');
dwolla.iav.start('iavContainer', iavToken, function(err, res) {
console.log('Error: ' + JSON.stringify(err) + ' -- Response: ' + JSON.stringify(res));
});
}
</script>
Next invoke the javascript function using the following objective c.
NSString * jsCallBack = [NSString stringWithFormat:#"setMessage()"];
[webView stringByEvaluatingJavaScriptFromString:jsCallBack];
P.S: You need to add <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> (or if you have the js file locally add it.) in the html to work with the js.
I am trying to create a signalr chatroom in asp.net I am getting the following error "Uncaught TypeError: Cannot read property 'chatHub' of undefined" and the prompt does not come up.
I followed this tutorial https://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr with a modification to the startup class.
Startup.cs..
using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartupAttribute(typeof(MyTrainer.Startup))]
namespace MyTrainer
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var config = new HubConfiguration();
config.EnableDetailedErrors = true;
config.EnableJavaScriptProxies = true;
app.MapSignalR("/signalr", config);
}
}
}
My View (ChatRoom.cshtml)...
#{
ViewBag.Title = "ChatRoom";
}
<!DOCTYPE html>
<html>
<head>
<title>SignalR Simple Chat</title>
<style type="text/css">
.container {
background-color: #99CCFF;
border: thick solid #808080;
padding: 20px;
margin: 20px;
}
</style>
</head>
<body>
<div class="container">
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion"></ul>
</div>
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="../Scripts/jquery-1.11.3.min.js"></script>
<!--Reference the SignalR library. -->
<script src="../Scripts/jquery.signalR-2.2.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="../signalr/hubs"></script>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
</script>
</body>
</html>
My Hub...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace MyTrainer
{
public class ChatHub : Hub
{
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
}
}
My Controller..
public ActionResult ChatRoom()
{
return View();
}
Thank you!
I was rendering fullcalendar scripts in the layout page that was messing with the scripts for signal r
You should catch the error message when connecting to the server,you can add ".fail", one of the errors you may encounter is due to the version.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
}).fail(function (reason) {
console.log("SignalR connection failed: " + reason);
});