Displaying data to a grid with ejs and express - javascript

what im trying to do is display news using newsAPI in a grid which is created in for each loop and it randomizes how it looks in each iteration. Problem that i have is obvious, im receiving 3 or 2 but only one instance of data from express each time it loops.Im trying to figure out how to keep grid randomized and receive exact number of data for each div inside the grid. Since its hard to explain here is the code:
EJS:
<div class="col-md-12">
<% let current = -1 %>
<% data.forEach(function(news){ %>
<% let count = Math.floor( Math.random() * Math.floor(4)) %>
<% if(count == 0 && count !== current){ %>
<div class="row py-2 px-1">
<div class="col-sm-12 col-md-8 bg border mainGrid">duh</div>
<div class="col-sm-12 col-md border mainGrid"></div>
</div>
<% current = count %>
<%}else if(count == 1 && count !== current){ %>
<div class="row py-2 px-1">
<div class="col-sm-12 col-md-5 bg border mainGrid">duh</div>
<div class="col-sm-12 col-md border mainGrid"></div>
<div class="col-sm-12 col-md-5 bg border mainGrid">duh</div>
</div>
<% current = count %>
<%}else if(count == 2 && count !== current){ %>
<div class="row py-2 px-1">
<div class="col-sm-12 col-md-3 bg border mainGrid">duh</div>
<div class="col-sm-12 col-md border mainGrid"></div>
</div>
<% current = count %>
<%}else if(count == 3 && count !== current){ %>
<div class="row py-2 px-1">
<div class="col-sm-12 col-md-4 bg border mainGrid">duh</div>
<div class="col-sm-12 col-md border mainGrid"></div>
<div class="col-sm-12 col-md-6 bg border mainGrid">duh</div>
</div>
<% current = count %>
<%}%>
<% }) %>
Express:
router.get("/",(req,res) => {
newsapi.v2.topHeadlines({
sources: 'bbc-news,the-verge',
language: 'en',
pageSize: 9
}).then(response => {
let data = response.articles;
console.log(data);
res.render("index",{data:data})
});
})
module.exports = router;
Thanks in advance!

If somebody wants to know how i solved it:
<div class="col-md-12">
<% let current = 0 %>
<% let count = 0 %>
<% let currentCount = 0 %>
<% data.forEach(function(news){ %>
<% if(current === 1){ %>
<%let gridcount = Math.floor((12 - count)/2); %>
<div class="col-sm-12 col-md-<%=gridcount%> border mainGrid">
<h2>
<%= news.title %>
</h2>
<p>
<%= news.description %>
</p>
</div>
<% current = 2 %>
<% }else if(current == 0){ %>
<% while(count == currentCount){ %>
<% count = Math.floor( Math.random() * Math.floor(4)) +3 %>
<% } %>
<div class="row">
<div class="col-sm-12 col-md-<%=count%> border mainGrid">
<h2>
<%= news.title %>
</h2>
<p>
<%= news.description %>
</p></div>
<% currentCount = count %>
<% current = 1 %>
<% }else if(current == 2){%>
<div class="col-sm-12 col-md border mainGrid">
<h2>
<%= news.title %>
</h2>
<p>
<%= news.description %>
</p>
</div>
</div>
<% current = 0 %>
<% } %>
<% }) %>
</div>

Related

How do I sort by distance from user, based on user's location?

