Update View After Selecting Date Range (Rails, Javascript) - javascript

I have a table that shows sales by event for a bunch of different date ranges (last month, last week, etc.)
<% #events.each do |event| %>
<tr class="<%= cycle("odd", "even") -%>">
<td class=" "><%= number_to_currency(stripe_to_display(event.sales(VARIABLE_1,VARIABLE_2))) %></td>
<td class=" "><%= number_to_currency(stripe_to_display(event.sales(0,0))) %></td>
<td class=" "><%= number_to_currency(stripe_to_display(event.sales(7,0))) %></td>
<td class=" "><%= number_to_currency(stripe_to_display(event.sales(30,0))) %></td>
<td class=" "><%= number_to_currency(stripe_to_display(event.sales)) %></td>
</tr>
<% end %>
That first td row calculates sales based on a CUSTOM date range. An event instance can calculate sales based on two integers (start_day and end_day). (They represent the number of days from today.)
And when a date range is selected, this Javascript is called:
$(document).ready(function() {
$('#sales_date_range').daterangepicker(
{
format: 'YYYY-MM-DD',
startDate: $.now,
endDate: $.now
},
function(start, end, label) {
var now = new Date();
var start_days_ago = (now - start) / 86400000;
var end_days_ago = (now - end) / 86400000;
start_days_ago = start_days_ago.toFixed();
end_days_ago = end_days_ago.toFixed();
}
);
});
Importantly, that last Javascript function calculates start_days_ago and end_days_ago which are what an event instance needs to calculate sales for a custom date period.
So my problem: I can figure out the required arguments in JS, but don't know how to get them to the ERB file.
I assume it has something to do with AJAX and conceptually this is wrong, but my hours of searching haven't gotten me any closer to a solution.

Figured it out:
I created params with the JS days variables:
var path = '?start_day=' + start_days_ago + '&end_day=' + end_days_ago
and then refreshed the page with the new path:
window.location = path;
Then my controller has access to the two arguments:
#start_day = params[:start_day].to_i
#end_day = params[:end_day].to_i

In case you want a more snappy update (not refreshing the whole page), you could also load part of the page in. Keep the changes you made (Using params[:start_day] etc.), but change your javascript to something like:
$("#events").load('path/to/action #events', {start_day: start_days_ago, end_day: end_days_ago});
And give your table the id of events. Then only the table it self will update, ajax style. Note that you might have to deal with error handling and that the page url won't update this way.

Related

Is there a way to remove and HTML element after six hours?

