NodeJS & Jade/Pug variables not defined in jade script? - javascript

When I pass a variable over to jade, it looks like it works correctly, for example #{myvar} works but, when I try to call it in a script block in Jade, it doesn't load at all. Upon doing a typeof(myvar) in my script block it said that it was undefined at one point but now it doesn't return anything. My code looks something like this:
- typeof(rm120[0].description) <---- Returns string
div#change !{rm120[0].description} <----- Works perfectly fine
div#test
script.
change.innerHTML = "test code" <------ Works perfectly fine
test.innerHTML = rm120[0].description
test.innerHTML = typeof(rm120)
test.innerHTML = typeof(locals.rm120)
all the lines after the first one in script. seems to never load or just get ignored and I'm extremely confused as to why I can't use the objects I passed through from my node.js file in my script block. Any help would be much appreciated!

The script tag in Pug renders text which is sent to the client to run as client side Javascript. As server side variables don't exist on the client, they need to be passed across to the client somehow.
Two possible ways are rendering the variables in Pug or passing the data out via an AJAX call.
Render
Rendering variables into the Javascript is the simplest method to pass data but I tend to keep this limited to very simple, bootstrap data required for the JS App.
script.
let rm120 = !{JSON.stringify(rm120)}
console.log(rm210)
AJAX
Using an API endpoint to pass JSON objects out is more complicated to setup as there needs to be a server endpoint and you start dealing with async requests. As an app starts passing more data, or more complex data, then it's a more scalable method of sharing.
script.
fetch("/api/v1/rm120")
.then(response => response.blob())
.then(body => {
console.log(body)
})
.catch(err => console.log(err))

I assume you're trying to insert the actual value of rm120[0].description on your html file, which you want to run as a script once it's delivered to client side. In which case you need to use #{} or !{}.
If you don't, then the word "rm120[0].description" will be written onto your html file, quite literally. And when it runs client side, there won't be an rm120 presumably.

Related

Pass Data From Node/Express to Front-End Javascript

