How to loop attributes of an object on EJS? - javascript

I am creating sort of an api app with node.js, express, body-parser, ejs, fs. I have the server running and everything else working. The problems is that have an object(JSON file) that is parsed, but I can't get access to certain attributes when using my index.ejs template:
{
"x":{
"color": "black"
"total": 1
},
"y":{
"color": "red"
"total": 5
}
}
My javascrip file has the following function that loops trough the file.
var keys = Object.keys(Obj);
for (var i = 0; i< keys.length; i++){
var k = keys[i];
var colorKey = Obj[k].color;
var totalKey = Obj[k].total;
}
var db = keys;
res.render("index", {
db: db
}
Then on my index.ejs I have the code that works with the first attribute ("x" and "y") but can't access the rest.
Welcome to the main page!
<% for (var i = 0; i < db.length; i++) { %> ////This is the for loop that shows "x" and "y"
<h1> We have the variable: <%= db[i] %> </h1>
<h1> The color is: <%= db[i].color %></h1>
<h1> There is <%= db[i].total %> left!</h1>
<% } %>
The page shows both variables 's but shows nothing when it comes to color and total. Is there a way to loop those in ejs?

I presume you don't actually need the preprocessing. Instead, you can do can make an array of keys
db = /* the source object */
const keys = Object.keys(db)
res.render("index", { db })
<% for (let i = 0; i < keys.length; i++) { %>
<h1> We have the variable: <%= keys[i] %> </h1>
<h1> The color is: <%= db[keys[i]].color %></h1>
<h1> There is <%= db[keys[i]].total %> left!</h1>
<% } %>

Related

How to change value of multiple iterated element in ejs dynamically?

Here is my EJS code:
when I click on any iterated button it only changes first element's value. But I want to make other element to change as well. What's wrong with it?
<% for(let i=0; i<10; i++){
%> <h2 id="value">0</h2> <button onclick="btnHandler()">click to change</button> </h1> <%
} %>
<script>
let val = document.getElementById('value');
let start = 0
function btnHandler(){
val.innerHTML = `${start++}`
}
</script>
I try to to change value of iterated element using iterated button with onlclick but it only affect first elements.
I expect to change other element as well.
In the rendered HTML, you have 10 <h2> elements and 10 <button>s, but there is no correspondence between each <button> and "its" <h2> element. Moreover, all the <h2> elements have the same id, and you have only one start counter whereas you need 10.
The following solution relates <h2> elements, <button>s and counters by the index i. I assume this is what you intend to achieve.
<% for(let i=0; i<10; i++){
%> <h2 id="value-<%= i %>">0</h2> <button onclick="btnHandler(<%= i %>)">click to change</button> <%
} %>
<script>
let start = [];
function btnHandler(i){
start[i] = start[i] || 0;
let val = document.getElementById('value-' + i);
val.innerHTML = ++start[i];
}
</script>

How to convert object to list in javascript?

I need to convert this object into list in expressJS view (using EJS):
{https://ae01.alicdn.com/kf/HTB12Xa4ipGWBuNjy0Fbq6z4sXXa3/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg,https://ae01.alicdn.com/kf/HTB10xfciv9TBuNjy1zbq6xpepXaG/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg,https://ae01.alicdn.com/kf/HTB13AHqcfiSBuNkSnhJq6zDcpXav/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg}
I've tried :
<% const xx = result.data[0].galleryimages.replace('{',"['").replace('}',"']").split(',') %>
<% for (let j=0; j<xx.length; j++) { %>
<%= xx[j]%>
<% } %>
but it returns :
['https://ae01.alicdn.com/kf/HTB12Xa4ipGWBuNjy0Fbq6z4sXXa3/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg https://ae01.alicdn.com/kf/HTB10xfciv9TBuNjy1zbq6xpepXaG/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg https://ae01.alicdn.com/kf/HTB13AHqcfiSBuNkSnhJq6zDcpXav/Mickey-Mouse-Microwave-Glove-Potholder-Bakeware-Blue-and-White-100-Cotton-Oven-Mitts-and-Potholder-mat.jpg']
What you posted is not an object, it's a string - try:
const xx = result.data[0].galleryimages.replace(/[{}]/, '').split(',')
problem solved
<% let xx = result.data[0].galleryimages.slice(1,-1).split(",") %>
<% for (let j=0; j<xx.length; j++) { %>
<% let ha = xx[j].slice(1,-1); %>
<img src=<%= ha.replace("'","") %> width="10%"/>
<% } %>

Dynamically insert content for a full text user search with JS and Rails

I have a search input-field and I want to display content dynamically depending on what the User types in it.
The Database hast 1,5k slots and I can allready search by giving a parameter
?search_for=SOMETHING_TO_SEARCH_FOR
where SOMETHING_TO_SEARCH_FOR is just a string. It does a full text search over the database and gives me the results.
I would like to replace the search results with the current shown elements inside
<div class = 'slots-container' id = 'dynamic'>...</div>
index.html.erb
<div class = "index-body">
<%= link_to 'home', root_path, id: 'home', hidden: true %>
<div class = "search_bar" id = 'search'>
<input type="text" placeholder="Search..">
</div>
<div id = 'slots'>
<div class = 'slots-container' id = 'dynamic'>
<%= render #slots %>
</div>
</div>
<%= will_paginate #slots, hidden: true %>
</div>
index.js.erb
appends the next elements to the div with the id: dynamic and removes the .pagination div which is included by will_paginate statement if we have no more pages so that my script for loading more pages gets a null reference
$('#dynamic').append('<%= j render #slots %>');
<% unless #slots.next_page %>
$('.pagination').remove();
<% end %>
main.js
Loads a new page if User is only 100px away from the end of the document,
with the url: next_page from the link with the .next class
var ready = true;
$( document ).on('turbolinks:load', function() {
$("img").lazyload();
document.onscroll = function(){loadNextPage()};
})
function loadNextPage(){
var window_top = $(window).scrollTop();
var doc_height = $(document).height();
var window_height = $(window).height();
var window_bottom = window_top + window_height;
var should_scroll = doc_height - window_bottom < 100;
var next_page = $('.next_page').attr('href');
if (ready && should_scroll && next_page) {
ready = false;
$.getScript(next_page).done(function() {
$("img").lazyload();
ready = true;
});
}
}
function loadSearch(){
var root_page = $('#home').attr('href');
...
}
As you see my loadSearch() function should set the param search_for and append it to my root_page url and my index.js.erb should replace the current content of the document with the search results and also being able to still do infinite scrolling feature.
I think the controller is of no interest jsut be sure that #slots has the right paginated slot elements that needs to be drawn
I solved it now as follows:
index.html.erb
<div class = "index-body">
<%= link_to 'home', root_path, id: 'home', hidden: true %>
<div class = "search-bar">
<input class = "search-input" type="text"
placeholder="Search..."
id = "search-input">
</div>
<div id = 'slots-container'>
<div class = 'slots-container' id = 'slots'>
<%= render #slots %>
<%= will_paginate #slots, hidden: true,id: "paginate" %>
</div>
</div>
</div>
index.js.erb
#identical_search indicates that last search result is the same as the current one so dont do anything
<% unless #identical_search %>
if (dirty) {
dirty = false;
$('#slots').empty();
}
$('#slots').append('<%= j render #slots %>');
<% if #slots.next_page %>
if(document.getElementById("paginate") === null)
$('#slots').append('<%= j will_paginate #slots, hidden: true, id: "paginate" %>');
$('#paginate').replaceWith('<%= j will_paginate #slots, hidden: true, id: "paginate" %>');
<% else %>
$('#paginate').remove();
<% end %>
<% end %>
main.js
var documentLoaded = false;
var dirty = false;
var pending = false;
var loadSearchTimer = null;
$( document ).on('turbolinks:load', function() {
...
documentLoaded = true;
document.getElementById("search-input").addEventListener("input", startTimerForUserInput);
})
...
function startTimerForUserInput(){
if (loadSearchTimer !==null)
clearTimeout(loadSearchTimer);
loadSearchTimer = setTimeout(loadSearch, 300);
}
function loadSearch(){
if (documentLoaded){
documentLoaded = false;
dirty=true;
var search_input = document.getElementById("search-input");
var search_for = search_input.value;
var root_page = $('#home').attr('href');
if(search_for && search_for !== '')
root_page += "?search_for=" + search_for;
$.getScript(root_page).done(function() {
$("img").lazyload();
documentLoaded = true;
if(pending){
pending = false;
loadSearch();
}
});
}
else
pending = true;
}
In main.js I use a Timer to only search 300 ms after last user input to limit the calls so that it doesnt search after every input. When the getScript returns success I am checking if a search request was submitted while the current request was processed to send a new request via pending variable.
dirty is set to true when the user search so that the index.js.erb knows to empty out the div containing the elements.
This runs smooth and I like it how it is.
I hope this will help someone in the future...
If it helps to udnerstand the whole picture, here is the controller:
class SlotsController < ApplicationController
require 'will_paginate/array'
##last_search_content = nil
def index
#identical_search = false
#hashtags = Hashtag.all
if params[:search_for]
search_str = params[:search_for].gsub(/\s\s+/, ' ').strip
#slots = Slot.where("LOWER(slot_name) LIKE LOWER('%#{search_str}%') ")
if ##last_search_content.to_set == #slots.to_set && (params[:page] == nil || params[:page] == 1)
#identical_search = true
end
elsif params[:hashtags]
#slots = slotsWithAtLeastOneOfThose(params[:hashtags])
else
#slots = Slot.all
end
##last_search_content = #slots
unless #identical_search
#slots = #slots.paginate(page: params[:page])
end
respond_to do |format|
format.html
format.js
end
end
def show
#slot = Slot.find(params[:id])
end
private
def slotsWithAtLeastOneOfThose(hashtags)
slots=[]
hashtags.split(' ').each do |h|
slots += Slot.joins(:hashtags).where("hashtags.value LIKE ?", "%#{h}%")
end
return slots.uniq
end
end

Value of DataList sourced from JavaScript returning undefined

I'm creating a datalist on my webpage that sources it's values from a JavaScript array (that sources from a Java array using JSP).
Here is my code for populating the data list:
<input name="Engineer Name" list="engineer" />
<datalist id="engineer"></datalist>
<script>
//Take the engineers array and transfer to javascript array
//This is so we can source the Engineer Drop-Down menu from a file dynamically
var engineerArray = [];
<% for (int i=0; i<engineers.size(); i++) { %>
engineerArray[<%= i %>] = "<%= engineers.get(i) %>";
<% } %>
for (var i in engineerArray) {
var datalist = document.getElementById('engineer');
datalist.innerHTML += '<option value=' + engineerArray[i] + '>';
}
</script>
This code displays the datalist correctly, but on submission of the form I call another JavaScript function that contains the line:
var engineer = document.getElementById('engineer').value;
And that value ends up being undefined.
You are trying to get the value of datalist incorrectly. The selector has to be on the input element. I have modified the code for reference:
<input name="Engineer Name" id="engineerList" list="engineer" />
<datalist id="engineer"></datalist>
<script>
//Take the engineers array and transfer to javascript array
//This is so we can source the Engineer Drop-Down menu from a file dynamically
var engineerArray = [];
<% for (int i=0; i<engineers.size(); i++) { %>
engineerArray[<%= i %>] = "<%= engineers.get(i) %>";
<% } %>
for (var i in engineerArray) {
var datalist = document.getElementById('engineer');
datalist.innerHTML += '<option value=' + engineerArray[i] + '>';
}
</script>
Then get the datalist value by specifying the correct id:
var engineer = document.getElementById('engineerList').value;

Accessing specific member of an ArrayList using Javascript

So, I have a table in a jsp page which shows the data fetched from a database via an ArrayList forwarded to the page. Each row of the table has a radio button corressponding to it. Now, I would like to access the elements in the row (the ArrayList's members on the selection of the corresponding radio button and then click of an 'edit' button)
Any thoughts as to how to achieve this would be very much appreciated. Here's my code for a bit intro.
<%
ArrayList<requestbean> reqjsp = new ArrayList<requestbean>();
reqjsp = (ArrayList<requestbean>) (request.getAttribute("reqdb"));
%>
<script type ="text/javascript">
function x() {
var ele = document.getElementsByName('reqradio');
var i = ele.length;
for ( var j = 0; j < i; j++ ) {
if ( ele[j].checked ) {
document.getElementById("edireq").disabled = false;
alert('request ' + ( j + 1 ) + ' selected');
//Here is where the functionality is desired to access reqjsp.get(j)
}
}
}
</script>
<input type="button" name="edireq" id="edireq" onclick="x()" value="Edit Request">
These are a few columns in my table.
<%
for ( int i = 0; i < reqjsp.size(); i++ ) {
%>
<tr>
<td> <input type="radio" name="reqradio" id="req<%=(i+1) %>"></td>
<td><%= reqjsp.get(i).getRequestid() %></td>
<td><%= reqjsp.get(i).getRequestor() %></td>
<td><%= reqjsp.get(i).getApprover() %></td>
</tr>
<%} %>
You could generate a JavaScript array with JSP code and then access this generated variable in your JavaScript. But you would not be able to change anything in the underlying Java object this way:
<script type ="text/javascript">
<%
ArrayList<requestbean> reqjsp = new ArrayList<requestbean>();
reqjsp = (ArrayList<requestbean>) (request.getAttribute("reqdb"));
%>
var myJsArray = new Array();
<%
for ( int i = 0; i < reqjsp.size(); i++ ) {
%>
myJsArray.push('<%= reqjsp.get(i) %>');
<%
}
%>
// JavaScript code to access the myJsArray array
</script>
The JSP code will generate this kind of code:
<script type ="text/javascript">
var myJsArray = new Array();
myJsArray.push('value1');
myJsArray.push('value2');
myJsArray.push('value3');
// JavaScript code to access the myJsArray array
</script>

Categories

Resources