I have a picture with the word "NEW" over it to designate a new document that has been posted to our website. I would like to have jQuery remove the picture after 6 hours of it being posted. How would I go about doing this?
Here is the element:
<tr class="pointer">
<td>
<img class="germ" src="~/Image" width="40px" />
<i class="created" hidden="hidden">April 3, 2020 13:13:00</i>
Document Title
</td>
<td>PDF</td>
<td>March 2020</td>
</tr>
As you can see, I have a hidden <i> element that designates when the document was posted to the website. I need to remove the <img> tag 6 hours from the time in the <i> tag.
How can I do this using jQuery or JavaScript?
This would be better done server-side. The way you want to do it assumes that the user will have this same page up for 6+ hours, or come back to this page in the same state, which is pretty unlikely.
What I would do is add a property to the post for created and have it set a default time of Date.now(), and then have front end code look for whether that created value was less than 6 hours ago (1000 * 60 * 60 * 6 miliseconds).
If so, show the 'New' graphic. If not, don't.
Another way to do it so that you don't have to update server-side stuff that might be more set in stone is to have the default display for the "New" graphic to be true, then:
let createdTime = new Date(document.queryselector('i.hidden').textContent);
if (Date.now() - createdTime > (1000 * 60 * 60 * 6)){
//code to hide the "New" graphic
}
A little extra two cents for free: I would add an id attribute to that hidden i element to make sure you're selecting only that and not something else that may have the same class
Since you asked how to do this with JavaScript or JQuery, this is how.
I also included a 3-second example to show that it does work.
window.setTimeout(function() {
document.getElementById('sixHours').outerHTML = '';
}, 2160000);
window.setTimeout(function() {
document.getElementById('threeSeconds').outerHTML = '';
}, 3000);
<div id="sixHours">This will be removed after six hours</div>
<div id="threeSeconds">This will be removed after three seconds</div>
Keep in mind, that as soon as the page is refreshed, the timer will start over. If you want to avoid this and still have JavaScript handle it, you could have it removed at a definite time.
Edit
The snippet below will parse the date in expiration and find the milliseconds from that till now. Then like the snippet above, the remove element will get removed when the timer expires. 6 hours are added to the timer to make it expire 6 hours from the given time.
var expiration = Date.parse(document.getElementById('expiration').innerHTML);
var diff = expiration - Date.now();
window.setTimeout(function() {
document.getElementById('remove').outerHTML = '';
}, diff + 2160000);
//2160000ms = 6 hours
<div id="expiration">April 3, 2020 20:00:00</div>
<div id="remove">Will be removed by the date above</div>
Use setTimeout(), but bear in mind that people aren't likely going to sit at a single page for 6 hours meaning this will fail as soon as they navigate away. You'll have to change the time sent over every time they refresh.
const testing = true;
if (testing) {
// BEGIN - Fake date for testing
const tmpNow = new Date();
document.querySelector("i.created").innerHTML = tmpNow.toUTCString();
// END - Fake date for testing
}
const d = document.querySelector("i.created").innerHTML;
const dd = new Date(d);
if (testing) {
dd.setSeconds(dd.getSeconds() + 3);
} else {
dd.setHours(dd.getHours() + 6);
}
const ddd = dd.getTime();
const now = Date.now();
if (ddd < now) {
console.log("Too late");
}
const dt = Math.max(ddd - now, 0);
setTimeout(() => {
const img = document.querySelector("img.germ");
img.parentNode.removeChild(img);
}, dt);
<tr class="pointer">
<td>
<img class="germ" src="~/Image" width="40px" />
<i class="created" hidden="hidden">April 3, 2020 13:13:00</i> 03.21.2020 GOA - Alaska Businesses Now Eligible for SBA Economic Injury Disaster Loans (2)
</td>
<td>PDF</td>
<td>March 2020</td>
</tr>
You don't understand the problem here.
As R Greenstreet said it needs to be done server-side. You need a Create Post Date to be sent to UI.
Let's assume you have a JSON coming from a server where you can add createDate property of a post form bata base.
{createDate: date, name......}
You need to compare that date with Date.now()
Pseodu Code here:
if(createDate + 6 hours >= Date.now()) then hide your Icon.
You will need to use Date to convert the String into a Date Object:
new Date("April 3, 2020 13:13:00");
This will create a Date Object, yet since there is no Timezone Offset, the script might assume UTC. Your result might be:
"2020-04-03T13:13:00.000Z"
So consider specifying a Time Zone. Some browsers will assume the Users local Timezone.
$(function() {
function getDate(cObj, tz) {
if (tz == undefined) {
tz = "GMT-07:00";
}
var str = cObj.text().trim() + " " + tz;
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
var nDt = new Date(str);
console.log(str, nDt);
return nDt;
}
function getHoursPast(thn) {
// https://stackoverflow.com/questions/19225414/how-to-get-the-hours-difference-between-two-date-objects/19225463
var now = new Date();
return Math.floor(Math.abs(now - thn) / 36e5);
}
var hours = getHoursPast(getDate($(".created")));
console.log(hours + " have passed since", getDate($(".created")));
if (hours > 5) {
$(".germ").remove();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr class="pointer">
<td>
<img class="germ" src="~/Image" width="40px" />
<!--
Would advise better format
Example: 2020-04-03T13:00.000-7:00
-->
<i class="created" hidden="hidden">April 3, 2020 13:13:00</i> Document Title
</td>
<td>PDF</td>
<td>March 2020</td>
</tr>
</table>
References
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
How to get the hours difference between two date objects?
Getting the client's timezone offset in JavaScript

Rails 5, Ajax, jQuery - Cant send received data to particular element

So, I have partial where is a table row and different table datas. By clicking a button (which is in <tr>) I send Ajax request (simply, with remote: true) and also update item data (displayed in <tr>) with action.
It all goes fine, but I can't send received data from Ajax to specific <td>. If more items being displayed - all of them receives that data.
_partial.html.erb:
<body>
<div>
<tr data-line-item-id='<%= line_item.id %>' class='line-item'>
<td data-th="Product">
<div class="row">
<div class="col-sm-2 hidden-xs"></div>
<div class="col-sm-10">
</div>
</div>
</td>
<td data-th="Price"><%= number_to_currency(line_item.product.price) %></td>
<td data-th="Quantity">
<%= line_item.quantity %>
</td>
<td data-th="Subtotal" class="text-center" class="subtotal">
<%= number_to_currency(line_item.total_price, :unit => "€", separator: ",", format: "%n %u") %></td>
<td class="actions" data-th="">
<td><%= link_to "-", decrease_line_item_path(product_id: line_item.product), remote: true %></td>
<td><%= link_to "+", increase_line_item_path(product_id: line_item.product), remote: true %></td>
</td>
</tr>
</div>
</body>
decrease.js.erb:
$("td[data-th='Quantity']").html('<%= #line_item.quantity %>');
My 'nice tries' were something like:
$(this).parent().parent().find("td[data-th='Quantity']").html('<%= #line_item.quantity %>');
But my 'best achievement' was to update only the particular, found by number item, like this:
$("td[data-th='Quantity']").eq(0).html('<%= #line_item.quantity %>');
Otherwise they all get updated...
UPDATE
This, kinda made it working, but if I increase numbers of one item and then increase other item numbers, first click shows the number of previously updated item number... But answer is close. Hope someone could help... Many thanks
increase.js.erb:
$(document).ready(function(){
$('.increase').click(function(){
var element = $(this).parent().parent()
$(element).find("td[data-th='Quantity']").html('<%= #line_item.quantity %>');
});
});
You should not add click event in js.erb file in your case as when the page loads increase.js.erb's click function is not available.
Lets say current quantity is 2.
Now on first click AJAX request is sent, in response $('.increase') function is loaded but it will not execute as the first click happened before the AJAX response.
def increase
# quantity is increased to 3.
end
The increase function which just loaded will have new incremented number.
// first click function loaded not triggered.
$(document).ready(function(){
$('.increase').click(function(){
var element = $(this).parent().parent()
// $(element).find("td[data-th='Quantity']").html('<%= #line_item.quantity %>');
$(element).find("td[data-th='Quantity']").html('3');
// but as the click is not triggered in first click, the value has changed to 3.
});
});
On second click on increase button, the first click function gets executed, changing the value of the td cell to 3. And in response to AJAX call of 2nd click on increase button, one more $('.increase').click() is loaded with a value 4. But again this newly loaded function doesn't execute.
// second click function loaded not triggered in response to second click.
$(document).ready(function(){
$('.increase').click(function(){
var element = $(this).parent().parent()
// $(element).find("td[data-th='Quantity']").html('<%= #line_item.quantity %>');
$(element).find("td[data-th='Quantity']").html('4');
// but as the click is not triggered in second click, the value has changed to 4.
});
});
// this 2nd function will get executed on third click.
decrease.js.erb
$('tr[data-line-item-id]').each(function(){
if ($(this).data('line-item-id') == '<%= #line_item.id %>' ){
$(this).each(function(){
if ( $(this).data('th') == 'Quantity' ) {
$(this).html('<%= #line_item.quantity %>');
}
});
}
});
This can be made a lot simpler if you add an id attribute to each tr, for example:
<tr data-line-item-id='<%= line_item.id %>' id='row-<%= line_item.id %>' class='line-item'>
---
</tr>
and then access it in decrease.js.erb like this:
$('#row-<%= #line_item.id %> td:nth-child(3)').html('<%= #line_item.quantity %>');

Rails: Making each choice in a form select field render relevant input in another form field

Noob here so I apologize ahead of time for sounding like an amateur. I'm trying to code an e-commerce site. Customers will order posters from images uploaded to the site and get to choose the size of poster (h x w) they want depending on the dimensions of the original image. I have a form for creating a new order and one of the fields is a select field with the poster size options. When they select a size, I want a price to automatically update in a separate field in the form so they know before submitting the form what the price will be.
The strategy I've been trying is to add jQuery onclick code in the select field choices. Here's what I have for the form (just showing the first choice in the select field for brevity):
<%= form_for(#order) do |f| %>
<div id="order_form">
<div class="field">
<%= f.label(:size) %><br>
<%= f.select(:size, [link_to("#{#image.dimensions['width']/120} * #{#image.dimensions['height']/120}", '#', :onclick => "showPrice('#{#image.dimensions['width']/120} * #{#image.dimensions['height']/120}'); return true;"), ... ]) %>
</div>
<div class="field">
<%= f.label(:price) %><br>
<%= f.text_field :price, :id => 'price' %>
</div>
</div>
And in assets>javascripts>application.js my jQuery code is:
function showPrice(size) {
$("#price").html("$" + size * 0.08);
}
It's not working and I don’t know if what I’m trying to do won’t work or if I'm just doing it wrong.
Thanks in advance for any help.
Here's the solution I came up with finally... I changed my goal a little, instead of trying to make it so when the user selects the size it will automatically update the price field I just made a separate paragraph (not a form field). Here's what it looks like:
<div id="order_form">
<p id='price'><%= '$' + :size.to_int * 0.8 %></p>
<div class="field">
<%= f.label(:size) %><br>
<%= f.select :size, ["#{#image.dimensions['width']/120} X # {#image.dimensions['height']/120}", "#{#image.dimensions['width']/140} X #{#image.dimensions['height']/140}", "#{#image.dimensions['width']/160} X #{#image.dimensions['height']/160}", "#{#image.dimensions['width']/180} X #{#image.dimensions['height']/180}", "#{#image.dimensions['width']/200} X #{#image.dimensions['height']/200}", "#{#image.dimensions['width']/220} X #{#image.dimensions['height']/220}"], {}, :oninput => "showPrice(this)" %>
</div>
</div>
and here's my jQuery function:
function showPrice(size) {
var Amt = $(size).val();
var arr = Amt.split(" ");
var newerAmt = Math.round( arr[0] * arr[2] * 0.8);
$("#price").html('Price: $' + newerAmt);
}
This works except it's not automatically showing the price when the page with the form loads with the default size... any advice on that would be great...
~~~~~~~~~
OK I finally figured that last part out. I referred to another thread on here and it led me to this solution so sorry for the resubmit but here it is:
To get JavaScript to recognize the ruby symbol :size I added this div in that same file:
<%= content_tag :div, class: "size_information", data: {size: #size} do %>
<% end %>
It isn't visible in the browser but it contains the data we need for JS.
Then in the JS function on that same page I referred to that data and then was able to use it as a variable:
<%= javascript_tag do %>
$(document).ready(function() {
var size = $('.size_information').data('size');
var arr = size.split(" ");
var newerAmt = Math.round( arr[0] * arr[2] * 0.8);
$("#price").html('Price: $' + newerAmt);
})
<% end %>
I would try something like this.
$('select#size').change( function () {
var amount = $('select#size').val();
var newAmt = amount * 0.08
$('#price').val('$' + newAmt);
})
Try breaking down the parts of the code to see which is working and which are not.
For example start with something simple like this
$('select#size').change(function () {
var amount = $('select#size').val();
console.log(amount)
//checking to see if .change function works
//and if you are able to collect the value of
//whats inside 'select#size'
})
If this works then maybe you can consider doing the next line
var newAmt = amount * 0.08
console.log(newAmt)
If this works then next would be to try checking to see if you are successfully calling on the #price field.
var price = $('#price').val();
console.log(price)
So if thats working then maybe you can try placing values into #price first
$('#price').val('its working!')
If all of them are working, combining the whole code should work too. Hope this helps!

Change the color of the table row based on the value from sercer

I am creating a JSP page with a html table to display employee directory. This is scriptlet :
<%
String selectedItem = "";
List<Employee> list = new ArrayList<Employee>();
PhoneListController controller = new PhoneListController();
list = controller.getAllContacts();
}
for (Employee eachEmp : list) {
%>
<tr >
<td><%=eachEmp.getLast()%></td>
<td><%=eachEmp.getFirst()%></td>
<td><%=eachEmp.getExt()%></td>
<td><%=eachEmp.getLoc()%></td>
<td><%=eachEmp.getCell()%></td>
<td><%=eachEmp.getTeam1()%></td>
</tr>
<% } %>
and then i display the table rows and columns for each employee object(PS: I know scriptlets are bad and obsolete but this is my first individual project.)
I would like to change the background color of certain rows based on value of one particular value(based on eachEmp.getManagerCode).
How can i achieve that by using javascript? I tried to call a js function by calling onload event on . But as I need to check for each row that is not the possible solution. I have not tried jquery yet as I am very new to jquery and I didnt quite understand how to do it in jquery.
Please help.
Thanks
you can simply use an if statement
<%
String selectedItem = "";
List<Employee> list = new ArrayList<Employee>();
PhoneListController controller = new PhoneListController();
list = controller.getAllContacts();
}
for (Employee eachEmp : list) {
if (eachEmp.getManagerCode==1) { %>
<tr class="red">
<% } else { %>
<tr class="blue">
<% } %>
<td><%=eachEmp.getLast()%></td>
<td><%=eachEmp.getFirst()%></td>
<td><%=eachEmp.getExt()%></td>
<td><%=eachEmp.getLoc()%></td>
<td><%=eachEmp.getCell()%></td>
<td><%=eachEmp.getTeam1()%></td>
</tr>
<% } %>
Or if you don't want to use css class you can simply write etc.. etc..
you can put how many if you want, or use the switch statement

How to validate the Two Date fields on my view using jquery or javascript

I have two fileds in my View one is Effective data and one is Cancel date
<td>
Effective date:
</td>
<td>
<%= Html.TextBoxFor( x => Model.SelectedAccountGroup.GroupEffectiveDate, new { #class="datepicker"} )%>
<%= Html.ValidationMessageFor( x => x.SelectedAccountGroup.GroupEffectiveDate )%>
</td>
</tr>
<tr>
<td>
Cancel date:
</td>
<td>
<%= Html.TextBoxFor( x => Model.SelectedAccountGroup.GroupCancelDate, new { #class = "datepicker" } )%>
<%= Html.ValidationMessageFor( x => x.SelectedAccountGroup.GroupCancelDate )%>
</td>
On Save button I should not allow user to Enter the Cancel date Before Effective data? can any body tell me how to do this?
get the two date field value as a single integer value . For eg 20101006 .
if time is also there add that too,
if you use jquery
var dateval= $("#dateid").val();
for javascript
var dateval = document.getElementById("dateid").value;
I assume the text box where you show date is having an id. let it be dateid
Now you can compare two fields just as integer.
if(date1>date2)
do something
return false

Categories

Resources