Html injection problems on node.js - javascript

Hi i'm trying to inject html code from a String to a view and i'm getting some a error trying to, im stuck:
This is the Code on Node.js route:
router.get('/profile/:page', isLoggedIn, async (req, res) => {
// Get current page from url (request parameter)
let page_id = parseInt(req.params.page);
let currentPage = 0;
if (page_id > 0) currentPage = page_id;
//Change pageUri to your page url without the 'page' query string
pageUri = '/profile/';
/*Get total items*/
await pool.query('SELECT COUNT(id) as totalCount FROM user where user_type="Client"', async (err, result,) => {
// Display 10 items per page
const perPage = 10,
totalCount = result[0].totalCount;
console.log("Estos son los datos",totalCount, currentPage, pageUri, perPage);
// Instantiate Pagination class
const Paginate = new Pagination(totalCount, currentPage, pageUri, perPage);
/*Query items*/
const data = {
users: await pool.query('SELECT * FROM user where user_type="Client" LIMIT ' + 10 + ' OFFSET ' + Paginate.offset),
pages: Paginate.links()// Paginate.lins()->return a variable with all html
}
res.render('profile', { data });
});
});
This is Links() function
class Pagination{
constructor(totalCount,currentPage,pageUri,perPage=2){
this.perPage = perPage;
this.totalCount =parseInt(totalCount);
this.currentPage = parseInt(currentPage);
this.previousPage = this.currentPage - 1;
this.nextPage = this.currentPage + 1;
this.pageCount = Math.ceil(this.totalCount / this.perPage);
this.pageUri = pageUri;
this.offset = this.currentPage > 1 ? this.previousPage * this.perPage : 0;
this.sidePages = 4;
this.pages = false;
}
links(){
this.pages='<ul class="pagination pagination-md">';
if(this.previousPage > 0)
this.pages+='<li class="page-item"><a class="page-link" href="'+this.pageUri + this.previousPage+'">Previous</a></li>';
/*Add back links*/
if(this.currentPage > 1){
for (var x = this.currentPage - this.sidePages; x < this.currentPage; x++) {
if(x > 0)
this.pages+='<li class="page-item"><a class="page-link" href="'+this.pageUri+x+'">'+x+'</a></li>';
}
}
/*Show current page*/
this.pages+='<li class="page-item active"><a class="page-link" href="'+this.pageUri+this.currentPage+'">'+this.currentPage+'</a></li>';
/*Add more links*/
for(x = this.nextPage; x <= this.pageCount; x++){
this.pages+='<li class="page-item"><a class="page-link" href="'+this.pageUri+x+'">'+x+' </a></li>';
if(x >= this.currentPage + this.sidePages)
break;
}
/*Display next buttton navigation*/
if(this.currentPage + 1 <= this.pageCount)
this.pages+='<li class="page-item"><a class="page-link" href="'+this.pageUri+this.nextPage+'">Next</a></li>';
this.pages+='</ul>';
return this.pages;
}
}
module.exports = Pagination;
In the HTML:
<div id="pages">
{{ data.pages }}
</div>
Finally I am getting an error in my browser which does not allow the html that I send from the path to read correctly.
PLZZ HELP ME. IM STUCK
This is pool:
const pool = require('../database');
And this is database.js:
const mysql = require('mysql');
const { promisify } = require ('util');
const { database } = require('./keys');
const pool= mysql.createPool(database);
pool.getConnection((err, connection)=>{
if(err){
if(err.code === 'PROTOCOL_CONNECTION_LOST'){
console.error('DATABASE CONNECTION WAS CLOSED');
}
if(err.code === 'ER_CON_COUNT_ERROR'){
console.error('DATABASE HAS TO MANY CONNECTIONS');
}
if(err.code === 'ECONNREFUSED'){
console.error('DATABASE CONNECTION WAS REFUSED');
}
}
if (connection) connection.release();
console.log('DB is CONNECTED');
return;
});
//Promisify Pool Querys
pool.query = promisify(pool.query);
module.exports = pool;
Also the browser detect only text, not code.
View Source in the browser
enter image description here
Which exact database library are you using?
require('mysql')
And, what exactly is the error in your browser?
enter image description here