I am unsure how this would work exactly, and I am unable to find my answer from searching for it. I am working with a node and express server, and have been passing data to my front end ejs without issues. Now, I am trying to implement charts.js in my front-end, and that requires the data to be in a front-end javascript file. I know that to pass data to my ejs file, I use something like this:
res.render("dashboard", {data: data});
and to display the data in the ejs file, I use
<%= data %>
Now, what I would like to do, is basically the same thing, but instead of passing the data into an ejs file, I want to pass it into a javascript file, while still displaying the ejs file. Right now, I can't seem to figure out how I go from having my data in the express server, and returning it into a front-end javascript file. The flow I am looking for would be something like this:
In node:
data = []:
res.render("dashboard", {data: data});
and then the ejs file is rendered and data is passed into the front-end javascript file that is being used within the ejs file:
let data = <%= (data array passed from the node server here) %>
Of course, this is not the correct way to write the code, but this is the basic logic I am trying to implement.
I am sure this is something simple, but I can't seem to find the answer within my context here. Are there any resources where I can learn to do what I am trying to do? Thanks.
You can't respond to a single request with both an HTML document and a seperate JavaScript file.
So you need to either:
Store the data somewhere and, in a separate endpoint, serve up some generated JavaScript and have a mechanism which identifies which data to serve up when the request is made. (NB: This is stupidly complex. Don't do it.)
Generate the JavaScript inline in the HTML document inside a <script> element. (You'll need to properly escape the data as JS to make sure you aren't subject to XSS).
Output the data into the HTML document (e.g. with data-* attributes or <meta> elements) and read it with static JavaScript.
Again, using a seperate endpoint: Serve up JSON with the data in it and read that with Ajax from a static JS file. (Again, you'll need a way to determine which data to send for that particular request).

Serve files from Apache to Javascript

I am writing my first web application with Javascript and WebGL. For now I am running the app on localhost from Apache. The app needs to work with data that is provided instantly. Until now I worked with AJAX calls that happen during runtime which doesn't work out for my purposes anymore. So instead of serving individual files from Server to Client when asked, I want the application to load all files from the Server to Client side at initialization time (I want this to happen automatically at the start so I don't have to add every new file as a url in the html index). I understand I should do this with Server Side scripting; probably with PHP since I have a Apache localhost? I have different folders which hold my necessary resources in a uniform dataformat (.txt, .png and .json). So what I want to do is, before the Javascript app starts, look through the folder and send one object per folder that holds filenames as keys bound to filedata. Is my intuition right that I need to do that with PHP? If yes, where do I start to tell my application what to do when (first start serving files with php, then start the javascript app)? How do I do this on localhost? Should I already think about extending my toolset (e.g. using nodeJS on ServerSide(locally for now))? If so what lightweight tools do you propose for this kind of work? I feel I am missing some design principles here.
EDIT:
Keep in mind that I don't want to specifically call a single file... I am already doing that. What I need is a script that automatically serves all the files of a certain folder on the server to the client side at init time of the app before the program logic of the actual application starts.
Your question is kind of broad so I'll try my best. Why does AJAX not work for real-time data but loading all the files once does? If you're working with real time data, why not look into a websocket or at the bare minimum, AJAX queries?
If you want to pass data from the server to the client, you will need to use a HTTP request no matter what. A GET request or POST request is necessary for the client to request data from the server and receive it as a response.
You could theoretically just pass the data from PHP straight to the view of the application (which is technically done through a GET request whenever a user requests data such as .php files from the server) but this isn't as flexible as if Javascript had access to the data. You can do some hacks and 'transfer' the data from the view to Javascript with some .value methods, but this isn't ideal and can be prone to some security holes. This also means data is only being passed once.
So what would need to happen is that the data would need to be processed upon initialization and then immediately transferred to the client by use of Javascript and HTTP requests.
So if you want Javascript to have access to the data and use it in variables or manipulate it further, then you'd need to use an HTTP request such as GET or POST which is called by Javascript. Otherwise, you need to immediately pass the data to the view upon initialization (through PHP), but this means you can't work with real-time data because the data is only being passed once when there is a page refresh.
Example of scandir():
<?php
//scandir() returns filenames, not data from files
$fileArray = scandir('datafolder/') //this is a relative path reference to the folder 'datafolder'
$finalArray = [];
foreach($fileArray as $filename){
tempArray = [];
$file = fopen('datafolder/' . $filename, 'r'); //im pretty sure scandir only retrieves the filenames and not the path, so you might need to append the filepath so your script knows where to look
$tempArray = fgetcsv($file, 1024); //temp array to hold contents of each iteration of foreach loop
array_push($finalArray, $tempArray); //this will store the data for later use
}
Or the data can be used however, depending on what it is. Say, if you need to combine the data from multiple .csv files, you can read each file and append it to a single array. If you want to read multiple distinct files and preserve the independence of each file, you can create multiple arrays and then pass back a single JSON encoded object that contains each file's data as a separate attribute of the object such as:
{
'dataOne': [0,1,2,3,4,5,6...],
'dataTwo': ['new', 'burger', 'milkshake'],
'dataThree': ['Mary', 'Joe', 'Pam', 'Eric']
}
Which can be created with a PHP associative array using one of the following methods:
//assuming $arrayOne is already assigned from reading a file and storing its contents within $arrayOne
$data['dataOne'] = $arrayOne;
// or
array_push($data['dataTwo'], $arrayTwo);
// or
array_push($data, [
'dataThree' => ['Mary', 'Joe', 'Pam', 'Eric']
]);
Then $data can simply be passed back which is a single array containing all the different sets of data, if each set needs to be distinct.

Sending an html file with json AND having the browser reload that json without reloading page

I am trying to write a browser-server program where the browser sends an http get to 'http://localhpost:3000/param=something'. The server should return an html page and a json. I tried using res.render() where I pass the json as a parameter (it is an array) but render won't work. Here's my code in app.js:
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
and here's the index.js which answers the http request:
router.get('/:screen', function(req, res, next) {
var arr = Array();
res.render('main.html', { playlist : arr });
});
The error I get is:
Error: Cannot find module 'html'
Now, even if that works, I still have to somehow get an updated json (the array) from the server every minute without reloading the page. I succeeded in doing that partially where I access the main json (the array) that is stored in the shared library and load it using ajax. That works, but the program needs to get a sub-json of that one that is relevant to the 'screen' parameter that was sent in the original http get.
In order to do that I need a way to make the server re-calculate the sub-json from the original one and re-send it to me without reloading the page.
As to research and things I've tried:
Problem 1: I searched a lot through this site and found a couple of solutions that none worked for me. It might be a version problem or anything else that I'm not paying attention to but I've made all the changes I'm supposed to in order to make 'render()' work on html. I just kept getting this error.
Problem 2: As I've already explained, I found a way to get the original json but can't figure out how to get the sub-json. here's the code in main.html (which is sent back regardless of the parameter 'screen' as part of the original get request):
$.get("http://localhost:3000/ads.js", function(data, status){
playlist = JSON.parse(data);
});
I would very much appreciate any help regarding any of these problems.
Note: I included those two problems in the same question because they are connected to each other. Both requests should make the server calculate a sub-json and send it. One request will send it back as part of an html file and the other will be loaded into that page without reloading the whole page. Solving one of these problems directly affects the other so I chose to include them both here.
Alright so here's how I solved all those problems:
As for the render() function I learned that you need to change your view engine somehow so I didn't use it.
Instead, I sent the main html file to all stations using 'sendFile()'. Inside that html file I included ajax requests (which kept the site from reloading). I set the 'url' to 'window.location.href' which included the parameter needed.
At the server side I used separate functions for dealing with requests. One that sends back the main html file and the other calculates the sub-json using the parameter in the url and sends it back to the user.

Html button to send a post request to retrieve information from .json in a table

I have a simple html file that has a button called Display Animal. I have a seperate .json file that has various animals stored in some way. What I am trying to do is on click of Display Animal I want to fetch the information from this json file and display it in a table on the screen. I am using Express, Node, jQuery and Javascript. Note that I am running server that displays the simple html file. I am little unsure of the structure of how to do this? Like in my html file do I have my onClick method there or in my server file? Also, how do I fetch this information? I am trying to accomplish this using GET or POST requests.
Are you using a front-end library (like jQuery or Angular) or are you trying to do this natively with JavaScript?
If the former, there are HTTP request APIs built into each (e.g. jQuery.POST(), or $http). If the latter, you'll want to look into native XMLHttpRequest.
Not a sophisticated answer, but your question is very broad. I'll leave reading the documentation to you.
Create a get service on your backend, with express it would be something like
var app = express();
app.get ('/animals', function (req, res){
// your code to parse and return your list of animals, function (err, data) {
res.end (data) }
That's not 100% working code but gives you an idea how the get will be formatted.
Then you can either use jquery.get () with your button onclick or write out a javascript xmlhttprequest.
Jquery would be easier but for you want to do it yourself there are tons of tutorials on writing a xhr in javascript.
EDIT: I wrote this in response to a get request. If you want to use post it's essentially the same, use jquery.post () as the other answer suggests and instead of app.get it would be app.post.
For data like animals I'd use get, you are only showing information with no need to change it and a unless you are passing sensitive information get will serve your purposes fine.

JavaScript code on rails console

I use binding.pry in somewhere in Cabypara code for debugging, and i want to check the value of html element using jQuery.
I can't use debugger, then check the value from browser, because this code is Cabybara code for testing as example:
When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
select(value, :from => field)
binding.pry
end
How can i check the value of this field by jQuery code as $("##{field}").val() on rails console ?
This answer depends on #apneadiving's comment:
Rails console used for server side only, not for client side, these helper links:
Ruby-on-Rails is server side.
Rails console is useful for testing out quick ideas with code and changing data server-side without touching the website.
You can call binding.pry while Rails is rendering your view, even in the javascript portion of the view.
This is not going to give you access to the the client side code. Like #apneadiving and #mohamed-yakout stated you can't access the client from the server, but it can give the the access to all of the server side information that is available at that moment in the rendering process.
erb:
<script>
// some javascript...
"<% binding.pry %>"
</script>
// Note: You can not do this from `.js` files that are assets of the view without
// adding the `.erb` extension to the javascript files.
This may be helpful in checking values being utilized by JQuery or Javascript and verifying that they are being built correctly at this step in the process. Ex: verifying the collection being used to generate the rows of a table
In your case you could verify the value of field, but not the value of the element found by the id being passed by the field variable.
$("##{field}").val()
This can be helpful when the result of "##{field}" is giving an #unexpected result instead of an #expected one, since you can't access the server side code from the client to determine the rendering problem.
Note: This translates to Slim as well
javascript:
// some javascript...
"#{binding.pry}"

Categories

Resources