I have a Rails 7 app in which users can search, sort, and filter to find parks and nature reserves. I'm using the Ransack gem.
I have calculated the distance of each park from the user based on the user's IP address using Javascript.
Now I want to add a link on the Parks Index page for users to sort by distance. (Currently I have sort by rating and sort by name.)
Not sure how to go about this... I suspect I'll have to store the distance in the database somehow (on the user table?), so I can apply a server-side sort. Is that the right approach?
How do I store the distance from user in an efficient way, when the distance is recalculated every time the user visits the site?
app/javascript/controllers/geolocation_controller.js
import { Controller } from '#hotwired/stimulus';
import { getDistance, convertDistance } from 'geolib';
export default class extends Controller {
static targets = ['park'];
connect() {
window.navigator.geolocation.getCurrentPosition((position) => {
this.setUserCoordinates(position.coords);
this.setDistanceText();
})
}
setUserCoordinates(coordinates) {
this.element.dataset.latitude = coordinates.latitude;
this.element.dataset.longitude = coordinates.longitude;
}
getUserCoordinates() {
return {
latitude: this.element.dataset.latitude,
longitude: this.element.dataset.longitude,
};
}
setDistanceText() {
this.parkTargets.forEach((parkTarget) => {
let distanceFrom = getDistance(
this.getUserCoordinates(),
{ latitude: parkTarget.dataset.latitude,
longitude: parkTarget.dataset.longitude },
);
parkTarget.querySelector('[data-distance-away]').innerHTML =
`${Math.round(convertDistance(distanceFrom, 'km'))} kilometers away`;
});
}
}
app/views/parks/_park_cards.erb
<% #parks.order('average_rating DESC NULLS LAST').each do |park| %>
<li
style="list-style-type: none;"
data-geolocation-target="park"
data-latitude="<%= park.latitude %>"
data-longitude="<%= park.longitude %>"
>
<div class="col">
<div class="card border-0 px-2 mb-4">
<% if park.default_image && park.default_image.content_type.in?(%w[image/gif image/jpeg image/png]) %>
...
<% else %>
...
<% end %>
<div class="card-header border-0 bg-white mx-0 px-0 d-flex justify-content-between align-items-center">
<strong><%= link_to park.name, park, class: "text-body" %></strong>
<div class="mx-0 px-0">
<% if park.average_rating? %>
<span>
...
</span>
<%= park.average_rating.round(2) %>
<% end %>
</div>
</div>
<div>
<div data-distance-away>
</div>
<div class="btn p-0 favorite-icon">
...
</div>
<div class="btn p-0">
...
</div>
<br>
<br>
</div>
</div>
</div>
</li>
<% end %>
app/views/parks/index.html.erb
<% provide(:title, 'Parks') %>
<div
data-controller="geolocation"
class="container-fluid"
data-latitude=""
data-longitude=""
>
<div class="col-sm-12">
<%- if current_user && current_user.admin? %>
<%= link_to "New park", new_park_path %>
<% end %>
</div>
<div class="container-fluid">
<div class="col-sm-12 d-flex justify-content-between align-items-center mx-0 px-1 mb-5">
<span class="d-flex align-items-center">
<strong>
<%= #parks.count %>
<%= 'park'.pluralize(#parks.count) %>
</strong>
<span class="ms-4">
<%= link_to "Clear all filters", parks_path, class: "btn link-dark" %>
</span>
</span>
<span class="mb-5">
</span>
<span class="d-flex align-items-center">
<%= sort_link(#q, :average_rating, "Sort by rating", default_order: :desc, class: "btn") %>
<% if I18n.locale.to_s.include?('he') %>
<%= sort_link(#q, :name_he, "Sort by name (Hebrew)", default_order: :asc, class: "btn") %>
<% else %>
<%= sort_link(#q, :name_en, "Sort by name", default_order: :asc, class: "btn") %>
<% end %>
<span class="d-flex justify-content-end ms-4">
<%= render 'filters_button' %>
</span>
</span>
</div>
</div>
<div class="col-sm-12 row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 mx-0 px-2">
<%= render 'park_cards', parks: #parks %>
</div>
<div class="col-sm-12 pagination">
<%= will_paginate(#users) %>
</div>
</div>
<%= render 'filters_modal' %>
app/controllers/parks_controller.rb
class ParksController < ApplicationController
before_action :set_park, only: %i[ show edit update destroy ]
before_action :admin_user, only: %i[ new edit create update destroy ]
# GET /parks or /parks.json
def index
#parks = #q.result(distinct: true).paginate(page:params[:page], :per_page => 48)
end
...
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
before_action :set_search
def set_search
#q = Park.ransack(params[:q])
end
...

How to calculate total price and deprice on EJS

I'm trying to calculate total price when user click on the image and reduce price when user delete the image out by using EJS that call data base of items on MySQL which it have price.
This is my html page with ejs and js
$(document).ready(function(){ //when click on the image of item it, item will show out on canvas.
$('.items_img').click(function(){
var path = $(this).attr('data-title');
alert(path);
addImage(path, 500, 500, 0.5, -90, 3);
})
});
<!DOCTYPE html>
<html>
<body>
<div class="tab-content clearfix">
<% for(var i=0; i<categories.length; i++){ %>
<div class="tab-pane <% if(i==0){ %> active <% } %>" id="<%= categories[i].id %>a">
<% for(var j=0; j<items.length; j++){ %>
<% if(items[j].category_id == categories[i].id){ %>
<div class="item col-xs-4 col-lg-4">
<div class="thumbnail">
<img class="group list-group-image items_img" src="/pic_items/<%= items[j].picture_path %>" data-title='/anime_items/<%= items[j].anime_path %>' data-target='<%= items[j].price %>' alt="Test" />
<div class="caption">
<h4 class="group inner list-group-item-heading">
<%= items[j].title %>
</h4>
<p class="group inner list-group-item-text"> <%= items[j].description %> </p>
<div class="row">
<div class="col-xs-12 col-md-6">
<p class="">Width <%= items[j].width %> CM</p>
<p class="">Height <%= items[j].height %> CM</p>
</div>
</div>
</div>
</div>
</div>
<% } %>
<% } %>
</div>
</body>
</html>

dynamically render div based on selectbox input rails 5 and select.js plugin

I have a Rails 5, ruby 2.4.0, bootstrap 4 alpha 6 app using the selectize.js plugin.
What I am trying to do is display device info based on the selected item in the select box.
Currently, When the page loads the div is hidden as it should be and the select box is displayed (as it should be) but when I select anything other than the first select option, it wont change the device in the div.
I am a java / ajax noob and am lost for a solution. Any assistance would be greatly appreciated!
my select-box:
<select class="form-control div-toggle" id="select-device" data-target=".device-names">
<option>Select Device</option>
<% #devices.each do |device| %>
<option value="<%= device.id %>" show=".<%= device.device_name %>"> <%= device.device_name.titleize %></option>
<% end %>
</select>
My Div to be rendered and displayed for each device when its selected:
<div class="container device-names">
<% #devices.each do |device_div| %>
<div class="<%= device_div.id %> invisible" id="result">
<div class="phoneDetailsContainer">
<div class="row">
<div class="col-sm-12">
<center><h5 class="deviceHeader"><%= device_div.manufacturer.name.titleize %> | <%= device_div.device_name.upcase %></h5></center>
</div>
</div>
<div class="row">
<div class="col-md-4 hidden-sm-down"></div>
<div class="col-sm-12 col-md-4" id="deviceDivImageContainer">
<center>
<% if device_div.image.present? %>
<%= image_tag device_div.image_url(:thumb), :class => "deviceImage" %>
<% else %>
<% end %>
</center>
</div>
<div class="col-md-4 hidden-sm-down"></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-4"></div>
<div class="col-sm-12 col-md-4">
<center>
<span class="proceedDisclaimer">By clicking this button you agree that this is the device in your possession</span>
<%= link_to "Proceed to Carrier Selection", manufacturer_device_path(#manufacturer, device_div), class: 'btn btn-outline-primary proceedButton', :id => "proceed" %>
</center>
</div>
<div class="col-sm-12 col-md-4"></div>
</div>
</div>
</div>
<% end %>
</div>
my javaScript to call the div when the item is selected:
<script type="text/javascript">
var ready = function () {
// add code here
$('#result').hide();
$('#select-device').selectize({
});
$('#select-device').change(function(){
$('#result').show().removeClass('invisible')
});
//end code here
}
$(document).ready(ready);
$(document).on('page:load', ready);
$(document).on('turbolinks:load', ready);
</script>
Any assistance here would be greatly appreciated! please let me know if further info is required!
A fair warning. I am NOT much knowledgeable on ruby and thus my answer might be bit buggy on ruby side.
HTML
<div class="container device-names">
<% #devices.each do |device_div| %>
<!-- first id change -->
<div class="invisible" id="result<%= device_div.id %> ">
<div class="phoneDetailsContainer">
<div class="row">
<div class="col-sm-12">
<center><h5 class="deviceHeader"><%= device_div.manufacturer.name.titleize %> | <%= device_div.device_name.upcase %></h5></center>
</div>
</div>
<div class="row">
<div class="col-md-4 hidden-sm-down"></div>
<!-- second id change -->
<div class="col-sm-12 col-md-4" id="deviceDivImageContainer<%= device_div.id %> ">
<center>
<% if device_div.image.present? %>
<%= image_tag device_div.image_url(:thumb), :class => "deviceImage" %>
<% else %>
<% end %>
</center>
</div>
<div class="col-md-4 hidden-sm-down"></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-4"></div>
<div class="col-sm-12 col-md-4">
<center>
<span class="proceedDisclaimer">By clicking this button you agree that this is the device in your possession</span>
<!-- third id change. Not knowing ruby i cannot help here -->
<%= link_to "Proceed to Carrier Selection", manufacturer_device_path(#manufacturer, device_div), class: 'btn btn-outline-primary proceedButton', :id => "proceed" %>
</center>
</div>
<div class="col-sm-12 col-md-4"></div>
</div>
</div>
</div>
<% end %>
</div>
Javascript
<script type="text/javascript">
$(document).ready(function(){
//result.hide is not wanted as elements are already having class invisible
//Assuming that the dropdown values have same values as element ids
$('#select-device').change(function(){
$('#'+$('#select-device').val()).removeClass('invisible')
});
});
</script>
Right now, your jQuery selector for $('#result') is going to return an array of all the elements which match your selector. You want to find the one which has the class of the id of the item. You can pass the target into the function like this
$('#select-device').change(function(e){
id = $(e.target).val()
$('.' + id).removeClass('hidden')
}

forEach usage with bootstrap grid system

I'm working on a blog site (in node.js), created a blog Schema, a forEach loop iterates over every blog and adds image, title,body to it :
Code :
<% blog.forEach(function(blog) { %>
<div class="col-md-4 col-sm-6">
<img src="<%= blog.image %>">
<div class="caption">
<h2><%= blog.title %></h2>
</div>
<span><%= blog.created.toDateString(); %></span>
<div class="relative">
<p><%- blog.body.substring(0,250); %></p>
<div class="absolute"></div>
</div>
</div>
<% }) %>
Because I've applied forEach, all blog posts have the same appearance.
Is there any chance that the 4th and 5th blog posts appear in different ways(col-md-6, i.e they both occupy half the space of the row)?
The second parameter of the forEach callback is for index:
<% blog.forEach(function(blog, idx) { %>
<% if (idx > 3) %>
<div class="col-md-6 col-sm-6">
<% else %>
<div class="col-md-4 col-sm-6">

Ruby on Rails jQuery: Toggle not working

I am trying to create a button that shows/hides a div. It seems relatively easy, but whenever I click this button, it just does a refresh, and when I keep clicking it, it hides most of my page. Here is what I have so far. Also, I dont know if it matters but I am using foundation for most of the css
application.js
$(function() {
$(document).foundation();
});
$(document).ready(function() {
$('#message_button').click(function() {
$("#messages").toggle();
});
});
_userindex.html
<div class="row">
<div class="small-12 columns new-button">
<%= link_to 'New Job', new_job_path, class: 'button' %>
</div>
</div>
<div class="section-container auto" data-section>
<section>
<p class="title" data-section-title>Active Jobs</p>
<div class="content" data-section-content>
<% if #active.present? %>
<ul>
<% #active.each do |job| %>
<li class='panel'>
<div class="row">
<div class="small-12 columns">
<div class="row">
<div class="large-6 columns">
<span id="location"><strong>location</strong>: <%= job.location %></span>
</div>
<div class="large-6 columns">
<span id="status"><strong>status</strong>: <%= job.status %></span>
</div>
</div>
<div class='light panel bottom'>
<strong>job: <%= link_to job.name, job %></strong><br>
<%= job.description %>
</div>
</div>
</div>
<div class="row job-buttons">
<div class="small-6 columns">
MESSAGES BUTTON -->>> <%= link_to 'messages', '', class: 'button small secondary', id: "message_button" %>
</div>
<div class="small-6 columns">
<%= link_to 'cancel', job, method: :delete, data: {confirm: 'Are you sure?'}, class: 'button small alert' %>
</div>
</div>
<br />
I WANT TO HIDE THIS ENTIRE DIV ---->>>> <div id="messages">
<div class="row">
<div class="small-12 columns">
<div class="panel">
<%= form_for(#message) do |f| %>
<%= f.label :body, "Description" %>
<%= f.text_area :body %>
<%= f.hidden_field :job_id, value: job.id %>
<%= f.submit 'Create message', class: 'button small secondary' %>
<% end %>
</div>
</div>
</div>
<% jobs_messages = job.messages %>
<% if jobs_messages.present? %>
<ul>
<% jobs_messages.each do |m| %>
<% if m.user_id.present? %>
<% user = m.user %>
<% else %>
<% user = m.runner %>
<% end %>
<li class='panel'>
<div class='row'>
<div class='small-12 columns'>
<p> From: <%= user.login %> </p>
<p> Body: <%= m.body %>
</div>
</div>
</li>
<% end %>
</ul>
<% else %>
<div class="empty panel">
<p>no messages at the moment</p>
</div>
<% end %>
</div>
</li>
<% end %>
</ul>
<% else %>
<div class="empty panel">
<p>no active jobs at the moment</p>
</div>
<% end %>
</div>
</section>
<section>
<p class="title" data-section-title>Completed Jobs</p>
<div class="content" data-section-content>
<% if #completed.present? %>
<% else %>
<div class="empty panel">
<p>no completed jobs yet</p>
</div>
<% end %>
</div>
</section>
</div>
I am trying to an $().click action to the link_to button with id "message_button". Whenever this button/link is clicked, I want it to show/hide the "messages" div.
I am new to jQuery, rails, and foundation, so I left most of the code just in case anything was important. But I marked the message_button and the message div to help you better find it.
2 problems:
It looks to me as though you have a bad case of the "multiple IDs"!
You are not preventing the default behaviour of the link. (so when you click it, the page refreshes or navigates away)
Problem #2 is easy: call preventDefault() (usage example below).
Problem #1 is a little trickier...
You are creating <li> content within a loop, inside each of those <li> tags you have elements with the IDs #messages and #message_button. Multiple instances of an ID on the same page is not allowed. If you want, you can use classes instead of ids as you can have multiple instances of a class.
However, switching from IDs to Classes won't fix your problem, as if you use classes you'll just be toggling ALL messages when any message button is clicked.
Referring to this question here, you can easily get the index of the loop in your rails template:
<% #active.each do |job, index| %>
Your template/html code here
<% end %>
This exposes a new variable, index which you can use to decorate each of your messages and buttons with an index value to then specify which message you wish to show.
Note: I'm not sure if this is the best approach, but this should work. It's been a while since I've used Rails, so there might be errors. I've included the code below just to demonstrate the possible solution:
application.js:
$(function() {
$(document).foundation();
});
$(document).ready(function() {
//NOTE that I am selecting on a class here
$('.message_button').click(function(e) {
//You also need to prevent the default behaviour of
//the link. That is why the page keeps refreshing.
e.preventDefault();
//get the index value I appended to this elements ID
var msgButtonIndex = $(this).attr("id").replace("message_button_","");
//select and toggle the respective message
$("#messages_" + msgButtonIndex).toggle();
});
});
_userindex.html:
<div class="row">
<div class="small-12 columns new-button">
<%= link_to 'New Job', new_job_path, class: 'button' %>
</div>
</div>
<div class="section-container auto" data-section>
<section>
<p class="title" data-section-title>Active Jobs</p>
<div class="content" data-section-content>
<% if #active.present? %>
<ul>
<% #active.each do |job,index| %>
<li class='panel'>
<div class="row">
<div class="small-12 columns">
<div class="row">
<div class="large-6 columns">
<span id="location"><strong>location</strong>: <%= job.location %></span>
</div>
<div class="large-6 columns">
<span id="status"><strong>status</strong>: <%= job.status %></span>
</div>
</div>
<div class='light panel bottom'>
<strong>job: <%= link_to job.name, job %></strong><br>
<%= job.description %>
</div>
</div>
</div>
<div class="row job-buttons">
<div class="small-6 columns">
<%# Adding a "message_button" class and a decorated "message_button_{index}" ID! %>
<%= link_to 'messages', '', class: 'button small secondary message_button', id: "message_button_" + index.to_s %>
</div>
<div class="small-6 columns">
<%= link_to 'cancel', job, method: :delete, data: {confirm: 'Are you sure?'}, class: 'button small alert' %>
</div>
</div>
<br />
<%# decorating this ID too %>
<div id="messages_<%= index.to_s %>">
<div class="row">
<div class="small-12 columns">
<div class="panel">
<%= form_for(#message) do |f| %>
<%= f.label :body, "Description" %>
<%= f.text_area :body %>
<%= f.hidden_field :job_id, value: job.id %>
<%= f.submit 'Create message', class: 'button small secondary' %>
<% end %>
</div>
</div>
</div>
<% jobs_messages = job.messages %>
<% if jobs_messages.present? %>
<ul>
<% jobs_messages.each do |m| %>
<% if m.user_id.present? %>
<% user = m.user %>
<% else %>
<% user = m.runner %>
<% end %>
<li class='panel'>
<div class='row'>
<div class='small-12 columns'>
<p> From: <%= user.login %> </p>
<p> Body: <%= m.body %>
</div>
</div>
</li>
<% end %>
</ul>
<% else %>
<div class="empty panel">
<p>no messages at the moment</p>
</div>
<% end %>
</div>
</li>
<% end %>
</ul>
<% else %>
<div class="empty panel">
<p>no active jobs at the moment</p>
</div>
<% end %>
</div>
</section>
<section>
<p class="title" data-section-title>Completed Jobs</p>
<div class="content" data-section-content>
<% if #completed.present? %>
<% else %>
<div class="empty panel">
<p>no completed jobs yet</p>
</div>
<% end %>
</div>
</section>
</div>

Categories

Resources