Your template engine by default escapes any text that you insert into the page so it will be rendered as text and not accidentally interpreted as HTML. This is why the HTML you inject is displaying as plain text.
If you want to inject actual HTML, then you have to tell the template engine that you don't want it to escape this particular insertion. When you tell us what template engine you're using, we can help you with how you do that.
To stop Handlebars from escaping your HTML, just use triple braces like this:
<div id="pages">
{{{ data.pages }}}
</div>
Here's the relevant doc page that describes it.
Also, await does not work with pool.query() in either of the places you're using it because the mysql module does not support promises and thus await on something other than a promise does nothing useful. You can use the mysql2 module as in require('mysql2/promise') to get built-in promise support with mysql2. Then, don't pass a callback and just use the returned promise.

Related

How to accses to laravel if-else variable with jquery

I have a dating project. We are using laravel 6 and jquery 3.4.1
The problem is that I need to draw a div when receiving AJAX.
So, javascript and blade template :
static countNewMessages() {
$.get('/some/link/here', results => {
let total = 0;
if (results.length === 0) {
$('.chat__list-block').each(function (index) {
$(this).removeClass('chat__list-block_new');
});
$('.chat__list-non-read-counter').addClass('chat__list-non-read-counter_hidden').each(function (index) {
$(this).text('');
});
$('#number-of-new-messages').addClass('d-none').removeClass('d-flex').html('');
$('#inbox-messages-count-title').html('0');
return false;
}
results.forEach(v => {
if (Chat.containers?.threads) {
let threadElement = $('.chat__list-block[data-pid=' + v.from_userid + ']');
threadElement.addClass('chat__list-block_new');
threadElement.find('.chat__list-non-read-counter')
.addClass('chat__list-non-read-counter_hidden')
.text(v.count);
if (0 < threadElement.length && !threadElement.hasClass('chat__list-block_active') && 0 < v.count) {
threadElement.find('.chat__list-non-read-counter')
.removeClass('chat__list-non-read-counter_hidden');
}
}
total += v.count;
$('#number-of-new-messages').addClass('d-flex').removeClass('d-none').html(total);
$('#inbox-messages-count-title').html(total);
});
});
}
#if(count($threads))
<div>Chat requests</div>
#else
<div>No chat requests</div>
#endif
The standard if-else behavior in the template suits me fine. If a user visits the page but has no messages the second block is displayed, and if he has messages the first block is displayed. But if a user who is on the block "no chat requests" and receives new messages then the block "chat requests" is rendered only after a full refresh of the page.
If you need more information, please let me know
Try this :
#if(count($threads))
<div data-threads-count="{{ count($threads) }}">Chat requests</div>
#else
<div data-threads-count="{{ count($threads) }}">No chat requests</div>
#endif
Now you can access threads count by using data function in jquery ex :
$(selector).data('threads-count');
or
$(selector).attr('data-threads-count');
Both will return threads count
i hope it was useful 😊

data extraction with javascript fetch api

