I have a .JSON file that contains an array of hashes, each hash contains some info. regardless, i want to write a code that creates a checkbox for each hash, provided that the code has to be dynamic (if the number of hashes in the array changes, the code still works)
I'm using Ruby for the backend and HTML/JavaScript for the frontend
I was able to get a method that converts the .json file into "something useful I could use" :D
response = HTTParty.get("file.json")
i = JSON.parse(response.body)
and I learned how to create a checkbox in HTML
<input type="checkbox" name="check" value="check1">option 1< br>
but I know this does not create a checkbox for the item (hash in this case) inside the array and I want it to be repeated "x" number of times (provided that "x" is the number of hashes in the array)
It will executes when the window finishes loading. It uses an asynchronous arrow function to fetch data from a remote server and display it on a web page. The function fetches data from a server at a specific URL using the fetch() method with a GET request and expects the response to be in JSON format. It then checks if the response is an array, and if it is, it creates an HTML element for each element in the response using a for loop and template literals. The HTML elements include a checkbox input and a label for each element in the response. Finally, it sets the innerHTML of an element with the ID "data" to the HTML created in the previous step, which displays the data on the web page. If there is an error while fetching data from the server or parsing the response, it logs an error message to the console.
window.onload = function() {
(async () => {
try {
let data = ``;
let response = await fetch('https://reqbin.com/echo/get/json', {
method: 'GET',
headers: {
'Accept': 'application/json',
},
})
response= response.json();
if (!Array.isArray(response)) throw Error(`Invalid response. Expecting Array found ${typeof response}`);
for (const element of response) {
data+= `
<p>
<input type="checkbox" value="${element}" title="${element}" id="${element}"/>
<label for="${element}">${element}</label>
</p>
`
}
document.getElementById("data").innerHTML = data;
} catch (error) {
console.error("Error", error.message)
}
})()
};
Related
I am trying to create a web application that allows the user to send specific data to the webserver and retrieve it to process it further into functions that visualizes information to the user.
However, when sending code from the webserver back to the client, some data values within the data become 'undefined'.
#app.route('/_create_vis_json', methods=['GET'])
def process_vis_input():
""" This function gets the inputs of the user of the MGcV viewer. It converts it into a json with all the information
needed for the visualisation of the genes.
:return: JSON containing info of genome
"""
gi_codes = request.args
search = GeneConverter(gi_codes)
processed_dictionary = (search.create_output_json())
return {'result': processed_dictionary}
Using the Pycharm debugger, I have concluded that all data is present when the data gets send to the front-end.
$(function () {
/** when a input button with name vis_button is clicked, a ajax request is send to the server containing
* information about the settings used in the viewer. A Json object containing information about the given
* genes is returned to be processed into a visualisation.
*/
$('input[name="vis_button"]').bind('click', function () {
$.ajax({
dataType: "json",
type: 'GET',
url: $SCRIPT_ROOT + '/_create_vis_json',
data: {
gi_codes: $('textarea[name="gi_codes"]').val(),
input_type: $('select[name="input_type"]').val(),
context_range: $('select[name="context_range"]').val(),
map_size: $('select[name="map_size"]').val(),
gene_orient: $('select[name="gene_orientation"]').val(),
gene_label: $('select[name="gene_label"]').val(),
gene_coloring: $('select[name="gene_coloring"]').val()
},
success: function (data) {
console.log('==========');
console.log(data);
console.log('-----');
$("#result").html(buildSVG(data.result))
}
});
});
});
Taking a look at the console log, at the inconsistent values, 1 or more of the values will be undefined. When I repeat the process, the same values go missing.
I am using Python 3.7.4 with Flask 1.1.1 and using jquery version 3.4.1
Edit 1: As indicated by Ajax1234, I have already tried to use Flask.jsonify and got the same results. I will also include a picture of the missing data.
Screenshot of console log of the browser
You can use flask.jsonify instead of returning a dictionary as the response for your route. flask.jsonify automatically sets the appropriate Content-Type headers for a JSON response:
return flask.jsonify({'result': processed_dictionary})
Additionally, if processed_dictionary is not a basic type (int, float, str), you need to convert it to a JSON string:
flask.jsonify({'result': json.dumps(processed_dictionary)})
Then, in your Javascript:
success: function (data) {
$("#result").html(buildSVG(JSON.parse(data.result)))
}
On a webpage, I need to upload both an image file and an ID string to the server. Usually, I do these things using $.ajax. As it often happens when uploading files, $.ajax threw an Uncaught TypeError: Illegal invocation because the function by default tries to convert the file object into a string. It's common advice to set processData to false to prevent this.
But I cannot use this option:
If I set processData to false, only an empty array is sent to the server. I can see in the developer tools that the Form Data object is empty and there's no data in the request object that reaches the server (I'm using PHP/Laravel).
If I omit the option, I get an Illegal invocation error.
What's special about my code and what else can I do?
Below is most of the JS code. File uploads are triggered by dropping an image in the last cell of a table row. I need to upload both an image and an ID which is stored in the (hidden) first cell of the same table row.
<script>
// dragover-listener omitted
// Add listeners for drop event to each cell in last column
let imageCells = Array.from(document.getElementsByClassName('image'));
imageCells.forEach(function(cell) {
cell.addEventListener('drop', fileSelect);
});
// Handle drop event
function fileSelect(event) {
event.preventDefault();
// Get data for AJAX request: ID and new image
let parentRow = event.target.closest('tr');
let id = parentRow.cells[0].textContent;
let data = {
id: id,
image: event.dataTransfer.files[0]
}
// data is available
console.log(data);
let ajaxRequest = $.ajax({
url: '/map/set-image',
type: 'POST',
processData: false,
data: data
});
ajaxRequest.done(function(msg) {
console.log(msg);
});
// fail handler omitted
}
</script>
edit: Some sample HTML
<tr>
<td class="hidden">4</td>
<td contenteditable="true">John</td>
<td contenteditable="true">Doe</td>
<td contenteditable="true">john.doe#example.com</td>
<td contenteditable="true">555 12345</td>
<td class="image"><img src="/img/avatars/4.jpg"></td>
</tr>
I recommend you to wrap your inputs with a form element and give it an id. Then use $.post instead:
$.post('/map/set-image', $("#yourFormId" ).serialize());
Note that you would need to create a hidden input in the form to send the ID string to the server.
Just to try something different, I used a FormData object (instead of a plain one) to collect my data. So I replaced
let data = {
id: id,
image: event.dataTransfer.files[0]
}
with
let data = new FormData();
data.append('image', event.dataTransfer.files[0]);
data.append('id', id);
Didn't work yet, I still had to replace the third line with data.append('id', String(id));
It seems the request failed because as I switched off the automatic conversion of the request data into strings (processData: false) the ID was treated as a number.
Note that the string conversion alone didn't do the trick, just using String(id) instead of idin the initial version doesn't work - I'd still like to know why.
I am creating a basic piece of functionality to allow users to send their location to a server which then queries a database and returns locations near to them. I am using the below jQuery .ajax wrapper to POST data to the server. This takes the form of a latlon point which is then used as the basis for a geosearch in MongoDB using nodejs and express on the backend. The results of the search are then intended to be returned to the client and rendered by the createMapListings function.
The /find page is initially rendered through a GET request to the database via mongodb separate from the below code. However subsequent to initial rendering, I then want to return results dependent on the location provided.
The POST method works fine and the location is posted to the server, with the search results being returned as I can print contents out through the console log.
However, I then want to render the results on the client-side. As mentioned, the results of the search render in the console, but when I attempt to pass through to the client, I can render the data itself (in the form of an array of objects) in the #output div, but the createMapListings function does not seem to catch the data.
In fact, the below function appears to be called but prints out over a thousand rows with the data that should be caught described as 'undefined'. I have tried to use res.render and res.redirect, but in the first case, the view renders in the div (which I suppose is expected) and the redirect fails.
The createMapListings function works fine when a simple GET request is made to the server, for example, for all objects in a collection, using ejs template. However, I think the issue here may be a combination of a POST request and then wanting to pass the results back to the AJAX request using the complete callback.
I apologise if the below code is somewhat obtuse. I’m definitely what you would call a beginner. I appreciate the above functionality may not possible so if there is a better way, I would of course be open to it (res.direct perhaps).
Here is the relevant client side script:
$(document).ready(function(){
$("#geolocate").click(function(){
navigator.geolocation.getCurrentPosition(geolocate, function(){
});
});
});
function geolocate(pos){
var latlonpt = [];
var x = pos.coords.latitude;
var y = pos.coords.longitude;
latlonpt.push(x);
latlonpt.push(y);
var obj = {
userlocation: latitudelongitudept
};
$.ajax({
url: "/find",
type: "POST",
contentType: "application/json",
processData: false,
data: JSON.stringify(obj),
complete: function (data) {
$('#output').html(data.responseText);
$('#infooutput').children().remove();
createMapListings(data.responseText);
}
});
};
function createMapListings(maps) {
for (var i = 0; i < maps.length; i++) {
var url = maps[i]._id;
var fullurl = "<a href='/show?id=" + url + "'>Route</a></div>";
var title = "<div>" + maps[i].title + " - " + fullurl +"";
$('#infooutput').append(title);
};
};
</script>
Here is the relevant route used in a basic express app to handle the post request made by the above .ajax wrapper.
exports.findbylocation = function(req, res) {
console.log(req.body.userlocation);
var userlocation = req.body.userlocation;
Map.ensureIndexes;
Map.find({loc :{ $near : userlocation }}, function(err, maps) {
if (err) {
console.log(err)
}
else {
var jmaps = JSON.stringify(maps);
console.log(jmaps);
res.send(jmaps);
}
});
};
By convention, the data variable name in an $.ajax callback signature refers to the parsed HTTP response body. Since your callback is on complete, we're actually passed the XMLHttpRequest used, by convention called xhr. You rightly grab the responseText property, but this needs parsing to be useful. So long as we take care over our Content-Type's and don't explicitly disable processData, jQuery will do the encoding/unencoding for us - we just deal with objects. This is a good thing, since the transport format isn't usually of any particular importance to the application logic. If we use res.json(maps) in place of res.send(jmaps), we can write our call more simply:
$.ajax({
url: '/find',
type: 'POST',
data: obj,
success: function(data) {},
error: function(xhr, text, err) {}
});
Here data is a Javascript object already parsed and ready to use. We also use a default application/x-www-form-urlencoded request rather than explicitly setting a contentType. This is the same as far as express is concerned: it will just be parsed by urlencoded instead of json.
Assuming you solved your client-sie problem.
As you are using express there is no need for JSON.stringfy,
you can use res.json(maps).
I have two HTML pages that work in a parent-child relationship in this way:
The first one has a button which does two things: First it requests data from the database via an AJAX call. Second it directs the user to the next page with the requested data, which will be handled by JavaScript to populate the second page.
I can already obtain the data via an ajax call and put it in a JSON array:
$.ajax({
type: "POST",
url: get_data_from_database_url,
async:false,
data: params,
success: function(json)
{
json_send_my_data(json);
}
});
function json_send_my_data(json)
{
//pass the json object to the other page and load it
}
I assume that on the second page, a "document ready" JavaScript function can easily handle the capture of the passed JSON object with all the data. The best way to test that it works is for me to use alert("My data: " + json.my_data.first_name); within the document ready function to see if the JSON object has been properly passed.
I simply don't know a trusted true way to do this. I have read the forums and I know the basics of using window.location.url to load the second page, but passing the data is another story altogether.
session cookie may solve your problem.
On the second page you can print directly within the cookies with Server-Script tag or site document.cookie
And in the following section converting Cookies in Json again
How about?
Warning: This will only work for single-page-templates, where each pseudo-page has it's own HTML document.
You can pass data between pages by using the $.mobile.changePage() function manually instead of letting jQuery Mobile call it for your links:
$(document).delegate('.ui-page', 'pageinit', function () {
$(this).find('a').bind('click', function () {
$.mobile.changePage(this.href, {
reloadPage : true,
type : 'post',
data : { myKey : 'myVal' }
});
return false;
});
});
Here is the documentation for this: http://jquerymobile.com/demos/1.1.1/docs/api/methods.html
You can simply store your data in a variable for the next page as well. This is possible because jQuery Mobile pages exist in the same DOM since they are brought into the DOM via AJAX. Here is an answer I posted about this not too long ago: jQuery Moblie: passing parameters and dynamically load the content of a page
Disclaimer: This is terrible, but here goes:
First, you will need this function (I coded this a while back). Details here: http://refactor.blog.com/2012/07/13/porting-javas-getparametermap-functionality-to-pure-javascript/
It converts request parameters to a json representation.
function getParameterMap () {
if (window.location.href.indexOf('?') === (-1)) {
return {};
}
var qparts = window.location.href.split('?')[1].split('&'),
qmap = {};
qparts.map(function (part) {
var kvPair = part.split('='),
key = decodeURIComponent(kvPair[0]),
value = kvPair[1];
//handle params that lack a value: e.g. &delayed=
qmap[key] = (!value) ? '' : decodeURIComponent(value);
});
return qmap;
}
Next, inside your success handler function:
success: function(json) {
//please really convert the server response to a json
//I don't see you instructing jQuery to do that yet!
//handleAs: 'json'
var qstring = '?';
for(key in json) {
qstring += '&' + key + '=' + json[key];
qstring = qstring.substr(1); //removing the first redundant &
}
var urlTarget = 'abc.html';
var urlTargetWithParams = urlTarget + qstring;
//will go to abc.html?key1=value1&key2=value2&key2=value2...
window.location.href = urlTargetWithParams;
}
On the next page, call getParameterMap.
var jsonRebuilt = getParameterMap();
//use jsonRebuilt
Hope this helps (some extra statements are there to make things very obvious). (And remember, this is most likely a wrong way of doing it, as people have pointed out).
Here is my post about communicating between two html pages, it is pure javascript and it uses cookies:
Javascript communication between browser tabs/windows
you could reuse the code there to send messages from one page to another.
The code uses polling to get the data, you could set the polling time for your needs.
You have two options I think.
1) Use cookies - But they have size limitations.
2) Use HTML5 web storage.
The next most secure, reliable and feasible way is to use server side code.
I have a background script that is responsible for getting and setting data to a localStorage database. My content scripts must communicate with the background script to send and receive data.
Right now I send a JSON object to a function that contains the command and the data. So if I'm trying to add an object to the database Ill create JSON that has a command attribute that is addObject and another object that is the data. Once this is completed the background scripts sends a response back stating that it was successful.
Another use case of the function would be to ask for data in which case it would send an object back rather than a success/fail.
The code gets kind of hacky once I start trying to retrieve the returned object from the background script.
It seems like there is probably a simple design problem to follow here that I'm not familiar with. Some people have suggested future/promise design problems but I haven't found a very good example.
Content Script
function sendCommand(cmdJson){
chrome.extension.sendRequest(cmdJson, function(response){
//figure out what to do with response
});
}
Background script
if (request.command == "addObject"){
db[request.id]= JSON.stringify(request.data);
sendResponse("success");
}
else if(request.command == "getKeystroke"){
var keystroke = db[request.id];
sendResponse(keystroke);
}
Your system looks OK and here are some minor improvements.
For each remote command send back the same type of object (with possibly empty fields):
var response = {
success: true, // or false
data: {},
errors: [],
callback: ''
}
Also, if you have multiple different commands which send back data, you may replace if-else with an object lookup:
var commands = {
addObject: function () { /* ... */ },
getKeystroke: function (request, response) {
response.data = db[request.id]
}
}
Then if you have any data to response with, just add it to the object. And send the same object for any command:
var fn = commands[request.commands]
fn(request, response)
As for figuring out what to do with response, I'd pass a callback into the sendCommand function and let the content scripts request and process the response data as they see fit:
function sendCommand(cmdJson, callback){
chrome.extension.sendRequest(cmdJson, callback)
}