Is there a way to make async functions return a value inside ejs? - ejs

I'm using template like this
<%= (async ()=>{return "some test here";})() %>
after rendering, I'm getting Object Promise, but I need just a value. Example of rendering
let result = ejs.render('<%= (async ()=>{return "some test here";})() %>');
console.log("result = "+result);
let neededResult = ejs.render('<%= (()=>{return "some test here";})() %>');
console.log("neededResult = "+neededResult);
<script src="https://cdn.jsdelivr.net/npm/ejs#3.1.6/ejs.min.js"></script>
Is there a way to convert promise to a value in ejs template?

Related

How to show Axios response data into DataTable using Jquery

Hello guys i have this problem i have been trying to fix for days now.
Am making a post request to my PHP server to fetch results from database. Now am using JS map function to populate the results into table.
Am using DataTable which populates and show results but when i try to search for Student using DataTable search everything disappears and show "No Results Found"
Need help to make pagination and search, sorting work.
i have provided my script and html code below
student.ejs //HTML page containing students table
<thead>
<tr>
<th class="text-center">Name</th>
<th class="text-center">Index No</th>
</tr>
</thead>
<tbody id="tableData" class="text-center"></tbody>
</table>
<!-- fetch -->
<script>
axios.get('myFetchAPIHere')
.then(function(response){
let finalData = response.data;
let tableData = "";
finalData.map((values) => {
tableData += `<tr class='text-center'>`;
tableData += `<td class='fw-bolder text-dark'>${values.fullname}</td>`;
tableData += `<td class='text-primary fw-bolder'>${values.index_no}</td>`;
tableData += `</tr>`;
});
document.getElementById('tableData').innerHTML = tableData;
})
.catch(function(error){
console.log(error);
})
</script>
<script>
// Jquery Datatable
let jquery_datatable = $("#table1").DataTable({)
</script>
Order of Execution
You have two scripts in your page. The second script initializes your JavaScript datatable:
$("#table1").DataTable();
However, it is being executed before the first script finishes.
This means that DataTables finds an empty <html> table - and therefore the DataTable contains no data. When you perform any DataTables operation such as filtering or sorting, DataTables re-displays its data - which is no data at all.
Your first script starts before your second script starts... but the first thing it does is to issue an Ajax call using your axios library. This is an asynchronous event - so it waits for the response before it executes its .then function.
While it is waiting for that callback, the second script runs (as described above).
Now, after the Ajax call has returned its data, your first script builds the HTML table - and that is what you get to see in your web page.
It's not showing you a DataTable - it's just showing you a raw HTML table. And (as noted already) that is why all its data disappears as soon as you try to use the DataTable.
Quick Fix
The simplest fix is to delete that second script, and then place the following line...
let jquery_datatable = $("#table1").DataTable();
...inside the .then function, at the very end:
<script>
$(document).ready(function() {
axios.get('myFetchAPIHere')
.then(function(response) {
let finalData = response.data;
let tableData = "";
finalData.map((values) => {
tableData += `<tr class='text-center'>`;
tableData += `<td class='fw-bolder text-dark'>${values.fullname}</td>`;
tableData += `<td class='text-primary fw-bolder'>${values.index_no}</td>`;
tableData += `</tr>`;
});
document.getElementById('tableData').innerHTML = tableData;
// place the DataTables initialization command here:
let jquery_datatable = $("#table1").DataTable();
}); // note how the above command MUST BE INSIDE the "then" function
});
</script>
Note how I have also wrapped everything inside a $(document).ready(function() { ... } - so that no JavaScript starts running until the page is ready.
If you are interested, you can prove to yourself what is happening with your existing code, by adding console.log() statements to your code.
For example:
<script>
console.log( 'step 1: ' + Date.now() );
axios.get('myFetchAPIHere')
.then(function(response){
console.log( 'step 2: ' + Date.now() );
let finalData = response.data;
let tableData = "";
finalData.map((values) => {
tableData += `<tr class='text-center'>`;
tableData += `<td class='fw-bolder text-dark'>${values.fullname}</td>`;
tableData += `<td class='text-primary fw-bolder'>${values.index_no}</td>`;
tableData += `</tr>`;
});
document.getElementById('tableData').innerHTML = tableData;
console.log( 'step 3: ' + Date.now() );
})
.catch(function(error){
console.log(error);
})
</script>
<script>
// Jquery Datatable
console.log( 'step 4: ' + Date.now() );
let jquery_datatable = $("#table1").DataTable({)
console.log( 'step 5: ' + Date.now() );
</script>
Take a look at what order the steps are printed in the browser's console (F12 to open).
Quick fix I found:
I deleted the Axios call and used Ajax as suggested by andrewJames
<script>
// Jquery Datatable
let jquery_datatable = $("#table1").DataTable({
ajax:{
url:"Your API CALL",
type: "GET",
dataSrc:"",
},
// fetch all the columns in your json object array
"columns" :[
{"data" : "fullname"},
{"data" : "index_no"}
]
})
</script>

Prefill Mustache.JS Template with Values from Mongo DB (Mongoose)

I am currently having a list with some entries in my database. Now i want the users to be able to edit one of those entries.
When the "Edit" Button is clicked, it should load the original form and prefill all the fields with the values already stored in the database.
I used a mustache template for my form, looking like this:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1>Issue Form</h1>
<p>{{ errors }}</p>
<form method="post">
<label>Title: <br><input type="text" name="title">{{ value }}</label><br>
<label>Description: <br><textarea type="text" name="description">{{ value }}
</textarea></label><br>
<label>Priority: <br>
<select name="priority">
<option>high</option>
<option>medium</option>
<option>low</option>
</select>
</label><br>
<input type="submit" value="Save Entry">
</form>
</body>
</html>
This is my mongoose schema:
var issueSchema = new mongoose.Schema({
title: String,
description: String,
priority: String
});
I of course did a lot of researche on how to fill my fields. I read about the mongoose "populate()" function, but when i tried to use it, there was always some errors telling me that the function itself is undefined.
Another option was using a JSON file to store the data values, but i cannot do this in this example since the values should always be stored in my MongoDB data folder.
Another version i found was creating an object via the toObject() function. But anytime i tried that out:
router.get('/edit/:id', (req, res) => {
var objectForEditing = issueModel.findOne(req.params.id).toObject;
console.log(objectForEditing);
res.render('issueFormEdit');
});
The console.log part shows me the object as undefined.
Using JQuery like i did in any other javascript file before didn't work either, even when including the modules.
I simply need a method to connect my javascript code with my hjs file. But i simply am not able to do so, my knowledge is not enough for this. I really tried out a lot and have invested hours so far. But i simply can't get to the bottom on how to connect these two files.
This is my first time ever working with this combination of Mustache.JS and MongoDB/Mongoose/Express. Please be gentle :(
If any more code is needed, please just let me know.
Your code has the following list of issues:
1) Model.prototype.findOne() method is asynchronous, so you either need to use async/await or use promises before calling toObject() on it.
2) You are querying mongoose in the wrong way. You need to use findOneById(id) or findOne({ _id: id }).
3) toObject is a function, so it has to be called.
4) objectForEditing needs to be passed to res.render function as the second argument which represents locals, which basically is:
an object whose properties define local variables for the view
Try this code (async/await):
router.get('/edit/:id', async (req, res) => {
let objectForEditing = await issueModel.findOneById(req.params.id);
objectForEditing = objectForEditing.toObject();
res.render('issueFormEdit', objectForEditing);
});
Using Promises:
router.get('/edit/:id', (req, res) => {
issueModel.findOneById(req.params.id)
.then(issue => {
const objectForEditing = issue.toObject();
res.render('issueFormEdit', objectForEditing);
});
});

