Bind click event to dynamically generated content (Angular 4) - javascript

I have the following function that basically generates a date and inserts it before a div in a view - I need to modify this so I am able to use a click event using the angular renderer function but having difficulties with the code below:
generateTimestampDiv(date, $this) {
let parent = document.getElementsByClassName('ui-datepicker-header');
let minutes = (date.getMinutes()<10 ? '0' : '') + date.getMinutes();
let datetime = date.toDateString()+' '+date.getHours()+':'+minutes;
let content = '<div style="background-color: #fafafa; width:90%;">'+ datetime +'</div>';
$(content).insertBefore(parent[0]);
// this bit is incorrect
this.renderer.listen(content, 'click', (event) => {
this.userClicked(event, this);
})
}
I need to modify the function to insert the content as per the function but also listen for a click event event so that I can pass the event to the userClicked() function

Use the Angular Renderer2 insertBefore method
export class AppComponent implements OnInit {
#ViewChild('clickablediv') el: ElementRef;
constructor(private _renderer: Renderer2) { }
ngOnInit() {
this._renderer.listen(this.el.nativeElement, 'click', (event) => {
this.generateTimestampDiv(new Date())
});
}
generateTimestampDiv(date) {
let minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes();
let datetime = date.toDateString() + ' ' + date.getHours() + ':' + minutes;
const div = document.createElement('div');
div.style.backgroundColor = "#fafafa";
div.style.width = "90%";
div.innerHTML = datetime;
this._renderer.insertBefore(this.el.nativeElement.parentNode, div, this.el.nativeElement)
}
}
demo

Related

Updating component realtime based on Vue + apexchart + websocket

I have a chart like so:
.....
<div class="flex flex-auto">
<apexchart
width="300%"
height="380"
type="line"
:options="optionsLine"
:series="seriesLine"
></apexchart>
.....
And the vue component has a method like so:
methods: {
getTraceData: function (data) {
var esocket = new WebSocket(
"ws://localhost:5001/provideTraceData?serverHost=" + data
);
esocket.onmessage = function (event) {
var res = JSON.parse(event.data);
var ts = [];
var dataLength = res["timeseries"].length;
console.log(res);
for (var i = dataLength - 1; i > dataLength - 11; i--) {
ts.push([
res["timeseries"][i]["timestamp"],
res["timeseries"][i]["ttfb"],
]);
}
console.log("==", ts);
this.optionsLine = {
tooltip: {
shared: false,
x: {
formatter: function (val) {
var date = new Date(val * 1000);
// Hours part from the timestamp
var hours = date.getHours();
// Minutes part from the timestamp
var minutes = "0" + date.getMinutes();
// Seconds part from the timestamp
var seconds = "0" + date.getSeconds();
// Will display time in 10:30:23 format
var formattedTime =
hours + ":" + minutes.substr(-2) + ":" + seconds.substr(-2);
return formattedTime;
},
},
},
};
this.seriesLine = [
{
name: "TTFB",
data: ts,
},
];
};
}
}
From the WebSocket server I get a JSON response, I parse it, etc, etc, and then try to update the chart series. But for some reason, the chart does not seem to render.
But when I use a basic HTTP endpoint without WebSocket to get the same data then the chart renders. I'm sort of new javascript, is there some behind the scene async shenanigans happening I'm unaware of?
The logic of updating the chart is same, the difference between the HTTP and WebSocket versions is basically the URL string and the event handler, the rest is the same.

jquery plugin multiple instances

