making auto-updating, facebook-style time formatting - javascript

Can some help me figure out why my javascript HTML template doesn't auto-update the time but the regular HTML does? Here's the templating library i'm using: https://github.com/blueimp/JavaScript-Templates
here's my JS (you can fiddle with it here: http://jsfiddle.net/trpeters1/SpYXM/76/ ):
$(document.body).on('click', 'button', function(){
var id= $(this).data('id');
var data={id:id, string: "just now...", fxn: nicetime()};
var result = tmpl('<div id="string" data-id="'+id+'">{%=o.string%}</div><div id="function" data-id="'+id+'">{%=o.fxn%}</div>', data);
$('div[data-id="'+id+'"]').html(result);
nicetime();
});
function nicetime(){
var time = new Date(),
var comment_date = setInterval(function() {
var time2 = time_since(time.getTime()/1000);
$('#time_since').html(time2);
return time2;
},
1000);
}
HTML:
<button data-id="1">1</button>
<div data-id="1"></div> //tmpl output
<div id="time_since"></div> //non-tmpl output

You want something like this.
With JavaScript templating, you generally want to template once, then update the values of specific elements dynamically, as opposed to resetting the innerHTML of an entire element every second.
Here's the JavaScript:
$(document.body).on('click', 'button', function(){
var id= $(this).val(),
time = +new Date,
data = {
id: id,
string: "just now..."
},
result = tmpl('<span class="string">{%=o.string%}</span>', data),
tgt = $('#'+id),
str;
tgt.html(result);
str = tgt.find('.string');
window.setInterval(function() {
str.html(time_since(time/1000));
}, 1000);
});

Related

Adding text to a dynamically created DOM element

I'm trying to create <div> elements with child <p> elements; the <div> elements are being assigned a class of "clock" + a number (increments). While the elements themselves seem to be created, adding text (in my case a moment object) to the <p> element doesn't work.
HTML:
<body>
<select class="tz_list" name="timezones">
<option value="default">Please Select a Timezone</option>
</select>
<input type="button" name="addClock" value="Add Clock" class="button">
</body>
JS:
$(document).ready(function () {
var now = moment();
console.log(now);
//var repeat = setInterval(displayTime, 200);
var tzones = moment.tz.names();
tzones.forEach(function(key,value){
$('<option/>').val(key).html(key).appendTo('.tz_list');
});
var repeat;
var clock_count = 1;
var timezone ="";
function displayTime(timezone, clock_number) {
console.log(timezone);
var location = moment().tz(timezone).format("ddd, MMMM Do YYYY, HH:mm:ss");
console.log(location);
//$('.clock '+clock_number)[0].childNodes[0].nodeValue = timezone;
var selector = '.clock '+clock_number.toString() + ' p';
console.log(selector);
//$('.clock '+clock_number.toString()).css({"height":"100px", "width":"500px"});
$(selector).text(location.toString());
};
$('.button').on('click', function(e){
console.log(e.target.value);
var div = '<div class="clock '+clock_count.toString()+'"><p></p></div>';
$(div).insertAfter('.button');
clock_count+=1;
displayTime(timezone, clock_count-1);
});
$('.tz_list').on('change', function(event){
console.log(event.target.value);
timezone = event.target.value;
});
});
What am I missing?
Here is a JSFiddle
Instead creating class "clock " try to create with out giving space. It will work.
function displayTime(timezone, clock_number) {
console.log(timezone);
var location = moment().tz(timezone).format("ddd, MMMM Do YYYY, HH:mm:ss");
console.log(location);
//$('.clock '+clock_number)[0].childNodes[0].nodeValue = timezone;
var selector = '.clock'+clock_number.toString() + ' p';
console.log(selector);
//$('.clock'+clock_number.toString()).css({"height":"100px", "width":"500px"});
$('.clock'+clock_number.toString()).text(timezone);
$(selector).text(location.toString());
};
$('.button').on('click', function(e){
console.log(e.target.value);
var div = '<div class="clock'+clock_count.toString()+'"><p></p></div>';
$(div).insertAfter('.button');
clock_count+=1;
displayTime(timezone, clock_count-1);
});
Change this line:
$('.clock.'+clock_number.toString()).text(timezone);
add the "." after clock but is not a god practice add number as class, instead use something like clock_1 (or clock1 like the answer below)

Format number with commas in .each function

