I created a website using flask with a running sqlite-db (SQLAlchemy). I want to send an integer with javascript to flask and back. I know AJAX can be used to accomplish that, but I don't know how to send the integer whenever my if/else-statement within my javascript game is met.
games.html
if (loc == unicornloc) {
money = 5000;
alert("\n\nBRAVO! You found the Unicorn! :)");
}else {
money = -250;
alert("The unicorn isn't here :(")
}
<FORM method="POST" name="searchb">
<input type=checkbox onClick="javascript:search('x1y1');">
<input type=checkbox onClick="javascript:search('x1y2');">
<input type=checkbox onClick="javascript:search('x1y3');">
games.py
#app.route('/games/<money>',methods=['GET'])
#login_required
def games(money):
print(request.args.get('money', type=int))
return render_template('games.html',money)
I want to get the money-value to flask, calculate a new value, pass it to my db and show the updated value on my website without reloading the page.
first set up jquery in your html.
make sure that the jquery is included in your head section of the html page:
You won't need to submit a form to update the server it is enough if you put a listener on one of your buttons that sends an ajax request every time it is clicked:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
var sendServerNotification = function(status){
var urlToCall = '/games/' + status;
$.ajax({
url : urlToCall, // the endpoint
type : "GET", // http method
// handle a successful response
success : function(parentDescriptions) {
console.log('success'); // log the returned json to the console
// update the page with jquery
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
$( document ).ready(function() {
$('#obsevervedbutton').click(function{
//we read the value that the user wants to submit:
var valueToSubmit = $('#valueToSubmit').val()
// here you can check if you want to submit the value
// or not
if(true){
sendServerNotification(valueToSubmit);
}
});
});
</script>
</head>
<body>
<button id="obsevervedbutton">notify server</button>
<input id="valueToSubmit"></input>
</body>
and on your server side it is important to return a json response instaed of a normal http response to finish the ajax request and invoke either the success or error url:
def games(money):
print(request.args.get('money', type=int))
# update the database here
return json.dumps({"result":"operation successfull!"})
I hope this will get you going.
Related
I'm improving a system for controlling a telescope remotely. A Raspberry Pi runs flask, and provides a video stream for a camera attached to the telescope. The telescope's focuser is actuated by a stepper motor controlled with an Arduino.The server provides a website that shows the video stream, and offers two buttons to move the focuser in and out.
When either button is clicked, the client sends a POST to the RasPi, and then the RasPi tells the Arduino to move the focuser. But crucially I did not want the page to refresh while refocusing. Hence, I used jQuery and Ajax to suppress the page refresh.
The relevant code snippets are here:
Python/Flask code:
#app.route('/stream/<wcam>', methods=['GET'])
def stream_get(wcam):
class FocuserForm(FlaskForm):
nsteps = IntegerField('# steps: ', default=1)
focuser_in = SubmitField('Focuser in')
focuser_out = SubmitField('Focuser out')
form = FocuserForm()
return render_template('stream.html', wcam=wcam, form=form)
#app.route('/stream/<wcam>', methods=['POST'])
def stream_post(wcam):
results = request.form
arduino_serial = SerialFocuser()
if results['caller'] == "focuser_in":
command = "MVD" + results['steps'] + "\n"
arduino_serial.send_command(command)
elif results['caller'] == "focuser_out":
command = "MVU" + results['steps'] + "\n"
arduino_serial.send_command(command)
return ''
Web (stream.html):
<html>
<head>
<title>Video Streaming</title>
<style>
...
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {});
</script>
</head>
<body>
<h1>Streaming camera {{ wcam }}</h1>
<br>
<img id="bg" src="{{ url_for('video_feed', wcam=wcam) }}", height="480" width="640">
Back
<br>
<!--######################################################-->
<!--# Focuser handling -->
<!--######################################################-->
<br>
<form id="flaskform" method="POST">
<p>
{{ form.nsteps.label }} {{ form.nsteps() }}
{{ form.focuser_in() }}
{{ form.focuser_out() }}
</p>
</form>
<script>
// $(document).ready(function() { // Moved to header
var form = document.getElementById('flaskform');
function onSubmit(event) {
console.log('onSubmit function');
var objectID = event.explicitOriginalTarget.id;
var nsteps = form.nsteps.value;
var return_data = {caller: "", steps: nsteps};
if (objectID == "focuser_in") {
return_data.caller = objectID;
console.log("Focuser_in detected");
} else if (objectID == "focuser_out") {
return_data.caller = objectID;
console.log("Focuser_out detected");
} else if (objectID == "nsteps") {
console.log("nsteps detected");
event.preventDefault();
return;
} else {
console.log("No matches");
return;
}
console.log("About to run Ajax");
$.ajax({
url: "stream.html",
type: "post",
data: return_data,
success: function(response) {
console.log('It worked!');
},
error: function(xhr, status, text) {
console.log('An error occurred:', status,"; ", text);
},
timeout: 1000 // 1s
}); // Ajax
console.log("After running Ajax");
if (event) { event.preventDefault(); }
}
// prevent when a submit button is clicked
form.addEventListener('submit', onSubmit, false);
//<!--form.addEventListener('submit', onSubmit, false);-->
// prevent submit() calls by overwriting the method
form.submit = onSubmit;
//}); // Moved to header
</script>
</body>
</html>
The problem is as follows:
If I refresh the page on the client's browser and then click a button, ajax does POST, but flask does not seem to receive it. The request times out.
If I now restart the server (I'm developing this with PyCharm, so I just click re-run) without refreshing the page in the client, and then click a button, flask does get the POST, and the focuser works like a charm.
If I refresh the page again, then the buttons stop working until I reset the server.
Why does this happen? Obviously the code works in its main purpose, but somehow the page refresh is breaking something.
I had a similar issue once with a camera thread blocking all calls. When you reset the server, does your camera feed still run (before clicking the button)?
Because basically you are calling your camera feed twice - first with the get call when you refresh your page, then again with the post call.
I'd advice you to refactor your submitted code into an alternative function for clarity:
#app.route('/stream/<wcam>', methods=['POST'])
def moveCommand:
if form.is_submitted():
# POST method
results = request.form
arduino_serial = SerialFocuser()
if results['caller'] == "focuser_in":
command = "MVD" + results['steps'] + "\n"
arduino_serial.send_command(command)
elif results['caller'] == "focuser_out":
command = "MVU" + results['steps'] + "\n"
arduino_serial.send_command(command)
So basically you keep your get method for only the streaming and use the post for the moving around.
Thanks to #Peter van der Wal for pointing me towards the solution.
The video streamer has a while True loop, which continually takes frames from the camera, hence locking the thread.
The solution was to start the app with the threaded option on:
Before:
app.run(host='0.0.0.0', debug=True)
Now:
app.run(host='0.0.0.0', debug=True, threaded=True)
This allows the video streaming thread to continue on its own, while allowing the server to process other commands.
To put it simply, I need a way for client side code to be able to trigger a server side method in my project. The way that I'm trying to use such functionality is when a user inputs their email address into a textbox, after each character is typed I want the project to trigger the method shown below which uses a class to query my database.
private void EmailCheck()
{
lblEmailError.Text = null;
Customer y = new Customer();
int counter = 0;
y.Email = Email.Text;
counter = y.CheckEmail();
if (counter.Equals(1))
{
lblEmailError.Text = "Email is already in use";
}
else
{
lblEmailError.Text = null;
}
}
I currently have almost no experience of any kind with JavaScript or any form of client side scripting. As I understand, AJAX may be of use to me here but again I am clueless about how I would implement it. I've also heard about onkeydown/press/up but again I am not sure how to alter online solutions to my specific need. Any help?
The most straightforward way would be to make a button in HTML5, use jQuery $.ajax() function to invoke a server side REST API (implementation could be anything C# Web API, Python Flask API, Node.JS API).
In your client side:
<label> Enter something into the textbox </label>
<input type = "text" id = "myTextBox" placeholder="Enter something"/>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script>
$(function(){
//On button click query the server
$("#myTextBox").change(function(){
var textBoxValue = $("#myTextBox).val();
var dataToBeSent = {
"data": textBoxValue
};
$.ajax(function(){
url: "http://localhost:9999/api/YourAPIName",
method: "POST",
data: JSON.stringify(dataToBeSent),
success: function(data){
console.log(data);
},
error: function(jqXHR, textStatus, errorThrown){
console.log("Failed because" + errorThrown);
}
}); //end .ajax
}); //end click
}); //end jQuery
</script>
In your Server side (Assuming C#):
Make a model class, with properties the same name as the JSON key you constructed for the [FromBody] attribute to deserialize it correctly.
public class SomeModelClass
{
public string data { get; set; }
}
[HttpPost]
[Route("api/YourAPIName")]
public HttpResponseMessage YourMethod([FromBody] SomeModelClass modelClass)
{
//perform logic and return a HTTP response
}
so, below is a code snippet from my server.js file. When running, and I send a URL with a message, the res.end() causes the view to render a blank page.
When I comment out the res.end() command, the view displays all of the messages, but the browser waits and waits for the signal that the response from the server is complete.
I get that you can use res.end() and put data in the parens, to be transmitted and rendered by the view.
What I expect to happen is that with no args, it will just leave the view alone, but the empty args in the parens is manifesting as an empty view.
How do I indicate that the response is complete without deleting the data on the view?
server.js
var http = require('http'),
url = require('url'),
fs = require('fs');
var messages = ["testing"];
var clients = [];
http.createServer(function(req,res) {
var url_parts = url.parse(req.url);
console.log(url_parts);
if(url_parts.pathname == '/') {
// file serving
fs.readFile('./index.html', function(err, data) {
// console.log(data);
res.end(data);
});
} else if(url_parts.pathname.substr(0,5) == '/poll'){
//polling code
var count = url_parts.pathname.replace(/[^0-9]*/,'');
console.log(count);
if(messages.length > count){
res.end(JSON.stringify({
count: messages.length,
append: messages.slice(count).join("\n")+"\n"
}));
} else {
clients.push(res);
}
} else if(url_parts.pathname.substr(0, 5) == '/msg/') {
// message receiving
var msg = unescape(url_parts.pathname.substr(5));
messages.push(msg);
while(clients.length > 0) {
var client = clients.pop();
client.end(JSON.stringify({
count: messages.length,
append: msg+"\n"
}));
}
// res.end(); //if left in, this renders an empty page, if removed,
// client keeps waiting....
}
}).listen(8080, 'localhost');
console.log('server running!');
index.html
<html>
<head>
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script>
var counter = 0;
var poll = function() {
$.getJSON('/poll/'+counter, function(response) {
counter = response.count;
var elem = $('#output');
elem.text(elem.text() + response.append);
//elem.text(counter);
poll();
});
}
poll();
</script>
</head>
<body>
<textarea id="output" style="width: 90%; height: 90%;">
</textarea>
</body>
</html>
I have looked in the docs, but I don't see anything specific about using .end() method with empty args to signify and end without passing data to be rendered. I have googled this, but I don't have an answer yet.
Do a res.json({success:"true"}) instead. The reason being is because res.end inherently thinks the client was sent a view prior to the stream being closed. With res.json() you can send any generic data, without an implied view being expected as well as close out the stream on client and server side.
Move res.end() inside while loop
while (clients.length > 0) {
var client = clients.pop();
client.end(JSON.stringify({
count : messages.length,
append : msg + "\n"
}));
if(!clients.length) {
res.end();
}
}
My understand of your problem is:
You have an HTML page (index.html), which has a textarea displaying all messages submitted by user. After one message is received and displayed, it will send the request for next message immediately (/poll/<n>).
To accept user's input for latest message, you open an API (/msg/<message>). When an HTTP request is sent to this API, server will extract the message, and return this message to /poll/<n> sent in step 1.
However, as HTML page (index.html) and the request to /msg/<message> happens in the same browser window, you can't let the http handler of /msg/<message> in node.js invoke res.end(), because in that case, the browser window will render the HTTP response of /msg/<message> request (blank page). Actually, you can't make the res return 200 OK, whatever data it returns. You can't make res fail the /msg/<message> request either (using req.destroy()), because in that case the browser window will render a failure/broken page, which is worse.
Unfortunately, you can't make res of /msg/<message> in node.js keep pending either. Although it will update index.html, the browser window will keep waiting...
The root cause of your problem is: browser window resource conflict between index.html and /msg/<message> response -- as long as /msg/<message> request is sent by using index.html window's URL bar, whenever its response is sent back, the window content (index.html) will be cleaned.
One solution is: using Ajax to send /msg/<message>. In this way, there would be no conflict for window resource. Example code is listed below:
<body>
<textarea id="output" style="width: 90%; height: 90%;">
</textarea>
<div>
<input type="text" id="msg">
<button type="button" onclick="submitMsg()">Submit</button>
</div>
</body>
window.submitMsg = function() {
var msg = $('#msg').val();
$.getJSON('/msg/' + msg, function(res) {
$('#msg').val('');
console.log('message sent.');
});
}
EDIT:
Another simpler solution is: open index.html in one browser window, and open /msg/<message> in another one (use res.end('message received successfully') to indicate message receiving result).
I am working on a ColdFusion 8 training application where I'm making some AJAX requests (without any libraries such as jQuery) to support a very basic CRUD application.
The high level architecture includes a CFM view, a CFC with remote access methods which receive the AJAX requests, and a CFC which acts as a model and has all of the database queries.
For just retrieving data that doesn't require any sort of bind variables (like getting all rows from the table), the AJAX queries are working fine. When I try to post anything to the CFC middle layer, however, I'm getting errors about the values I'm looking for being undefined in the Form scope (which from my understanding is where post parameters will be stored). I even dissected the requests with Tamper Data and verified that the names and values of the post parameters are as I expect them to be.
Here is an example of the JS AJAX requests:
function addLocation(locToAdd) {
var thisAccess = new AccessStruct("POST", "jsontest.cfc?method=addNewLocation", getLocations, "newLoc=" + JSON.stringify(locToAdd));
accessWrapper("addLoc", thisAccess);
function accessWrapper(action, accessDef) {
var ajaxRequest = new XMLHttpRequest();
var nextStep;
if (action != "getLocs") {
nextStep = getLocations;
} else {
nextStep = buildTable;
}
ajaxRequest.onreadystatechange = function() { // using a closure so that the callback can
if (ajaxRequest.readyState == 4) { // examine the request and nextStep
if (ajaxRequest.status == 200) {
if (nextStep != null) {
nextStep(ajaxRequest);
}
return true;
} else {
alert("Request Could Not Be Completed; Errors On Page");
return false;
}
}
}
ajaxRequest.open(accessDef.method, accessDef.url, true);
ajaxRequest.send("newLoc=" + accessDef.params);
}
function Loc(locCode, parLocCode, name, addrL1, addrL2,
city, stateProv, postal, locTypeCode) {
this.locCode = locCode;
this.parLocCode = parLocCode;
this.name = name;
this.addrL1 = addrL1;
this.addrL2 = addrL2;
this.city = city;
this.stateProv = stateProv;
this.postal = postal;
this.locTypeCode = locTypeCode;
}
function AccessStruct(method, url, nextStep, params) {
this.method = method;
this.url = url;
this.nextStep = nextStep;
this.params = params;
}
Essentially what's happening on the page is that a table populated by all the location (loc) records is being rendered for a "user". There is a form to add a new user, and when they click the add button, a Loc structure is created containing the information they entered and is passed to the addLocation function. This creates an Access structure, which will include the request URL, method, the name of a function to act as a callback, and any post parameters. This is all passed into the accessWrapper function, which will create the XMLHttpRequest and process the AJAX request. I used a closure for the onreadystatechange callback function so that it could be aware of the XMLHttpRequest object and the callback function defined in the Access structure (this callback function will be generally be used to refresh the view table after a record is added, deleted, or edited).
Here is the cffunction within the middle-layer CFC where the problem is being reported from. I won't bother to post the DAO CFC as that has been tested elsewhere and is not even being reached during this process (because it's failing at the middle [or controller] level)
<cffunction name="addNewLocation" output="false" access="remote">
<cfset var deserializedLocation = "">
<cfscript>
deserializedLocation = DeserializeJSON(Form.newLoc);
</cfscript>
<cfobject component="locationDAO" name="locationDAOObj">
<cfinvoke
component="#locationDAOObj#"
method="addLocation">
<cfinvokeargument name="code" value="#deserializedLocation.locCode#">
<cfinvokeargument name="parentCode" value="#deserializedLocation.parLocCode#">
<cfinvokeargument name="name" value="#deserializedLocation.name#">
<cfinvokeargument name="addr1" value="#deserializedLocation.addrL1#">
<cfinvokeargument name="addr2" value="#deserializedLocation.addrL2#">
<cfinvokeargument name="city" value="#deserializedLocation.city#">
<cfinvokeargument name="stateProv" value="#deserializedLocation.stateProv#">
<cfinvokeargument name="postal" value="#deserializedLocation.postal#">
<cfinvokeargument name="locationType" value="#deserializedLocation.locTypeCode#">
</cfinvoke>
</cffunction>
The error in the request response is:
500 Element NEWLOC is undefined in FORM
Like I said before, I've checked the request in Tamper Data, and it looks fine there. Thanks in advance for any help you great folks might be able to offer!
There absolutely is a FORM scope when you do an Ajax post to a CFC.
This example POSTs form data via Ajax to a CFC function with no arguments and returns the JSON format of the FORM scope. Yes, you should have arguments to document, specify required/not required and data type, but they're not mandatory.
Is there any reason you aren't using jQuery? It would probably make your life much easier.
There must be something wrong with how you're sending the form data to the Ajax call. If you use FireBug to watch your Ajax calls, you can see the POSTed parameters.
HTML
<html>
<head>
<title>Ajax POST to CFC</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="test.js">
</head>
<body>
<form id="foo" action="" method="post">
<input type="text" id="a" name="a" value="Hello" />
<br />
<input type="text" id="b" name="b" value="Goodbye" />
<br />
<textarea id="data" cols="30" rows="10" disabled="true"></textarea>
<br />
<input type="button" id="btnSubmit" value="Do Ajax!" />
</form>
</body>
</html>
JavaScript
$(document).ready(function() {
$('#btnSubmit').on('click', function() {
$.ajax({
asynch : true,
type : 'POST',
dataType : 'json',
url : 'test.cfc?method=testing&returnformat=json',
data : {
a : $('#a').val(),
b : $('#b').val()
},
success : function(data, textStatus) {
$('#data').val(JSON.stringify(data));
}
});
});
});
CFC
<cfcomponent>
<cffunction name="testing" access="remote" output="false" returntype="string">
<cfreturn serializeJSON( form ) />
</cffunction>>
</cfcomponent>
Old School, no jQuery, just plain ol' JavaScript
I found a simple example of an Ajax POST without jQuery here:
http://www.openjs.com/articles/ajax_xmlhttp_using_post.php
HTML
Remove the jQuery SCRIPT tag, change the other SCRIPT to test-nojq.js and change the submit button to add an onclick event.
<input type="button" id="btnSubmit" value="Do Ajax!" onclick="doSubmit();" />
JavaScript: test-nojq.js
function doSubmit(){
var http = new XMLHttpRequest();
var url = "test.cfc";
var params = "method=testing&returnformat=json";
params += "&a=" + document.getElementById('a').value;
params += "&b=" + document.getElementById('b').value;
http.open("POST", url, true);
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
document.getElementById('data').value = http.responseText;
}
}
http.send(params);
}
Make newLoc into an argument and it should work.
<cffunction name="addNewLocation" output="false" access="remote">
<cfargument name="newLoc">
...
</cffunction>
update: not sure why I encountered no form scope one time calling a remote method. Anyway, it isn't true but the rest of the answer should still hold true.
I have a form on my site that when submitted takes the user from Page1.html to Page2.html.
I would like to display a message between the form being submitted and "Page2 loading".
Can someone provide me with an example of this?
If your form submit data via ajax then you could try something this:
$('form#myform').submit(function(e) {
e.preventDefault();
$('#message').html('Sending....'); // #message may be a div that contains msg
$ajax({
url: 'url_to_script',
data: 'your_data',
success: function(res) {
// when submit data successfully then page reload
window.location = 'page2.html'
}
});
});
What you're looking to do can't be done by standard form submission.
You'll want to submit the form using ajax, and display a "Please wait" message while you are waiting for a response. Once the response is received and validated to be OK, you can then redirect the user to the page you now call page2.
The easiest way to submit a form via ajax is to serialize it to a string and pass it along. Then, you'll need a page to process the received data, and return an OK or and ERR.
The JS will then need to decipher next action.
This is not tested, but copied and pasted from various working projects.
You'll need to download and include the json2.js project.
page1
<div id='pleaseWait'>Please Wait...</div>
<form id="theForm" onsubmit="doAjaxSubmit();">
<input type='text' name='age' id='age' />
<input type='submit' value='submit'>
</form>
<script type="text/javascript">
function doAjaxSubmit(){
var j = JSON.stringify($('#theForm').serializeObject());
$('#pleaseWait').slideDown('fast');
$.post('processor.php?j=' + encodeURIComponent(j), function(obj){
if(obj.status=='OK'){
window.location='page2.php';
}else{
$('#pleaseWait').slideUp('fast');
alert('Error: ' + obj.msg);
}
}, 'json');
return(false);
}
$.fn.serializeObject = function(){
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
</script>
processor.php
<?php
$j=json_decode($_POST['j'], true);
if ((int)$j['age']<=0 || (int)$j['age']>120){
$result = array('status'=>'ERR', 'msg'=>'Please Enter Age');
}else{
//Do stuff with the data. Calculate, write to database, etc.
$result = array('status'=>'OK');
}
die(json_encode($result));
?>
This is essentially very similar to the answer below (by #thecodeparadox), but my example shows how to pass the entire for without having to manually construct your data object, shows how to validate on the PHP side as well as return the appropriate JSON data to either redirect the user, or to display an error, and uses animations to display the message.