I am pulling data with fetch api. but I could not retrieve the data in the todosApi section of the last data I pulled. how can i pull data?
const usersApi = () =>{
fetch("https://jsonplaceholder.typicode.com/users").
then(response=>response.json()).
then(girilenVeri).
catch(e=>console.log(e));
}
const todosApi = (element) =>{
fetch(`https://jsonplaceholder.typicode.com/todos/?userId=${element.id}`).
then(response=>veriOlusturucu(response.json(), element)).//I can't get the data in response.json
catch(e=>console.log(e));
}
const girilenVeri = (data) => {
let cumle = [];
document.getElementById('arama').addEventListener('keydown',function(e){
if(e.keyCode == 8){
cumle.pop();
veriEslestir(data, cumle);
}
});
document.getElementById('arama').addEventListener('keypress',function(e){
cumle.push(String.fromCharCode(e.keyCode));
veriEslestir(data, cumle);
});
}
const veriEslestir = (data,cumle) =>{
veri = cumle.toString().replace(/,/g,"");
data.forEach(element => {
if(element.username.toLowerCase() == veri.toLowerCase()){
todosApi(element);
}
});
}
const veriOlusturucu = (todo,element) => {
console.log(todo);
console.log(element);
let html = "";
html =`
<h5 class="card-title">İletişim</h5>
<ul class="list-group">
<li class="list-group-item">Kullanıcı Adı: ${element.username}</li>
<li class="list-group-item">E-Mail: ${element.email}</li>
<li class="list-group-item">Web Site: ${element.website}</li>
<li class="list-group-item">Şirket: ${element.company.name}</li>
<li class="list-group-item">Telefon No: ${element.phone}</li>
<li class="list-group-item">Adres: ${element.address.street} ${element.address.suite} ${element.address.city} ${element.address.zipcode}</li>
</ul>
<h5 class="card-title">Yapılacaklar Listesi</h5>
<ul class="list-group">
`;
todo.forEach(element=>{//I need to access the data here with loop
html+=`
<li class="list-group-item">Kullanıcı Adı: ${element.title}</li>
`;
});
html +=`</ul>`;
document.getElementById('veriListele').innerHTML=html;
}
document.addEventListener('DOMContentLoaded',usersApi());
How do I return the "response.json" part with a foreach?
There is no problem with user information. but there is a problem with todo information. sends it to me as a promise. I can't access the promise result
If I can get into the "PromiseResult" the problem will be solved. but i can't reach
You're not quite using the fetch api correctly with the todo list. If you notice, on your userApi method, you include an extra .then which is necessary to return the json data rather than the promise:
const usersApi = () =>{
fetch("https://jsonplaceholder.typicode.com/users").
then(response=>response.json()).
then(girilenVeri).
catch(e=>console.log(e));
}
const todosApi = (element) =>{
fetch(`https://jsonplaceholder.typicode.com/todos/?userId=${element.id}`)
.then(response=>response.json())
.then(data => veriOlusturucu(data, element))
catch(e=>console.log(e));
}
Try this out.

Vue.js ignored when a blade is included in another blade