So I have some js which is converting a div class's number through a daily exchange rate engine. It outputs correctly as it should and I am now trying to separate this number it outputs using jQuery and a function I found whilst doing some research. I am trying to feed the number to the function using a .innerHTML method. I have got the function to alert a converted number but I have multiple elements which this function should run for, so have used an .each function - this is where something isn't working. I get no alert so I think there is something wrong with the .each code.
Can anyone see anything that might be causing it?
The complete code is here:
<script src="https://raw.githubusercontent.com/openexchangerates/money.js/master/money.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<div class="hello">
2300
</div>
<div class="hello">
52400
</div>
<script>
function ReplaceNumberWithCommas(yourNumber) {
//Seperates the components of the number
var n= yourNumber.toString().split(".");
//Comma-fies the first part
n[0] = n[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
//Combines the two sections
return n.join(".");
}
$(".hello").each(function() {
var currentDiv = $(this);
var currentPrice = currentDiv.text();
var demo = function(data) {
fx.rates = data.rates
var rate = fx(currentPrice).from("GBP").to("USD");
currentDiv.html("<div>"+currentPrice +"</div><div id='converted'> " +rate.toFixed(0)+"</div>");
//alert("Product Costs" + rate.toFixed(4))
}
$.getJSON("http://api.fixer.io/latest", demo);
});
$("#converted").each(function() {
var convertedPrice = $(this.innerHTML);
function runThis() { alert( ReplaceNumberWithCommas(convertedPrice)) }
setTimeout (runThis, 100);
});
</script>
I think the reason is
$("#converted").each(function() {
var convertedPrice = $(this.innerHTML);
function runThis() { alert( ReplaceNumberWithCommas(convertedPrice)) }
setTimeout (runThis, 100);
});
happends before you created the converted elements. Because you put the creation inside a get call.
I suggest you put this inside the callback of your get call.
Something like this
function ReplaceNumberWithCommas(yourNumber) {
//Seperates the components of the number
var n = yourNumber.toString().split(".");
//Comma-fies the first part
n[0] = n[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
//Combines the two sections
return n.join(".");
}
var currentDiv = $(this);
var currentPrice = currentDiv.text();
var demo = function(data) {
fx.rates = data.rates
$(".hello").each(function() {
var currentDiv = $(this);
var currentPrice = currentDiv.text();
var rate = fx(currentPrice).from("GBP").to("USD");
currentDiv.html("<div>" + currentPrice + "</div><div class='converted'> " + rate.toFixed(0) + "</div>");
//alert("Product Costs" + rate.toFixed(4))
});
$(".converted").each(function() {
var convertedPrice = $(this).html();
console.log(ReplaceNumberWithCommas(convertedPrice));
});
}
$.getJSON("https://api.fixer.io/latest", demo);

Bootstrap Date Paginator datepicker

I would like to make redirect when a date is changed and transmit selected date parameter (via window.location.href). I'm using Bootstrap Date Paginator, which contains Bootstrap datepicker, but I don't know how to change these lines of code to work properly:
this.$calendar
.datepicker({
options...
})
.datepicker('update', this.options.selectedDate.toDate())
.on('changeDate', $.proxy(this._calendarSelect, this));
I know I would use changeDate event but there aren't any examples of using this event. Can you help me, please?
Would this do?
You can use .on('change', ..) like this,
this.$calendar
.datepicker({
options...
}).on('change', function() {
var changedDate = this.$calendar.val();
//alert("value of date is "+ x);
var theUrl = 'your URL';
window.location.href = theUrl+"date="changedDate
});
Else use, on('change.dp', ..) event like this,
this.$calendar
.datepicker({
options...
}).on('change.dp', function() {
var changedDate = this.$calendar.val();
//alert("value of date is "+ x);
var theUrl = 'your URL';
window.location.href = theUrl+"date="changedDate
});
Alternatively have a look at this too.
May be it's too late, but I have same problem and come up with this solution,
while setting options for Bootstrap Date Paginator keep track of onSelectedDateChanged function and assign the date value to a variable and send that variable to location.href.
<script>
var currDate = new Date();
var options = {
selectedDateFormat: 'DD/MM/YYYY',
selectedDate: moment(currDate).format('DD/MM/YYYY'),
onSelectedDateChanged: function (event, date) {
var dateSelected = moment(date).format('DD/MM/YYYY');
location.href = '/ServletName?timestamp='+currDate .getTime() + "&date=" + dateSelected ;
},
};
$('#paginator').datepaginator(options);
</script>
<body>
<div id="paginator"></div>
</body>

Javascript results to div

Q1: My point is create many buttons as many rows of array. Like this, only one button appears.
<script type="text/javascript">
var myArray = [];
$('#button').click(function(){
var value1 = $('#value1').val();
var value2 = $('#value1').val();
var value3 = $('#value1').val();
var newArray = [];
var newArray[0] = value1;
var newArray[1] = value2;
var newArray[2] = value3;
myArray.push(newArray);
$("#save").append(
$("<button>").click(function() {
myFunction.apply(null, myArray);
}).text("Click me!")
);
});
});
function myFunction(value1,value2,value3)
{
var jsonData = $.ajax({
url: "file.php?value1=" + value1 + "&value2=" + value2 + "&value3=" + value3
dataType: "json",
async: false
}).responseText;
(...)
}
//edited: problem maybe found. I said buttons dont do anything because of this.
OUTPUT: file.php?value1=paul,23,USA&value2=undefined&value3=undefined
//it seems that value1 gets all values :s
</script>
<div id ="save"></div>
Im looking for a solution that return someting like this:
eg:
<!--<button onclick="myFunction(name,age,country)">Click me</button>-->
<button onclick="myFunction(paul,23,USA)">Click me</button>
<button onclick="myFunction(john,23,USA)">Click me</button>
EDITED MY CODE WITH MORE DETAILS
.html replaces, and your quotes are mismatched. But it doesn't matter - jQuery is better at manipulating the DOM than it is at manipulating strings. Try:
$("#save").append(
$.map(myArray, function(item) {
return $("<button>").click(function() {
myFunction.apply(null, item);
}).text("Click me");
})
);
Here's a demo.
You're only seeing one button because the .html() method replaces the html of the element. It doesn't append.
Luckily, jQuery has a method for the behavior you want, fittingly called append. Change it to look like this:
for(i=0;i<myArray.length;i++)
{
var button = $("<button>Click me</button>");
$("#save").append(button) ;
}
I intentionally left the onclick behavior out of that snippet. You can write it in the html of the button you create, as you have been, or you can do it with jQuery - the second method is preferable, and would look like this:
for(i=0;i<myArray.length;i++)
{
var button = $("<button>Click me</button>")
.click(function(){
// call the actual function you want called here
});
$("#save").append(button);
}
Did you mean this:
<div id="save">
</div>
<script type="text/javascript">
function addButtons(){
for(i=0;i<myArray.length;i++)
{
var button = $('<button id="btn_'+i+'" onclick="myFunction(this);">Click me</button>')
$(button).data('details',myArray[i]).appendTo("#save");
}
}
function myFunction(element){
alert($(element).data('details'));
}
</script>
This is because you are replacing the html in the $("#save") in the loop . Try
$("#save").append("<button onclick="myFunction('"+myArray[i]+"')">Click me</button>") ;
for(i=0;i<myArray.length;i++){
//Create a new DOM button element ( as jQuery object )
// Set the current button index, and add the click action
var button = $('<button />').data('myindex', i).click(function(){
var myArrayItem = myArray[$(this).data('myindex')];
alert(myArrayItem);
}).html('My label n. '+i);
$('#save').append(button)
}
Why bothering with all the JQuery and complicated code, just use simple way to implement this
<script type="text/javascript" >
var myArray = ["New York", "Boston", "San Jose", "Los Angeles"];
var strHTML = "";
for(i=0;i<myArray.length;i++)
{
strHTML += "<button onclick='myFunction("+i+")'>Click me</button>";
}
$("#save").innerHTML = strHTML;
function myFunction(index)
{
alert(index);
// do your logic here with index
}
</script>

