how can I make the DOM work with ejs and Mysql - html

I want to compare "test" with "angendaOficina".
test is a DOM element.
angendaOficina is a table in Mysql database.
When I run the code it tells me that test is not defined and I understand that it is because of the <%%> that I can, but if I remove it, it tells me that document is not defined.
<form name="formulario">
<div><input name="busqueda" placeholder="BUSCAR" required type="text" autofocus></div>
</form>
<div><button id="btn">BUSCAR</button></div>
<script>
function operation() {
var test = document.formulario.busqueda.value;
<% for (var i = 0; i < angendaOficina.length; i++){%>
<%if(angendaOficina[i].carpeta == test){
console.log("MATCH");
}else{
console.log("NO MATCH");
}
%>
<%}%>
}
var btn = document.getElementById("btn");
btn.addEventListener('click', operation, true);

I can't really do exactly what you wanna do, but i can at least help you to solve your problem.
You should not use EJS to import your database like this.
If you want to use your DB data like this, import it in the HTML JavaScript using GET requests.
To do requests you can either use a module like jQuery (which i don't recommend but it is surely the most known) or use the defaults XMLHttpRequest.
You can handle thoses requests in your express server like this :
expressApp.get("/getDatabase", (req, res) => { // "/getDatabase" is the url you wanna GET request.
res.json({
data: dbObject // "dbObject" is your DB data object.
})
})
Then, when you do a request to "/getDatabase" you will get a JSON object that contains data as your database data.

Related

Composable functions in Puppeteers page.Evaluate

I'm relatively new to puppeteer and I'm trying to understand the patterns that can be used to build more complex apis with it. I am building a cli where I am running a WebGL app in puppeteer which i call various functions in, and with my current implementation i have to copy and paste a lot of setup code.
Usually, in every cli command i have to setup pupeteer, setup the app and get access to its api object, and then run an arbitrary command on that api, and get the data back in node.
It looks something like this.
const {page, browser} = await createBrowser() // Here i setup the browser and add some script tags.
let data;
page.exposeFunction('extractData', (data) => {
data = data;
})
await page.evaluate(async (input) => {
// Setup work
const requestEvent = new CustomEvent('requestAppApi', {
api: undefined;
})
window.dispatchEvent(requestEvent);
const api = requestEvent.detail.api;
// Then i call some arbitrary function, that will
always return some data that gets extracted by the exposed function.
const data = api.arbitraryFunction(input);
window.extractData(data)
}, input)
What i would like is to wrap all of the setup code in a function, so that i could call it and just specify what to do with the api object once i have it.
My initial idea was to have a function that will take a callback that has this api object as a parameter.
const { page, browser } = wait createBrowser();
page.exposeFunction(async (input) =>
setupApiObject(((api) =>
api.callSomeFunction(input)
), input)
However, this does not work. I understand that puppeteer requires any communication between the node context and the browser to be serialised as json, and obviously a function cant be. Whats tripping me up is that I'm not actually wanting to call these methods in the node context, just have a way to reuse them. The actual data transfer is already handled by page.exposeFunction.
How would a more experienced puppeteer dev accomplish this?
I'll answer my own question here, since i managed to figure out a way to do it. Basically, you can use page.evaluate to create a function on the window object that can later be reused.
So i did something like
await page.evaluate(() => {
window.useApiObject = function(callback: (api) => void){
// Perform setup code
callback()
}
})
Meaning that later on i could use that method in the browser context and avoid redoing the setup code.
page.evaluate(() => {
window.useApiObject((api) => {
api.someMethod()
})
})

POST to local json file without server, using Svelte and Routiify

Im writing an PWA in Svelte with Routify and im trying to save notes (containing id, title and a body) in a local json file.
Ive been following this code from Svelte REPL (Svelte POST example), but they use an web URL. When trying to use a direct link i get a 404, even tho the path is correct.
<script>
let foo = 'title'
let bar = 'body'
let result = null
async function doPost () {
const res = await fetch('https://httpbin.org/post', {
method: 'POST',
body: JSON.stringify({
foo,
bar
})
})
const json = await res.json()
result = JSON.stringify(json)
}
</script>
<input bind:value={foo} />
<input bind:value={bar} />
<button type="button" on:click={doPost}>
<p>Post it.</p>
</button>
<p>Result:</p>
<pre>
{result}
</pre>
I installed a json server plugin, which kinda worked, but i want to store the data as a local file.
Is it possible to write, using POST to a local json file without using any server?
Is it possible to use relative path when using fetch? Or should i use something else?
Generally, you don't POST data anywhere else but to a server. Having said that, if you absolutely want to save your data using POST, you can add a serviceworker to your app that intercepts the fetch() request and then saves the data in cache, indexeddb, localstorage or something like this. But having that serviceworker in between just for that is a bit silly, you should rather store the data directly in cache, indexeddb or localstorage.
Example for localstorage:
const data = { someKey: { someOtherKey: 'some value' } };
localStorage.setItem('myData', JSON.stringify(data));
Be aware though that, no matter which kind of storage you're using, they all might be wiped out if the user decides to clear browser data or if the browser cleans up by itself due to storage shortage.

How to get around previously declared json body-parser in Nodebb?

I am writing a private plugin for nodebb (open forum software). In the nodebb's webserver.js file there is a line that seems to be hogging all incoming json data.
app.use(bodyParser.json(jsonOpts));
I am trying to convert all incoming json data for one of my end-points into raw data. However the challenge is I cannot remove or modify the line above.
The following code works ONLY if I temporarily remove the line above.
var rawBodySaver = function (req, res, buf, encoding) {
if (buf && buf.length) {
req.rawBody = buf.toString(encoding || 'utf8');
}
}
app.use(bodyParser.json({ verify: rawBodySaver }));
However as soon as I put the app.use(bodyParser.json(jsonOpts)); middleware back into the webserver.js file it stops working. So it seems like body-parser only processes the first parser that matches the incoming data type and then skips all the rest?
How can I get around that? I could not find any information in their official documentation.
Any help is greatly appreciated.
** Update **
The problem I am trying to solve is to correctly handle an incoming stripe webhook event. In the official stripe documentation they suggested I do the following:
// Match the raw body to content type application/json
app.post('/webhook', bodyParser.raw({type: 'application/json'}),
(request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig,
endpointSecret);
} catch (err) {
return response.status(400).send(Webhook Error:
${err.message});
}
Both methods, the original at the top of this post and the official stripe recommended way, construct the stripe event correctly but only if I remove the middleware in webserver. So my understanding now is that you cannot have multiple middleware to handle the same incoming data. I don't have much wiggle room when it comes to the first middleware except for being able to modify the argument (jsonOpts) that is being passed to it and comes from a .json file. I tried adding a verify field but I couldn't figure out how to add a function as its value. I hope this makes sense and sorry for not stating what problem I am trying to solve initially.
The only solution I can find without modifying the NodeBB code is to insert your middleware in a convenient hook (that will be later than you want) and then hack into the layer list in the app router to move that middleware earlier in the app layer list to get it in front of the things you want to be in front of.
This is a hack so if Express changes their internal implementation at some future time, then this could break. But, if they ever changed this part of the implementation, it would likely only be in a major revision (as in Express 4 ==> Express 5) and you could just adapt the code to fit the new scheme or perhaps NodeBB will have given you an appropriate hook by then.
The basic concept is as follows:
Get the router you need to modify. It appears it's the app router you want for NodeBB.
Insert your middleware/route as you normally would to allow Express to do all the normal setup for your middleware/route and insert it in the internal Layer list in the app router.
Then, reach into the list, take it off the end of the list (where it was just added) and insert it earlier in the list.
Figure out where to put it earlier in the list. You probably don't want it at the very start of the list because that would put it after some helpful system middleware that makes things like query parameter parsing work. So, the code looks for the first middleware that has a name we don't recognize from the built-in names we know and insert it right after that.
Here's the code for a function to insert your middleware.
function getAppRouter(app) {
// History:
// Express 4.x throws when accessing app.router and the router is on app._router
// But, the router is lazy initialized with app.lazyrouter()
// Express 5.x again supports app.router
// And, it handles the lazy construction of the router for you
let router;
try {
router = app.router; // Works for Express 5.x, Express 4.x will throw when accessing
} catch(e) {}
if (!router) {
// Express 4.x
if (typeof app.lazyrouter === "function") {
// make sure router has been created
app.lazyrouter();
}
router = app._router;
}
if (!router) {
throw new Error("Couldn't find app router");
}
return router;
}
// insert a method on the app router near the front of the list
function insertAppMethod(app, method, path, fn) {
let router = getAppRouter(app);
let stack = router.stack;
// allow function to be called with no path
// as insertAppMethod(app, metod, fn);
if (typeof path === "function") {
fn = path;
path = null;
}
// add the handler to the end of the list
if (path) {
app[method](path, fn);
} else {
app[method](fn);
}
// now remove it from the stack
let layerObj = stack.pop();
// now insert it near the front of the stack,
// but after a couple pre-built middleware's installed by Express itself
let skips = new Set(["query", "expressInit"]);
for (let i = 0; i < stack.length; i++) {
if (!skips.has(stack[i].name)) {
// insert it here before this item
stack.splice(i, 0, layerObj);
break;
}
}
}
You would then use this to insert your method like this from any NodeBB hook that provides you the app object sometime during startup. It will create your /webhook route handler and then insert it earlier in the layer list (before the other body-parser middleware).
let rawMiddleware = bodyParser.raw({type: 'application/json'});
insertAppMethod(app, 'post', '/webhook', (request, response, next) => {
rawMiddleware(request, response, (err) => {
if (err) {
next(err);
return;
}
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
// you need to either call next() or send a response here
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
});
});
The bodyParser.json() middleware does the following:
Check the response type of an incoming request to see if it is application/json.
If it is that type, then read the body from the incoming stream to get all the data from the stream.
When it has all the data from the stream, parse it as JSON and put the result into req.body so follow-on request handlers can access the already-read and already-parsed data there.
Because it reads the data from the stream, there is no longer any more data in the stream. Unless it saves the raw data somewhere (I haven't looked to see if it does), then the original RAW data is gone - it's been read from the stream already. This is why you can't have multiple different middleware all trying to process the same request body. Whichever one goes first reads the data from the incoming stream and then the original data is no longer there in the stream.
To help you find a solution, we need to know what end-problem you're really trying to solve? You will not be able to have two middlewares both looking for the same content-type and both reading the request body. You could replace bodyParser.json() that does both what it does now and does something else for your purpose in the same middleware, but not in separate middleware.

How do I send data from express => html

So say I have some form data in express right, and I'm checking it against a db. Say it doesn't find the db, so I have an if then statement for that. How would I edit a p element in a separate html file to say 'Account not found!' upon this if statement being activated? My code would be something like this..
let userData = keyv.get(username)
if (!userData) {
console.log('couldn't find user')
//edit p element with id status
}
else {
...
}
Thanks.
You need to use a templating engine and pass the userData variable when rendering the view.
You can do something like
app.get('/:id', function(req, res) {
// try to get user data
res.render('pages/index', {userData});
});
userData will be accessible from the view. I recommend you use EJS for this, although there are other engines like Pug, Handlebars, etc
EDIT:
I misunderstood your question, but the answer is the same except you render different data. If the user isn't found then you can render an error message instead.
app.get('/:id', function(req, res) {
// try to get user data. do the following if the user isn't found
res.render('pages/index', {
error: 'User not found'
});
});

Search mysql database with node in html

I connected a database to node and am trying to create an HTML page to search the database. I would rather not use EJS. I think I have to use a POST request in the HTML AJAX and connect it with a POST request in node.
Here is what I'm thinking:
app.post("/cities/:city", function(req, res) {
db.hospitalinfo.findAll({
where: { city: req.params.city }
}).then(function (result) {
res.json(result);
console.log("res--->"+result);
console.log("req--->"+req.params.city);
});
});
Here's the HTML:
<form id="author-form" method="POST">
<select id ="dropDownId">
<option value="Opp" >Opp</option>
<option value="Boaz">Boaz</option>
</select>
<input class="SubmitButton" type="submit" id="click" style="font-size:20px;" />
</form>
Now here's where I'm stuck. I need to grab the value from the select statement:
var nameInput = $("#dropDownId :selected");
I don't know how to actually send nameInput to the URL so my post statement will work. I probably don't completely understand how these routes work. This is my first project by myself. I would like to grab the nameInput, send it to the server via AJAX, and search my database with it. Right now it's returning an empty object. Thank you for your help.
You need to make a Ajax call to node server. For that you need to stop the default submit of form.
event.preventDefault();
can be used to stop the normal flow of submitting the form.
Here is an example of ajax call
(document).ready(function() {
// process the form
$('form').submit(function(event) {
// get the form data
// there are many ways to get this data using jQuery (you can use the class or id also)
var formData = {
'name' : $('input[name=name]').val(),
'email' : $('input[name=email]').val(),
};
// process the form
$.ajax({
type: "GET", // define the type of HTTP verb we want to use (POST for our form)
url: "http://localhost:5000/example" // the url where we want to POST
data: formData,
dataType: 'json', // what type of data do we expect back from the server
success: function (data) {
console.log(data.result);
// perform required changes
},
error: function (err) {
console.log(err);
}
});
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
});
});
you can refer this site for more details making ajax calls
I have modified the code taken from there.