I render a page with the data that ejs puts together. when the user presses a submit button a section (thirdRow)of the page should be refreshed with the new data that was submitted plus the old data. I got the new data in the db, I want to refresh the thirdRow that shows all the reviews.
basically my problem is the success method in the $.ajax . I could get all the data there but it seems weird to write everything over in html strings. There should be a better way.
I saw a method where I could put the .thirdRow into a template and include that into the main EJS page and also put that into my static public folder and do something like new EJS({url : 'public/thirdRow.ejs' }).update('.thirdRow', data); in this case is the data in the last code snippet the returned data from the success callback in the AJAX? How Do I get Access to the EJS There are alot of links for ejs can you show my how to include the EJS
I don't know if this is the correct method. How would you do it? I have a page that is basically made up of all the returned data and I want to click a button and have only one section have the new data.
One section inside main.ejs
<div class="thirdRow">
<div class="reviewSection">
<% if(reviews){%>
<% reviews.forEach(function(e, i){%>
<div class="indivReview">
<div class = "userRow row">
<div>
<span>user </span>
<% if( e.username) {%>
<span><%= e.username %></span>
<%}else{ %>
<span><%=e.user%></span>
<% }%>
</div>
<div><%= e.momented %></div>
</div><!--userRow-->
<div class = "companyRow row">
<div>
<span>Experince for</span>
<span><%=e.companyName%></span>
</div>
<div>
<span> industry</span>
<span>online retail</span>
</div>
</div> <!--companyRow -->
<div class="voteRow row">
<div>
Vote
</div>
<div><%= e.vote%></div>
</div>
<div class="reviewRow row">
<div>Review</div>
<div class = "displayReview">
<% e.reviewText.split("\n").forEach(function(e){ %>
<%= e %><br>
<%})%>
</div>
</div>
<div class="statementRow ">
// make a div for each object
<% e.statements.forEach(function(obj){%>
<div class="indivStatement">
<% var arr = []%>
<%for(var prop in obj) {%>
<% if(prop !== "name"){ %>
<% if(prop == "question"){%>
<% arr[0] = obj[prop] %>
<%} %>
<% if (prop == "result"){%>
<% arr[1] = obj[prop] %>
<%}%>
<% console.log(arr) %>
<%} %>
<%}%>
<div class = "question"><%= arr[0]%></div>
<div class = "bar" data-result ="<%= arr[1]%>"><%= arr[1]%></div>
</div>
<%})%>
</div>
<div> <span></span>
<span><%=e.companyName%></span></div>
<div><%= e.momented %></div>
</div>
<%})%>
<%}%>
</div> <!--reviewSection-->
</div> <!--thirdRow-->
inside client script
$(".submitButton").on("click",function(){
console.log(datum)
var empty;
if(datum.reviewText == "" && Object.keys(datum.statements) == 0 && datum.vote == null){
empty = true;
}else{
empty = false;
}
console.log("empty : " , empty)
scrollFunction(".thirdRow", ".submitButton, .shareButtonSection")
var data = datum;
if(!empty){
$.ajax({
type : "POST",
data : JSON.stringify(data),
contentType : "application/json",
url : "http://localhost:4000/submitreview",
success : function(data){
console.log("success")
$(".thirdRow").fadeOut(800, function(){
console.log("this", $(this))
$(this).html(data).fadeIn().delay(200)
})
console.log(data)
}
})
}
})
I never used EJS on the client side. Allways used with express
Here's an example of using EJS client side
https://github.com/tj/ejs/blob/master/examples/client.html
Related
SO i am trying to change the value of an html tag in an ejs file to a variable i declared in a JavaScript file
let checkbox = document.querySelector('input[name="plan"]');
checkbox.addEventListener('change', function () {
if (this.checked) {
document.querySelector('.plan-title').innerHTML = investment.name;
document.querySelector('.plan-description').innerHTML = investment.description;
}
else {
document.querySelector('.plan-title').innerHTML = '';
document.querySelector('.plan-description').innerHTML = '';
}
});
So when I pass it directly it shows but I want it to be dynamic and Although it gets pass through when i click the checkbox it doesn't seem to have any value.
<%- include('../partials/sidebar'); %>
<% if(currentUser && currentUser.isAdmin){ %>
Add New Plan
<% } %>
<div class="container">
<h1>Investments</h1>
<% investments.forEach((investment)=>{ %>
<div class="col-md-4">
<div class="card">
<strong>
<%= investment.name %>
</strong>
<h4>
<%= investment.min %> - <%=investment.max %>
</h4>
<p>
<%= investment.caption %>
</p>
<p><input type="checkbox" name="plan" id="">Choose investment</p>
</div>
<% if(currentUser && currentUser.isAdmin){ %>
Edit
Delete
<% } %>
</div>
<% }) %>
<% investments.forEach((investment)=>{ %>
<div class="">
<div><strong>Package: </strong>
<p class="plan-title">
</p>
</div>
<p class="plan-description">
</p>
<input type="number" name="" id="" min="<%= investment.min %>"
max="<%= investment.max %>">
</div>
<% }) %>
</div>
<%- include('../partials/footer'); %>
I cant seem to get through this, need help thanks!
If I got it right, you are trying to insert the value of the EJS variable in the HTML tag from JavaScript when the user clicks the checkbox.
The value of the HTML tag doesn't change because in your JS code:
document.querySelector('.plan-title').innerHTML = investment.name;
document.querySelector('.plan-description').innerHTML = investment.description;
investment.name and investment.description are undefined. Check the console on your page.
This is because you tried accessing EJS variables after the page finished rendering.
EJS is mainly used to pass server-side variables to the page before it is rendered. So once it's rendered you cannot access those variables.
So to have the values of those variables in your JavaScript after the page finishes rendering, try doing:
document.querySelector('.plan-title').innerHTML = '<%- investment.name %>';
document.querySelector('.plan-description').innerHTML = '<%- investment.description %>';
instead. This is how you pass the EJS variable to JavaScript. JavaScript now sees it as a string and there's no problem, unlike in your code where it was looking for investment object and returned undefined since that variable is not defined on the client-side.
Also, since you have a for-each loop in the HTML part, I'm assuming you are trying to change the values of specific plan-title and plan-description divs. If that's the case, '<%= investment.name %>' and '<%= investment.description %>' in JavaScript part should be in a for-each loop as well, but that would be a lot of mess.
I suggest you instead to right under the for-each loop in the HTML part, add class to the div tag according to the index of the for-each loop, add on change event to the checkbox, and pass the checkbox and the index of the for-each loop to the JavaScript function which would handle the on change event, include the EJS variables in the plan-title and plan-description divs, and in the JavaScript function that handles on change event change the CSS display property from display: none to display: block to these divs.
See an example:
HTML:
<% investments.forEach((investment, index)=>{ %>
<div class="col-md-4">
<div class="card">
<strong>
<%= investment.name %>
</strong>
<h4>
<%= investment.min %> - <%=investment.max %>
</h4>
<p>
<%= investment.caption %>
</p>
<p><input onchange="displayPlan(this, '<%= index %>')" type="checkbox" name="plan" id="">Choose investment</p>
</div>
<% if(currentUser && currentUser.isAdmin){ %>
Edit
Delete
<% } %>
</div>
<% }) %>
<% investments.forEach((investment, index)=>{ %>
<div class="plan <%= index %>" style="display: none;">
<div><strong>Package: </strong>
<p class="plan-title">
<%- investment.name %>
</p>
</div>
<p class="plan-description">
<%- investment.description %>
</p>
<input type="number" name="" id="" min="<%= investment.min %>"
max="<%= investment.max %>">
</div>
<% }) %>
JavaScript:
function displayPlan(checkbox, id){
if (checkbox.checked) {
document.querySelector(`.plan.${id}`).style.display = 'block';
}
else {
document.querySelector(`.plan.${id}`).style.display = 'none';
}
}
Cheers!
EDIT: Grammar and syntax issues
It's not clear to me what variable you're referring to, but any variable you set in a client-side script will not be available to you in an EJS file that you're rendering on the server. Server-side Node.js code and client-side JavaScript code have no knowledge of each other.
I'm currently trying to implement the Load More button in Ruby on Rails. I've managed to implement it. However, the Load More button still appears even though there is no more photos left to be rendered.
Here are the lists of codes:
index.html.erb
<div class = 'container'>
<div class = 'section-header'>
<h2> Let's Rewind! </h2>
</div>
<div class='row'>
<div class = 'container'>
<div class='cust-cont'>
<%= render #scroll_photos %>
</div>
</div>
</div>
<div class="load-more-container">
<%= image_tag "ajax-loader.gif", style: "display:none;", class: "loading-gif" %>
<%= link_to "Load More", scroll_photos_path, class: "load-more" %>
</div>
</div>
_scroll_photo.html.erb
<div class="col-lg-12 col-md-4 col-xs-12">
<div class="image-box-4-3">
<div class="record" data-year="<%= scroll_photo.year %>">
<div class="image-content">
<%= image_tag(scroll_photo.image_link, width: "100%") %>
</div>
</div>
</div>
</div>
and the controller
if params[:year]
# get all records with id less than 'our last id'
# and limit the results to 5
#scroll_photos = ScrollPhoto.where('year < ?', params[:year]).limit(2)
else
#scroll_photos = ScrollPhoto.limit(2)
end
respond_to do |format|
format.html
format.js
end
the javascript
$(document).ready(function(){
// when the load more link is clicked
$('a.load-more').click(function(e){
// prevent the default click action
e.preventDefault();
// hide load more link
$('.load-more').hide();
// show loading gif
$('.loading-gif').show();
// get the last id and save it in a variable 'last-id'
var last_year = $('.record').last().attr('data-year');
// make an ajax call passing along our last user id
$.ajax({
// make a get request to the server
type: "GET",
// get the url from the href attribute of our link
url: $(this).attr('year'),
// send the last id to our rails app
data: { year: last_year },
// the response will be a script
dataType: "script",
// upon success
success: function(){
// hide the loading gif
$('.loading-gif').hide();
// show our load more link
$('.load-more').show();
}
});
});
});
index.js.erb
$('.cust-cont').append('<%= escape_javascript(render(:partial => #scroll_photos)) %>')
You can hide the load more part when the controller action return empty #scroll_photos
# in your javascript file
<% if #scroll_photos.empty? %>
$('.load-more-container').hide()
<% else %>
$('.cust-cont').append('<%= escape_javascript(render(:partial => #scroll_photos)) %>')
<% end %>
I am fairly new to Rails.
I was able to correctly get the onclick to function for a f.checkbox.
Now I am trying to do something similar for a f.select in a _form.
here is my working code for a checkbox
erb portion :
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :air? %>
<%= f.check_box :air, :id => "chk_air", :onclick => "manageAirDisp();" %>
</div>
</div>
<% if request.air? %>
<div class="col-md-4", id="MultiButton", style="display: block">
<% else %>
<div class="col-md-4", id="MultiButton", style="display: none">
<% end %>
<button onclick="showAirMulti(); return false;", class="btn-custom-normal">Show/Hide Multi-Destinations</button>
</div>
</div>
on top of the _frm the corresponding script portion:
function manageAirDisp (){
var checkbox = document.getElementById('chk_air');
// this check below checks if checkbox is checked or not.
if (checkbox.checked){
document.getElementById("air_div").style.display = "block";
document.getElementById("MultiButton").style.display = "block";
} else {
document.getElementById("air_div").style.display = "none";
document.getElementById("MultiButton").style.display = "none";
}
}
Now what I cannot get to work with a dorp down selection instead:
the erb portion:
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :event %>
<!-- < f.check_box :event, :id => "chk_event", :onclick => "manageEvent();" > -->
<%= f.select :event, [['Unkown', 'unk'], ['yes', 'yes'], ['no', 'no']], :onchange => "manageEvent();" } %>
</div>
</div>
</div>
<div class="row", id="event_blk", style="display: none">
<div class="col-md-4">
<div class="field">
<%= f.label :registration, "addQuestion?" %>
<%= f.check_box :addquestion %>
</div>
</div>
</div>
and now the corresponding script portion that I canot get to work:
function manageEvent(){
var checkbox = document.getElementById('chk_event');
// this check below checks if checkbox is checked or not.
if (selection.val() = "yes"){
document.getElementById("event_blk").style.display = "block";
} else {
document.getElementById("event_blk").style.display = "none";
}
// to check on value instead it should look as follows:
// if (checkbox.val() = "something") { then do something }
}
So what I want to do is to have the section event_blk to become visible when the user select "yes" and that as soon as they have it selected, or make it invisible as soon as they select no or unk
Thanks for any help
It looks like you aren't declaring selection -- you are setting the variable checkbox instead.
Also, you should use .value instead of .val().
Try this:
function manageEvent(){
// change checkbox to selection
var selection = document.getElementById('chk_event');
// changed selection.val() to selection.value
if (selection.value == "yes"){
document.getElementById("event_blk").style.display = "block";
} else {
document.getElementById("event_blk").style.display = "none";
}
}
Update:
You will also need to fix your select helper. If you check out the documentation, you will find that the last two arguments accepted by the select helper are the options hash and the html_options hash. You need to pass :onchange in the html_options hash. Also, Rails will default to [model_name]_[attribute_name] as the id for the select element, so you will also need to pass :id => "chk_event" in the html_options hash if you want to use that string as the id:
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :event %>
<!-- < f.check_box :event, :id => "chk_event", :onclick => "manageEvent();" > -->
<%= f.select :event,
[['Unkown', 'unk'], ['yes', 'yes'], ['no', 'no']],
{}, #empty options hash
{ :id => "chk_event", :onchange => "manageEvent();" } %>
</div>
</div>
</div>
I've built a card slider where 20 cards are loaded on each page. I'm trying to have it so that when the user clicks on a button on the the last card (card with index 19), an AJAX call is made to render the next page and replace my original 20 cards with the next 20. I'm using the will_paginate gem and I can extract the correct href for the next page (i.e. http://localhost:3000/events/queued?page=2). But when I make a get request to it, the console shows the error "Failed to load resource: the server responded with a status of 500 (Internal Server Error)". I manually entered that url into my browser and that link works fine. I tried to follow along the RailsCast on will_paginate and ajax and modify it to suit my needs but I'm pretty sure I botched something along the way. Thanks in advance for any help!
index.html.erb
<% if #events %>
<div id="event_carousel" class="col-sm-10 col-sm-offset-1 owl-carousel">
<% #events.each do |event| %>
<%= render 'event', event: event %>
<% end %>
</div>
<!-- this is set to display none -->
<div class="text-center">
<h3><%= will_paginate #events %></h3>
</div>
<% end %>
event.js
var cardCounter = 0;
var cardOwlIndex = 0;
var linksArr = [];
$.ajaxSetup({'cache': true
});
$(function(){
var owl = $("#event_carousel");
links = $('.pagination > a');
for (var i = 0; i < links.length - 1; i++) {
linksArr.push(links[i].href);
};
$('.btn-square.like').off().on('click', function() {
$(this).toggleClass('btn-pressed-square-like');
owl.trigger('owl.next');
var owlIndex = $(this).closest('.owl-item').index();
alert(owlIndex);
cardCounter = owlIndex;
cardOwlIndex = owlIndex;
console.log(cardCounter);
if (cardCounter === 19 && cardOwlIndex === 19) {
alert(linksArr[0]);
$.get(linksArr[0], null, null, "script");
};
});
});
index.js.erb
$('#event_carousel').html("<%= escape_javascript(render partial: 'event') %>");
events_controller.rb
def index
#events = Event.with_rankings(current_user.id, Date.today, 1.month.from_now)
.order("event_rankings.weighted_score DESC")
.paginate(:page => params[:page], :per_page => 20)
respond_to do |format|
format.js
end
end
EDIT:
error logs:
ActionView::Template::Error (undefined local variable or method `event' for #<#<Class:0x007fcbd06fd850>:0x007fcbd553d740>):
1: <div class="col-sm-12">
2: <div class="col-sm-12 event-card flip" style="background-image: url(<%= event.image.url(:large) %>);" id="<%= event.id%>">
3: <div class="card">
4: <div class="card-face front">
5: <% if current_user && current_user.admin %>
app/views/events/_event.html.erb:2:in `_app_views_events__event_html_erb__2820478606869763483_70256714846000'
app/views/events/index.js.erb:1:in `_app_views_events_index_js_erb___681525537736992419_70256717102340'
app/controllers/events_controller.rb:55:in `queued'
DevTools shows that it's breaking on this line:
xhr.send( ( options.hasContent && options.data ) || null );
As you want to replace all of the current records with the new page results so you need to replace existing page content with the new one exactly like the index.html.erb
Here are steps to do it.
1.Create a common partial for your events.
_events.html.erb
<% if #events %>
<div id="event_carousel" class="col-sm-10 col-sm-offset-1 owl-carousel">
<% #events.each do |event| %>
<%= render 'event', event: event %>
<% end %>
</div>
<!-- this is set to display none -->
<div class="text-center">
<h3><%= will_paginate #events %></h3>
</div>
<% end %>
2.Now in your index.html.erb
<div id="events_container">
<%=render partial: 'events'%>
</div>
3.Now for your ajax request add following line index.js.erb
$('#events_container').html("<%= escape_javascript(render partial: 'events') %>");
I am using $.getJSON in a jquery script to get data from a php file and display it in a template(underscore).
My template:
<script type="text/template" id="user-template">
<% _.each(users, function(user){%>
<div class="id"><%=user.id%> </div>
<div class="name"><%= user.name %></div>
<div class="city"><%= user.city %></div><br />
<% }); %>
</script>
My script:
$.getJSON(url, function(data){
var results = userTemplate({ users: data.users}),
$("#theresults").html(results);}
On each page im listing 10 users (or 10 results). The code works fine. I want to be able to show another div after every 4 results. Like an ad or a promotional content.
<div id="mycustomdiv">Custom DIV</div>
How do i do that?
Thanks.
Just use the second argument of the callback function to determine the current index
<% _.each(users, function(user, index){%>
<div class="id"><%=user.id%> </div>
<div class="name"><%= user.name %></div>
<div class="city"><%= user.city %></div><br />
<% if(index !== 0 && (index % 4) === 0) { %>
<div id="mycustomdiv">Custom DIV</div>
<% } %>
<% }); %>