TypeError: Cannot read property 'then' of undefined in protractor-cucumber

I am using cucumber 3 with protractor 5.2.2. and i have given the url in my config file as baseUrl: 'https://www.linkedin.com' and i have to check whether navigated to the home page after clicking login.Instead of passing URL "https://www.linkedin.com/feed" ,i have pass "feed" and given split method in my step.js file.
my feature file is given below
When I enter "qwerty" in ".username"
And I enter "Passw0rd" in ".password"
And I click on ".login"
Then I should be at the "feed"
and in my step.js
Then(/^I should be at the "(.*)"$/, function (url) {
var geturl=browser.getCurrentUrl() + '';
var res=geturl.split("/");
var result=res[1];
return expect(result).to.eventually.equal(url);
});
My fourth step failed and getting error "TypeError: Cannot read property 'then' of undefined".where i am going wrong in my step.js file.Or how can i check the remaining part of base url when i am on inner page which having a url format of "base.com/feed/profile/profile-edit".Thanks in advance.
Explain your code issue inline at below.
Then(/^I should be at the "(.*)"$/, function (url) {
var geturl=browser.getCurrentUrl() + '';
// browser.getCurrentUrl() return a pomise which it's also a javascript object
// in javascript claculate `an object + ''`, will convert the object
// to string firstly by toString() function,
// if the object not overwrite the supper toString() function,
// it will return an string "[object Object]"
// So geturl = "[object Object]"
var res=geturl.split("/");
// there is no "/" in geturl, so the array length of res is 1
var result=res[1];
// res[1] exceed array length, so result = undefined
return expect(result).to.eventually.equal(url);
// because you used eventually at here, so chai will regard result is a promise,
// chai will check the argument of expect(xxx) is a promise or not
// by detect xxx has property: then via calling xxx.then in chai's inside code,
// but result is undefined, of course has no property: 'then'.
});
You have to consume promise eventual value in then()
Then(/^I should be at the "(.*)"$/, function (url) {
return browser.getCurrentUrl().then(function(cururl){
var parts = cururl.split("/");
return expect(parts[parts.length-1]).to.equal(url);
// dont't use eventually at here, because parts[parts.length-1] is not promise
});
});