.clone doesn't not appear to be incrementing

this script is suppose to clone a new row of a HTML table. It does not seem to be incrementing the name, id, attributes. What am I doing wrong? The only other thing that is not working is get the value from the previous input id of #endtime_* and putting it in the cloned input id of #starttime_* although I think that is because it does seem to be incrementing as it clones a row.
<script type="text/javascript">
function MaskTime(){
var index = $("#TimeCard tbody>tr").length-1;
$('#endtime_'+index).mask("99:99 aa");
$('#starttime_'+index).mask("99:99 aa");
}
function update_rows(){
$("#TimeCard tbody>tr:odd").css("background-color", "#FFF");
$("#TimeCard tbody>tr:even").css("background-color", "#999");
}
$(document).ready(function() {
$("#addrow").click(function() {
var row = $('#TimeCard tbody>tr:last').clone(true).insertAfter('#TimeCard tbody>tr:last');
var index = $("#TimeCard tbody>tr").length-1;
var endvalue = $('#endtime_'+index-1).val();
$("td:eq(0) select").attr("name", 'type_'+index).attr("id", 'type_'+index).addClass("validate[required]").val('')
$("td:eq(1)").html(" ")
$("td:eq(2) select").attr("name", 'propid_'+index).attr("id", 'propid_'+index).addClass("validate[required]").val('')
$("td:eq(3)").html(" ")
$("td:eq(4) input").attr("name", 'starttime_'+index).attr("id", 'starttime_'+index).addClass("validate[required,custom[timeclock]]").val(endvalue)
$("td:eq(5) input").attr("name", 'endtime_'+index).attr("id", 'endtime_'+index).addClass("validate[required,custom[timeclock]]").val('')
$("td:eq(6)").html(" ")
update_rows();
MaskTime();
return false;
});
});
</script>
For the first part of your question:
It does not seem to be incrementing the name, id, attributes.
Your script isn't giving the proper context for where the tds are for which you want to modify the attribues, etc.
Here's a modification that corrects that, adding a new variable "newrow" (to reduce DOM calls) and modifying the lines of code related to td:eq(#)...
$(document).ready(function() {
$("#addrow").click(function() {
var row = $('#TimeCard tbody>tr:last').clone(true).insertAfter('#TimeCard tbody>tr:last');
var index = $("#TimeCard tbody>tr").length-1;
var endvalue = $('#endtime_'+index-1).val();
var newrow = $("#TimeCard tbody>tr:last");
newrow.children("td:eq(0)").children("select").attr("name", 'type_'+index).attr("id", 'type_'+index).addClass("validate[required]").val('')
newrow.children("td:eq(1)").html(" ")
newrow.children("td:eq(2)").children("select").attr("name", 'propid_'+index).attr("id", 'propid_'+index).addClass("validate[required]").val('')
newrow.children("td:eq(3)").html(" ")
newrow.children("td:eq(4)").children("input").attr("name", 'starttime_'+index).attr("id", 'starttime_'+index).addClass("validate[required,custom[timeclock]]").val(endvalue)
newrow.children("td:eq(5)").children("input").attr("name", 'endtime_'+index).attr("id", 'endtime_'+index).addClass("validate[required,custom[timeclock]]").val('')
newrow.children("td:eq(6)").html(" ")
update_rows();
MaskTime();
return false;
});
});
Also, I'd made a jsfiddle with the above: http://jsfiddle.net/m78UN/2/
I'm not following what you're wanting when you describe your second problem:
The only other thing that is not working is get the value from the previous input id of #endtime_* and putting it in the cloned input id of #starttime_*
...so I've not attempted to address that.
I think you can do everything you're doing in a way simpler way. I don't have your original HTML, but check this out as a possible alternative. It mainly does 3 things:
Removed IDs used for finding things
Caches selectors
Adds classes to time inputs to make them easier to reference
Removed MaskTime() function
Here's the code:
$(document).ready(function() {
var $timecard = $("#TimeCard");
var $tbody = $timecard.find("tbody");
var $rows = $tbody.children("tr");
$("#addrow").click(function(e) {
e.preventDefault(); // clearer than return false
var $lastRow = $tbody.find("tr:last-of-type");
var lastEnd = $lastRow.find(".endTime").val();
var $newRow = $lastRow.clone(true).appendTo($tbody);
var $cols = $newRow.find("td");
var index = $rows.length - 1;
$cols.eq(0).find("select").attr("name", 'type_' + index).addClass("validate[required]").val('');
$cols.eq(1).empty();
$cols.eq(2).find("select").attr("name", 'propid_' + index).addClass("validate[required]").val('');
$cols.eq(3).empty();
$cols.eq(4).find("input").attr("name", 'starttime_' + index).addClass("time startTime validate[required,custom[timeclock]]").val(lastEnd);
$cols.eq(5).find("input").attr("name", 'endtime_' + index).addClass("time endTime validate[required,custom[timeclock]]").val('');
$cols.eq(6).empty();
update_rows(); // no idea what this is
$newRow.find(".time").mask("99:99 aa"); // MaskTime() just did this
});
});

Categories

Resources