I'm trying to create a simple jQuery plugin that allows for multiple instances of a "timepicker". I haven't done much JavaScript OOP in the past so I figured that create this would be an excellent learning experience for me. That being said, I cannot seem to figure out why all instances are affected when I changed the time. This is my first post on StackOverflow so please bear with me.
Here's the code:
(function($) {
//Helper functions
if (typeof String.prototype.endsWith != 'function') {
String.prototype.endsWith = function(str) {
return str.length > 0 && this.substring(this.length - str.length, this.length) === str;
}
}
//Find if area is on the clickable list
var findOne = function(haystack, arr) {
return arr.some(function(v) {
return haystack.indexOf(v) >= 0;
});
};
var Timepicker = function(element, options) {
this.defaults = {
now: new Date()
};
this.element = $(element);
this.createTimepicker();
this.options = $.extend({}, this.defaults, options);
this.timepicker = $('.wicked-picker'); //The outer portion of the picker
this.up = $('.wicked-picker__controls__control-up'); //the up control(s)
this.down = $('.wicked-picker__controls__control-down'); //the down control(s)
this.hoursElem = $('.wicked-picker__controls__control--hours'); //the hours text
this.minutesElem = $('.wicked-picker__controls__control--minutes'); //the minutes text
this.meridiemElem = $('.wicked-picker__controls__control--meridiem'); //the am or pm text
this.canClick = ['timepicker', this.timepicker.selector.substring(1), this.up.selector.substring(1), this.down.selector.substring(1), this.hoursElem.selector.substring(1), this.minutesElem.selector.substring(1), this.meridiemElem.selector.substring(1)]; //the clickable areas
this.selectedHour = ((this.defaults.now.getHours() + 11) % 12) + 1; //the default hour
this.selectedMin = ((this.defaults.now.getMinutes() < 10) ? '0' : '') + this.defaults.now.getMinutes(); //the default minute
this.selectedMeridiem = (this.defaults.now.getHours > 12) ? 'PM' : 'AM'; //the defaut meridiem
this.attach(element); //attach events to this element
};
$.extend(Timepicker.prototype = {
showTimepicker: function(element) {
var timepickerPos = this.element.offset();
//set time to default time (now)
this.setText(element);
//if the timepicker's time differs from the input field's time change it
if (this.getText(element) !== this.getTime()) {
var inputTime = this.getText(element).replace(':', '').split(' ');
var newTime = new Date();
newTime.setHours(inputTime[0]);
newTime.setMinutes(inputTime[2]);
this.setTime(newTime);
}
//Positioning
this.timepicker.css({
'z-index': this.element.zIndex() + 1,
position: 'absolute',
left: timepickerPos.left,
top: timepickerPos.top + element.target.offsetHeight + 5
}).show();
//Time up/down events
//Most likely the area with issues
//Needs to know which instance
$(this.up).on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).on('click', $.proxy(this.changeValue, this, '-', element));
},
hideTimepicker: function(element) {
var targetClass = element.target.className.split(' ');
//Check if area is clickable before hiding
if (findOne(targetClass, this.canClick) === false) {
this.timepicker.hide();
}
},
//Create only one timepicker per page
createTimepicker: function() {
if ($('.wicked-picker').length === 0)
$('body').append('<div class="wicked-picker"> <p class="wicked-picker__title">Timepicker</p> <ul class="wicked-picker__controls"> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--hours">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--minutes">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--meridiem">AM</span><span class="wicked-picker__controls__control-down"></span> </li> </ul> </div>');
},
//Attach the show and hide picker events
attach: function(element) {
$(element).on('focus', $.proxy(this.showTimepicker, this));
$('body').on('click', $.proxy(this.hideTimepicker, this));
},
//set the timepicker's time
setTime: function(time) {
this.setHours(time.getHours());
this.setMinutes(time.getMinutes());
this.setMeridiem();
},
//get the timepicker's time in the form H : MM : AM || PM
getTime: function() {
return [this.getHours + ' : ' + this.getMinutes() + ' ' + this.getMeridiem()];
},
//set the timepicker's and input field's hours
setHours: function(hours) {
var hour = new Date();
hour.setHours(hours);
var hoursText = ((hour.getHours() + 11) % 12) + 1;
this.hoursElem.text(hoursText);
this.selectedHour = hoursText;
},
//set the timepicker's hours
getHours: function() {
var hours = new Date();
hours.setHours(this.hoursElem.text());
return hours.getHours();
},
//set the timepicker's and input field's minutes
setMinutes: function(minutes) {
var minute = new Date();
minute.setMinutes(minutes);
var minutesText = minute.getMinutes();
var min = ((minutesText < 10) ? '0' : '') + minutesText;
this.minutesElem.text(min);
this.selectedMin = min;
},
//set the timepicker's minutes
getMinutes: function() {
var minutes = new Date();
minutes.setMinutes(this.minutesElem.text());
var minutesText = minutes.getMinutes();
return ((minutesText < 10) ? '0' : '') + minutesText;
},
//set the timepicker's and input field's meridiem
setMeridiem: function() {
var meridiem = this.getMeridiem();
var newMeridiem = (meridiem === 'PM') ? 'AM' : 'PM';
this.meridiemElem.text(newMeridiem);
this.selectedMeridiem = newMeridiem;
},
//set the timepicker's meridiem
getMeridiem: function() {
return this.meridiemElem.text();
},
//change the input field's time based on the arrow selected for each time unit
//input is the input field to be changed
//element is the up or down arrow clicked
//operator is the '+' or '-' sign
changeValue: function(operator, input, element) {
var target = (operator === '+') ? element.target.nextSibling : element.target.previousSibling;
var targetClass = $(target).attr('class');
if (targetClass.endsWith('hours')) {
this.setHours(eval(this.getHours() + operator + 1));
} else if (targetClass.endsWith('minutes')) {
this.setMinutes(eval(this.getMinutes() + operator + 1));
} else {
this.setMeridiem();
}
console.log('changed ' + $(input.target).attr('name'));
this.setText(input);
},
//Set the input field's time
setText: function(input) {
console.log('set ' + $(input.target).attr('name') + ' to ' + this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem);
$(input.target).val(this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem);
},
//Get the input field's time
getText: function(input) {
return $(input.target).val();
}
});
//Create timepickers
$.fn.timepicker = function(options) {
return this.each(function() {
new Timepicker(this, options);
});
};
}(jQuery));
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="text" name="event-start-time" id="event-start-time" class="form-input timepicker grid-5" />
<input type="text" name="event-end-time" id="event-end-time" class="form-input timepicker grid-5" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$('.timepicker').timepicker({});
</script>
</body>
</html>
I was able to solve the problem by removing the previous up and down event click event handlers and then reapplying the new click event handlers. This was accomplished by changing
$(this.up).on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).on('click', $.proxy(this.changeValue, this, '-', element));
to
$(this.up).off('click').on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).off('click').on('click', $.proxy(this.changeValue, this, '-', element));
Thanks for all the advice!