Jade + mongodb + express.js, delete form not working

My delete code is not working and I think not even firing as I don't see my console.log, I have an add button that works with a form and they look alike, this is why I don't get it.
app.js:
var db = monk('localhost:27017/mongodb');
Jade:
extends admin_menu
block content
h1.
Cocktail list
ul
each cocktail, i in cocktaillist
li
p= cocktail.name
form#form_delete_project(name="/admin/delete_cocktail", method="post", action="/admin/delete_cocktail")
input#input_name(type="hidden", placeholder="", name="_id", value="#{cocktail._id}")
button#submit_project(type="submit") delete
index.js:
router.post('/admin/delete_cocktail', function(req, res) {
console.log(id)
// Set our internal DB variable
var db = req.db;
// Get our form values. These rely on the "name" attributes
var id = req.body._id;
// Set our collection
var collection = db.get('cocktailcollection');
// Submit to the DB
collection.remove({
"_id":id
}, function (err, doc) {
if (err) {
// If it failed, return error
res.send("There was a problem removing the information to the database.");
}
else {
// And forward to success page
res.redirect("/admin/cocktail_list");
}
});
});
Jade is built on indentation. Since you are not indenting the items in your form it is not in you form. In html your code would look like this:
<form>
</form>
<input name="_id">
<button>
Since your input with _id is outside the form it is not being posted. That is why your console log is showing nothing. There is no req.body._id.And, of course, your submit-button is also outside the form. So it does nothing.
So, the first thing you should do is indent the code.

callback function after submitting a form

I have the following form :
Is there a way to add a callback function to the form after it is submitted? Basically I am echoing the result of upload.php to an iframe and what I want to do is to get that information using a callback function.
You want to use Ajax to submit the post, and have the javascript catch the echo in a result and write out the HTML to the iframe.
As Gnostus says: use Ajax to submit the form, and attach a function for when the ajax has completed and has received a response... something like this (javascript)
// microsoft does their XMLHttpRequest differently, so make a different object for them.
var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
// this point is reached when ajax has completed
var output = xmlhttp.responseText;
doWhateverFunctionYouLike(output);
}
xmlhttp.open("GET","http://some.url.here,true);
xmlhttp.send();
Don't forget to get the values out of your form, do something like:
val1 = form.getElementsByTagName("input")[0].value;
val2 = form.getElementsByTagName("input")[1].value;
and submit them with the ajax call...
xmlhttp.open("GET", "http://some.url.here/?a=" + val1 + "&b=" + val2, true);
you get the idea.