I have created a product card view in Laravel. the card has a simple "accordion" ('Show Details') - closed by default - that is managed by Vue.js as well as a Vue.js quantity counter that changes the weight value in grams if you add products. It all functions very well on the card's view and it looks like this (closed):
I have another view in which I query my DB for product names with Vue.js to display all products of the same name as a result. The problem is when the cards are displayed on that "parent" view, they all appear with the accordion open and the counter is not responsive. It looks like so:
As you can see, the tailwindcss code is rendered without a problem but the Vue.js is being completely ignored (Although the parent view's Vue.js functions work perfectly) What am I doing wrong? What am I missing here? Why are the directives inside the included blade being ignored?
Here is the Vue.js method that manages the (product cards) views integration onto the parent (product name search) view:
setGearItem(gearItem) {
this.gearItem = gearItem;
this.modal = false;
console.log(gearItem);
document.getElementById("displaySearch").innerHTML = "";
axios.get('/send-name-get-ids/' + this.gearItem)
.then((response) => {
console.log(response.data);
if (response.data.length === 0) {
document.getElementById("displaySearch").innerHTML = `"<strong>${gearItem}</strong>" was not found in our database. You can add it manually:`;
this.generalForm = true;
return;
} else {
for (let i = 0; i < response.data.length; i++) {
axios.get('/gearitem/' + response.data[i])
.then((response) => {
console.log(response.data);
document.getElementById("displaySearch").innerHTML += response.data;
this.generalForm = false;
})
.catch((error) => {
document.getElementById("displaySearch").innerHTML =
"No items to display";
console.log(error);
});
}
}
});
},
The problem is in the .innerHTML method as Vue.js ignores anything added via this method even if it's an AJAX. The solution consists on changing the controller to return a JSON and not a blade view, then using the JSON to populate a Vue.js component to create the item's card. the setGearItem() method was changed like so:
setGearItem(gearItem) {
this.gearItem = gearItem;
this.modal = false;
console.log(gearItem);
document.getElementById("displaySearch").innerHTML = "";
this.displayItemCard = false;
axios.get('/send-name-get-ids/' + this.gearItem)
.then((response) => {
console.log(response.data);
this.gearItemId = response.data[0];
if (response.data.length === 0) {
document.getElementById("displaySearch").innerHTML =
`<p class="text-gray-700 ">
<strong class="capitalize">${gearItem}</strong>
was not found on our database. <br>You're free to add it manually! </p>`;
this.generalForm = true;
return;
} else {
this.displayItemCard = true;
}
});
},
the displayItemCard just activates the card component on the view and displays the correct card according to the id.

Adding specific 'badging' to a sku if it is on offer

I have a list of products that need a badge adding if they are found on a list/category page. I have this so far but it's adding badges to every sku and not the ones specified.
The code I have so far is:
const $discountedProducts = options.state.get('$discountedProducts')
const elibigleSKUs = [
'5981BZ501', 'CBMV03300', 'PCMC03300', 'PCMC46800', 'PCMS03300',
'PCMS46800', 'PCMV03300', 'PCMV46800', 'PKMC03300', 'PKMC46800',
'PKMS46800', 'PKMV03300', 'PKMV46800', 'RACOU4800', 'RAFRX6600',
'RAJUC6000', 'RALWC6001', 'RALWC6002', 'RAMC03300', 'RAMC46800',
'RAMS03300', 'RAMS46800', 'RAMV03300', 'RCMC46800', 'RCMS03300',
'RCMS46800', 'RCMV03300', 'RCMV46800', 'SEBCBH700', 'SECOU4800',
'SEFRX6600', 'SEJUC6000', 'SELWC6000', 'SEMC03300', 'SEMC46800',
'SEMS03300', 'SEMS46800', 'SEMV03300', 'SEMV46800', 'SEOS65100',
'SEOX02702', 'SEOX02704', 'STMC03300', 'STMC46800', 'STMS03300',
'STMS46800', 'STMV03300', 'STMV46800', 'SWCOU4800', 'SEATAY600',
'SEAT65100', 'RAAT65100', 'PKMS03300', 'RAATAY600'
]
const targets = [
'.productCard_mediaContainer'
]
poller(targets, ($products) => {
const $discountedProducts = $products.filter(function () {
const $this = $(this)
const $link = $this.find('.productCard_mediaContainer > a')
const currentSku = String($link.data('code')).toUpperCase()
if (elibigleSKUs.indexOf(currentSku) >= -1) {
return true
}
return false
})
if ($discountedProducts.length) {
$('.productCard_mediaContainer').append('<div class="t028-percent-off productCard_promoLine"><span class="discount"><strong>10%</strong> discount applied</span></div>').addClass('t028');
}
})
So it targets a container and attempts to inject the badge per sku. Apologise if this is not perfect but I am more Design/UX than Dev. Any help would be much appreciated. I can add more info if this is not enough.
I recommend adding console.log() statements in your poller function to see what you're getting. You could do something like this:
if (elibigleSKUs.indexOf(currentSku) >= -1) {
console.log("This SKU is eligible " + currentSku);
return true
}
console.log("This SKU is NOT eligible " + currentSku);
return false
This should give you a place to start.

Why can't my post functions access a variable above it?

I'm trying to figure out why the post functions at the end of the following code do not have access to the userID variable (I'm assuming it's a scope issue as logging userId immediately before the functions returns the correct value).
$.get("/set_languages_user", function(res) {
console.log(res)
if ( res.length === 0 ) {
var getUserInfo = $.get('/set_user', function(res){
var langConfirmSource = $('#language-confirmation-template').html();
var langConfirmCompiled = Handlebars.compile(langConfirmSource);
var langConfirmTemplate = langConfirmCompiled(res)
$('body').append(langConfirmTemplate)
$('html').toggleClass('disable_scrolling')
var userId = res.id
var native_language = res.native_language
var learning_language = res.learning_language
$(document).on('submit', '#language_confirmation', function(e){
e.preventDefault()
// prevent user from continuing if they haven't checked that they agree to the term's of use
if ( $('#touCheck').is(':checked')) {
console.log('checked!!!')
// this function finds the ID of the User's defined languages
var getUserInfo = $.get('/languages.json', function(lang){
// Find the ID of the languages the User is supporting in order to submit to languages_users db
for (i = 0; i < lang.length; i++) {
if (lang[i].language === native_language) {
var confirmedUserNativeInt = lang[i].id
}
}
for (i = 0; i < lang.length; i++) {
if (lang[i].language === learning_language) {
var confirmedUserLearningInt = lang[i].id
}
}
console.log(confirmedUserNativeInt)
console.log(confirmedUserLearningInt)
console.log(userId)
// creates a new instance in languages_user for the learningLanguage (level 1)
$.post( "/languages_users", { languages_user:{ language_id: confirmedUserLearningInt, user_id: userId, level: 1 }})
// creates a new instance in languages_user for the nativelanguage (level 5)
$.post( "/languages_users", { languages_user:{ language_id: confirmedUserNativeInt, user_id: userId, level: 5 } })
$('.signon_language_confirmation').remove()
$('html').toggleClass('disable_scrolling')
});
} else {
console.log('not checked!!!')
$('.wrapper_tou_signup').append('<p class="message_form_error">You must agree to Lexody\'s Terms of Use to continue.</p>')
}
})
});
}
})
Here is the handlebars template that is being rendered:
<script id="language-confirmation-template" type="text/x-handlebars-template">
<div class="signon_language_confirmation">
<p class="title_langconf">Welcome to</p>
<img src="">
<div class="wrapper_form_dark language_confirmation_form wrapper_form_sign_on">
<form id="language_confirmation">
<div class="form_section">
<div class="wrapper_input col_16_of_16">
<p>I speak {{native_language}} <svg class="icon_standard"><use xlink:href="#{{native_language}}"/></svg></p>
<p>I am learning {{learning_language}} <svg class="icon_standard"><use xlink:href="#{{learning_language}}"/></svg></p>
<div class="wrapper_tou_signup">
<p><input type="checkbox" name="tou" value="agree" id="touCheck"> I agree to Lexody's terms of use.</p>
</div>
<div class="submit_cancel">
<input type="submit" value="Submit" class="btn_primary submit">
</div>
</div>
</div>
</form>
</div>
</div>
When I submit I'm getting "Uncaught ReferenceError: userId is not defined(…)". How do I make that variable accessible to those functions and why is that variable not accessible but the others ('confirmedUserLearningInt' and 'confirmedUserNativeInt') are?
Thanks in advance.
you have not declared the var's somewhere where the post method can reach, as you can see in your code the vars are inside a if statement which is inside a for loop, you should declare the var before the for loop like this:
$.get("/set_languages_user", function(res) {
console.log(res)
if ( res.length === 0 ) {
var getUserInfo = $.get('/set_user', function(res){
var langConfirmSource = $('#language-confirmation-template').html();
var langConfirmCompiled = Handlebars.compile(langConfirmSource);
var langConfirmTemplate = langConfirmCompiled(res)
$('body').append(langConfirmTemplate)
$('html').toggleClass('disable_scrolling')
var userId = res.id
var native_language = res.native_language
var learning_language = res.learning_language
$(document).on('submit', '#language_confirmation', function(e){
e.preventDefault()
// prevent user from continuing if they haven't checked that they agree to the term's of use
if ( $('#touCheck').is(':checked')) {
console.log('checked!!!')
// this function finds the ID of the User's defined languages
var getUserInfo = $.get('/languages.json', function(lang){
// Find the ID of the languages the User is supporting in order to submit to languages_users db
var confirmedUserNativeInt; //<<<<<<<<<<<<<<
for (i = 0; i < lang.length; i++) {
if (lang[i].language === native_language) {
confirmedUserNativeInt = lang[i].id
}
}
var confirmedUserLearningInt;//<<<<<<<<<<<<<<<<
for (i = 0; i < lang.length; i++) {
if (lang[i].language === learning_language) {
confirmedUserLearningInt = lang[i].id
}
}
console.log(confirmedUserNativeInt)
console.log(confirmedUserLearningInt)
console.log(userId)
// creates a new instance in languages_user for the learningLanguage (level 1)
$.post( "/languages_users", { languages_user:{ language_id: confirmedUserLearningInt, user_id: userId, level: 1 }})
// creates a new instance in languages_user for the nativelanguage (level 5)
$.post( "/languages_users", { languages_user:{ language_id: confirmedUserNativeInt, user_id: userId, level: 5 } })
$('.signon_language_confirmation').remove()
$('html').toggleClass('disable_scrolling')
});
} else {
console.log('not checked!!!')
$('.wrapper_tou_signup').append('<p class="message_form_error">You must agree to Lexody\'s Terms of Use to continue.</p>')
}
})
});
}
})

Categories