Javascript Performance Testing, identical tests at different speeds

I've got some code for testing performance of jQuery selectors. I run the tests 3 times with 100000 repetitions in a browser console. The first test is always the slowest, then, the following two are nearly equal in speed. Has anybody an idea why?
Here's the fiddle: http://jsfiddle.net/05xq70na/, the execution times are logged in browser console.
var repetitions = 100000;
var html = '<ul><li id="parent"><div id="child" class="child" value="test"></div></li></ul>';
var time = [];
var finished = false;
var tests = {
"SelectorById": function(){
var element;
element = $("#child");
},
"SelectorByClass": function(){
var element;
element = $(".child");
},
"SelectorByTag": function(){
var element;
element = $("li");
}
}
function showResults(loopCounter) {
if(!finished) {
finished = true;
console.log("\nResults (" + loopCounter + " repetitions):");
for(executionTime in time) {
console.log(executionTime + ": " + (time[executionTime] / loopCounter) + " ms");
}
}
}
function perform(test, string) {
var startTime,
endTime,
nextTest = tests[test];
if(time[test + string] === undefined) {
time[test + string] = 0;
}
startTime = performance.now();
nextTest();
endTime = performance.now();
time[test + string] += (endTime - startTime);
}
function benchmark(tests) {
for(var i=0, loopCounter=1; i<repetitions; i++) {
// console.log('repetition ' + loopCounter);
for(test in tests) {
// console.log('\texecute ' + test);
perform(test, "1");
perform(test, "2");
perform(test, "3");
}
loopCounter++;
if(loopCounter>repetitions) {
showResults(--loopCounter);
};
}
}
document.getElementsByTagName('body')[0].innerHTML = html;
benchmark(tests);
I have tested the simple jQuery selector in JSLitmus (JSFiddle).
JSLitmus.test('jQuery ID selector 1', function(counter) {
while(counter--) {
$('#test');
}
});
...
The result is like:
The performance of ID selectors vary every time, but there is no fixed pattern.
I update your code to run every tests for 7 times: JSFiddle. Then the first run also spends most time, however the rest spend some time comparable. Since JSLitmus performs something called calibration, I am afraid your testing code is not so fare, especially when there are so many function calls.

Javascript clock to change hour, minute, second with image

i'm confuse my clock not work
i have made pictures for hour, minute, second and am/pm
http://i.stack.imgur.com/4zg00.png
i have tried this scripts
<script language="JavaScript1.1"> <!--
/* Live image clock III Written by Alon Gibli (http://www.angelfire.com/biz6/deathrowtech) Visit http://wsabstract.com for this script and more
*/
// Setting variables dig = new Image() dig[0] = '0.gif' dig[1] = '1.gif' dig[2] = '2.gif' dig[3] = '3.gif' dig[4] = '4.gif' dig[5] = '5.gif' dig[6] = '6.gif' dig[7] = '7.gif' dig[8] = '8.gif' dig[9] = '9.gif'
//writing images document.write('<table border=1 cellspacing=0 bgcolor="silver">') document.write('<tr><td><img src="0.gif" name="hrs1"></img>') document.write('<img src="0.gif" name="hrs2"></img>') document.write('<td><img src="col.gif"></img>') document.write('<td><img src="0.gif" name="mins1"></img>') document.write('<img src="0.gif" name="mins2"></img>') document.write('<td><img src="col.gif"></img>') document.write('<td><img src="0.gif" name="secs1"></img>') document.write('<img src="0.gif" name="secs2"></img>') document.write('<td><img src="am.gif" name="ampm"></img></table>')
//starting clock function function showTime() { now = new Date ampmtime = now.getHours() - 12 thisHrs = '' + now.getHours() + '' thisMin = '' + now.getMinutes() + '' thisSec = '' + now.getSeconds() + ''
if (thisHrs > 9) { if (thisHrs >= 12) {
document.ampm.src = 'pm.gif'
if (thisHrs==12)
newHrs=''+12+''
if (thisHrs > 12) {
newHrs = '' + ampmtime + ''
}
if (newHrs <= 9) {
document.hrs1.src = dig[0]
document.hrs2.src = dig[newHrs.charAt(0)]
}
if (newHrs > 9) {
document.hrs1.src = dig[newHrs.charAt(0)]
document.hrs2.src = dig[newHrs.charAt(1)]
} } else {
document.ampm.src = 'am.gif'
document.hrs1.src = dig[thisHrs.charAt(0)]
document.hrs2.src = dig[thisHrs.charAt(1)] } } if (thisHrs <= 9) { document.ampm.src = 'am.gif' if (thisHrs == 0) {
document.hrs1.src = dig[1]
document.hrs2.src = dig[2] } else {
document.hrs1.src = dig[0]
document.hrs2.src = dig[thisHrs.charAt(0)] } } if (thisMin > 9) { document.mins1.src = dig[thisMin.charAt(0)] document.mins2.src = dig[thisMin.charAt(1)] } if (thisMin <= 9) { document.mins1.src = dig[0] document.mins2.src = dig[thisMin.charAt(0)] } if (thisSec > 9) { document.secs1.src = dig[thisSec.charAt(0)] document.secs2.src = dig[thisSec.charAt(1)] } if (thisSec <= 9) { document.secs1.src = dig[0] document.secs2.src = dig[thisSec.charAt(0)] } setTimeout("showTime()",1000) }
window.onload=showTime // --> </script>
how to change every hour,minute, second and am/pm with images i have made?
i have tried many ways but failed :(
thank you :)
Ordinarily I'd approach this with a sprite sheet in mind as you have 135 unique images and traditionally that would mean 135 requests to a web server which would result in poor performance. Technically your images are simple enough that the effect could be generated using CSS or SVG quite easily too...
However because that feels like cheating the question and because you haven't specified a particular size for your clock; I've stuck with a solution using individual images - though I have taken measures to optimise your images for this example which I will explain first.
The images in your zip file are 400x298 pixels totalling 4MB (this is arguably not web-friendly) and if you can't resize them (IE. you actually want a big clock) then you should consider compressing the images. For the sake of this example and other people's bandwidth I've reduced the images to 50x37 and compressed them using pngquant (highly recommend checking this out).
I've also base64-encoded the images and dumped them in a javascript object that looks like so:
Clock.prototype.imgs = {
hrs:[...], // array(13)
min:[...], // array(60)
sec:[...], // array(60)
gmt:[...] // array(2)
}
This means that all the images can be loaded into the page in a single request and understood by the browser by means of a data URI.
All in all file-size cut down to ~150KB :)
And so to the script: (I've tried to keep it as straight-forward as possible)
First you need to leave an element in the page to hook on to, eg:
<div id="myClock"></div>
and then in your script tags:
new Clock;
function Clock(){
// setup our DOM elements
var clock = document.getElementById('myClock');
this.elHrs = document.createElement('img');
this.elMin = document.createElement('img');
this.elSec = document.createElement('img');
this.elGmt = document.createElement('img');
clock.appendChild(this.elHrs);
clock.appendChild(this.elMin);
clock.appendChild(this.elSec);
clock.appendChild(this.elGmt);
// set a timer to update every second
this.tick = setInterval((function(scope){
return function(){ scope.draw(); }
})(this), 1000);
this.draw = function(){
var date = new Date,
gmt = Math.floor(date.getHours()/12),
hrs = date.getHours(),
min = date.getMinutes(),
sec = date.getSeconds(),
uri = 'data:image/png;base64,';
if(hrs!=12) hrs %= 12;
this.elHrs.src = uri + this.imgs.hrs[hrs];
this.elMin.src = uri + this.imgs.min[min];
this.elSec.src = uri + this.imgs.sec[sec];
this.elGmt.src = uri + this.imgs.gmt[gmt];
}
}
jsFiddle
setInterval(() => {
d = new Date();
htime = d.getHours();
mtime = d.getMinutes();
stime = d.getSeconds();
hrotation = 30 * htime + mtime / 2;
mrotation = 6 * mtime;
srotation = 6 * stime;
hour.style.transform = `rotate(${hrotation}deg)`;
minute.style.transform = `rotate(${mrotation}deg)`;
second.style.transform = `rotate(${srotation}deg)`;
}, 1000);

How to Apply multiple styles on days

I have to mark three kind of days with different styles: Out_of_window, Free or Unavailable. The unavailable has to be disabled.
I made a function based on this question. And I had to remove the default datepicker class (ui-state-default) otherwise I couldn't change the bg-image.
Everything work as desired, until I change month. When I get back to original month, the day gets back its orignal class (ui-state-default) and I have no more my customized styles according the kind of day.
So, I have the following codes:
var pick_up_out_of_window_dayDates = new Array("2012-12-11","2012-12-12");
var pick_up_free_dayDates = new Array("2012-12-21","2012-12-22");
(as global ones)
function applyDayStyles(date){
var enabled = true;
var cssClass = "";
console.log(date);
var day = date.getDate();
var month = date.getMonth() + 1; //0 - 11
var year = date.getFullYear();
var compare = year + "-" + month + "-" + day;
var pick_up_out_of_window_day = pick_up_out_of_window_dayDates.indexOf(compare) + " " + compare
var pick_up_free_day = pick_up_free_dayDates.indexOf(compare) + " " + compare
if (pick_up_out_of_window_dayDates.indexOf(compare) >= 0){
cssClass = "pick_up_out_of_window_dayCalendar";
console.log(1);
return new Array(enabled, cssClass, pick_up_out_of_window_day);
}
else
if (pick_up_free_dayDates.indexOf(compare) >= 0){
cssClass = "pick_up_free_dayCalendar";
console.log(2);
return new Array(enabled, cssClass, pick_up_free_day);
}
else
return new Array(false, cssClass, date);
}
$(document).ready(function() {
$(".datepicker").datepicker({
minDate: 0,
beforeShowDay: applyDayStyles
})
//{edited}
// this is un necesssary !
// $('.pick_up_free_dayCalendar').children().removeClass('ui-state-default').addClass('pick_up_free_dayCalendarIN'); // I Had to add this line to remove the defaukt bg style.
})
Any thoughts?
Just have to override the default class :
.datepicker .pick_up_out_of_window_dayCalendar .ui-state-default {background: red;}
.datepicker .pick_up_free_dayCalendar .ui-state-default {background: blue;}
Thanx to #adeneo (see questions' coments)
http://jsfiddle.net/Cwg3P/2/

Categories

Resources