Differentiate between click and hold & click - angularjs

I have an html element that can get drag and dropped & also it can be clicked to do another action, I want to differentiate between these two actions so I thought I'd use ng-mousedown & ng-mouseup and count the time difference between them and based on that I'd be able to tell if that was a click or a click and hold (aka drag & drop).
So the element would look something like this:
<a ng-mousedown="mouseDownStudent()" ng-mouseup="mouseUpStudent()"> {{student.name}} </a>
And what I want to do is something along the lines of:
var isMouseDown = false;
var clickAndHoldTime = 0;
$scope.mouseDownStudent = function(){
isMouseDown = true;
while(isMouseDown){
clickAndHoldTime++;
}
}
$scope.mouseUpStudent = function(){
isMouseDown = false;
// If clickAndHoldTime > 100 ... it's a click
}
Of course this won't work and the while loop won't stop, I thought about using $interval but not sure how it would fit in that scenario.

You are very close in your implementation. What you want to do is capture the current time on mousedown and then on mouseup, find the elapsed time. You can do this by capturing the current Date and then finding the difference once you mouseup.
let startTime = 0;
$scope.mouseDownStudent = function() {
// Capture current time
startTime = new Date();
}
$scope.mouseUpStudent = function() {
// Get current time
let currentTime = new Date();
// Get elapsed time in ms
let elapsedTime = currentTime - startTime;
if (elapsedTime > 100) { ... }
}

Related

Cycle array of functions with TimerEvent AS3

i'm working on a movieclip that features a small array of functions that i'd like to execute at certain intervals.
Here is the code:
var Tmr:Timer = new Timer(1000, 3);
var funcArray:Array = [move1, move2, move3];
var i:Number = 0;
funcArray[i]();
function kick(){
if (i < 2) {i++; funcArray[i](); trace("GO NEXT");}
else {i = 0; funcArray[i](); trace("FROM-START");}
}
function timerX():void{
Tmr.start();
Tmr.addEventListener(TimerEvent.TIMER_COMPLETE, outro);
trace("TIMERSTART");
}
function outro(e:TimerEvent):void{
e.currentTarget.removeEventListener(TimerEvent.TIMER_COMPLETE, outro);
trace("TIMEREND");
kick();
}
function move1(){
item1.x = 100;
item1.y = 100;
trace("MOVE1");
timerX()
}
function move2(){
item1.x = 300;
item1.y = 400
trace("MOVE2");
timerX();
}
function move3(){
item1.x = 800;
item1.y = 600
trace("MOVE3");
timerX();
}
As you see i've filled it with trace commands because... The dark magic happens after move1() has been played: apparently it starts looping the functions EVERY SECOND instead of 5, like it is depending on an Enter_Frame event.
The trace sequence in output is: MOVE1, TIMERSTART, TIMEREND, MOVE2, TIMERSTART, GO NEXT, TIMEREND, MOVE3, TIMERSTART, GO NEXT, TIMEREND, MOVE1, TIMERSTART, FROM-START...
instead of: MOVE1, TIMERSTART, TIMEREND, GO NEXT, MOVE2, TIMERSTART, TIMEREND, GO NEXT etc.
I also tried to move the kick() function up in the outro one
function outro(e:TimerEvent):void{
kick();
e.currentTarget.removeEventListener(TimerEvent.TIMER_COMPLETE, outro);
trace("TIMEREND");
}
And the effect is that it doesn't go past move2().
Where do you think is the error? What was wrong in the logic i used to write down this?
Thanks for your kind help!
Per the timer firing every second, you've defined the Timer to dispatch timer events every 1-second; although, repeating 3 times before firing TIMER_COMPLETE.
var Tmr:Timer = new Timer(1000, 3);
If you want the timer to fire every 5-seconds, you could just:
var Tmr:Timer = new Timer(5000);
Next up, you never stop or reset the timer. You can stop() and start() the timer; or, if you're depending on a specific number of times for the timer to repeat, then reset() the timer.
Since it seems like you simply want an event to fire every 5-seconds infinitely, there's really no need to start / stop / reset / add new listeners - just start the timer and listen for timer events:
var timer:Timer = new Timer(5000);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
function timerHandler(event:TimerEvent):void {
// timer fired
}
Putting this all together, if you just want to go from: move1, move2, move3 infinitely repeating:
import flash.utils.Timer;
import flash.events.TimerEvent;
var timer:Timer = new Timer(5000);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
var actions:Array = [move1, move2, move3];
var i:uint = 0;
function timerHandler(event:TimerEvent):void {
actions[i]();
if(++i >= actions.length)
i = 0;
}
function move1():void {
trace("move1");
}
function move2():void {
trace("move2");
}
function move3():void {
trace("move3");
}
function exit():void {
timer.reset();
timer.removeEventListener(TimerEvent.TIMER, timerHandler);
timer = null;
}

Paginate By Week - AngularJS

I am trying to paginate a list of events (using ng-repeat) by week in AngularJS. I have a custom filter working that only displays the events within the current week, but I am trying to add functionality to look at future and past weeks.
Here is the filter I am using for the event lists -
$scope.week = function(item) {
var weekStart = moment().startOf('week');
var weekEnd = moment().endOf('week');
var eventTime = moment(item.jsdatetime);
if (eventTime >= weekStart && eventTime <= weekEnd) return true;
return false;
};
I have tried using ng-click to call a function that uses moment.js to .add(7, 'days'); to the weekStart and weekEnd variables but can't seem to get it to work.
Any help would be appreciated.
Here's a CodePen with the basic functionality going on - http://codepen.io/drewbietron/pen/xbKNdK
The moment() always return the current date/time.
You need to store a reference to it to a variable, and then use that for manipulations.
(and since you have other variables depending on it, i would create a function that sets all those variables at once)
So in the controller i changed the top part to
var currentDate,
weekStart,
weekEnd,
shortWeekFormat = 'MMMM Do';
function setCurrentDate(aMoment){
currentDate = aMoment,
weekStart = currentDate.clone().startOf('week'),
weekEnd = currentDate.clone().endOf('week')
}
// initialize with current date
setCurrentDate(moment());
// use these methods for displaying
$scope.currentWeek = function(){ return currentDate.format(shortWeekFormat); };
$scope.currentWeekStart = function(){ return weekStart.format(shortWeekFormat); };
$scope.currentWeekEnd = function(){ return weekEnd.format(shortWeekFormat); };
Then create two methods for going to next/previous week
$scope.nextWeek = function(){
setCurrentDate(currentDate.add(7,'days'));
};
$scope.prevWeek = function(){
setCurrentDate(currentDate.subtract(7,'days'));
};
(moment.js implements valueOf so you do direct comparisons)
And finally change your week filter to actually compare the dates (using .isSame(), .isBefore() and .isAfter()) instead of the moment objects (which was wrong as you cannot do direct comparisons on custom objects)
$scope.week = function(item) {
var eventTime = moment(item.jsdatetime);
if ((eventTime.isSame(weekStart) || eventTime.isAfter(weekStart))&&
(eventTime.isSame(weekEnd) || eventTime.isBefore(weekEnd))) return true;
return false;
};
$scope.week = function(item) {
var eventTime = moment(item.jsdatetime);
return (eventTime >= weekStart && eventTime <= weekEnd);
};
(you also, most likely, want the ng-repeat on the li elements and not the ul)
Demo at http://codepen.io/gpetrioli/pen/QwLRQB
The weekStart and weekEnd variables don't exist outside of the scope of week(item). If you're using ngClick to call a function that tries to modify those variables, it'll just return undefined. I don't know how your layout is but I would pull those two variables outside of the week function and make them $scope variables.
Additionally, I would have ngClick call a function that would change the two $scope variables (either adds 7 or subtracts 7 depending on which direction you want to go in).
$scope.weekStart = moment().startOf('week');
$scope.weekEnd = moment().endOf('week');
$scope.week = function(item) {
var eventTime = moment(item.jsdatetime);
if (eventTime >= $scope.weekStart && eventTime <= $scope.weekEnd) return true;
return false;
};
$scope.update= function(direction) {
$scope.weekStart.add(direction, 'days');
$scope.weekEnd.add(direction, 'days');
}
And create two buttons in your view:
Previous week
Next week

Angularjs - Time difference between my data time and CURRENT TIME

I am trying to display the time difference between my {{trade.timer}} and the current time but coudn't succeed after many tries.
I am looking to make the $scope.gains[i].timer = vtime - "CURRENTTIME"
Here is my code:
$scope.updatetimerValue = function (timerValue){
$.each(timerValue, function(k, v) {
for (var i =0; i < $scope.gains.length ; i ++) {
if($scope.gains[i].orderid == v.orderid){
$scope.gains[i].timer = v.time;
}
}
});
}
<td>{{gain.timer | date: 'HH:mm'}}</td>
Any idea?
Note: v.time time format is yyyy-MM-dd HH:mm:ss
You can get date difference between two days with basic javascript.
var date = new Date('10/27/2014');
var currentDate = new Date();
var milisecondsDiff = date-currentDate;
var secondsDiff = miliseconds/1000;
var minutesDiff = seconds/60;
var hoursDiff = minutes/60;
var daysDiff = hours/24;
Also I suggest don't mix up AngularJS and JQuery.
And instead $.each use the angular.forEach
angular.forEach(values, function(value, key) {
///
});
or even better to use simple for loop, because it works faster.

Angularjs freezes in loop suing $timeout to call function multiple times sequential after or less than a second?

I want to be able to call a function repeatedly every second (or faster).
Assuming "startdate" contains the starting date in the text... In my controller:
scope.arrayoftimes=[{time:XXXX},{time:XXXXXX}]
scope.startdate = $('#startingdate'); //start date comes from text in an element
scope.speed = 1000;
scope.index = 0;
scope.timer = $timeout(scope.doSomething(), scope.speed);
scope.doSomething = function() {
var currentTime = scope.startDate.html();
for (var i=scope.index; i < scope.arrayoftimes.length; i++) {
if(currentTime == roundTo(scope.arrayoftimes[i].time)) {
$rootScope.$emit('timeMatch', scope.index);
scope.index++;
break;
}
}
$timeout(scope.doSomething(), scope.speed);
}
The above code frezes my browser on execution. HOWEVER if I stick in an "alert" anywhere after the scope.index++ or inside the if condition, then it works fine (as long as I check "Prevent opening multiple dialog boxes")
scope.arrayoftimes=[{time:XXXX},{time:XXXXXX}]
scope.startdate = "//Insert Starting Date Here"
scope.speed = 1000;
scope.index = 0;
scope.timer = $timeout(scope.doSomething(), scope.speed);
scope.doSomething = function() {
var currentTime = scope.startDate;
for (var i=scope.index; i < scope.arrayoftimes.length; i++) {
if(currentTime == roundTo(scope.arrayoftimes[i].time)) {
$rootScope.$emit('timeMatch', scope.index);
scope.index++;
alert("alert"); // the existence of this alert message and checking prevent from opening more dialog boxes in chrome allows this to execute fine without freezing
break;
}
}
$timeout(scope.doSomething(), scope.speed);
}
What is going on? How can I get around this? Is there a better way to do this?
Your timeout call probably needs to be:
$timeout(function() { scope.doSomething(); }, scope.speed);
or
$timeout(scope.doSomething, scope.speed);
Otherwise you're executing doSomething() immediately which causes an infinite loop.

calling another method inside same view

I making a simple game that uses a two minute JavaScript timer. I can get the javascript timer to work without using backbone. The code is at the bottom for the working timer, and here's a fiddle of it http://jsfiddle.net/mjmitche/hDRjR/19/
However, once I try to the timer code into a few different methods inside a Backbone view, I'm getting an error depending on how a key method, displayTime, code is defined
Steps:
1) I create a new clockView and save it to a variable clock_view
var clock_view = new ClockView({ model: game});
Inside the initializer of clockview, I set up these variables that are used by the timer code
var totalWait = 120;
var secondsRemaining = totalWait;
var hasFocus = true;
var hasJustFailed = false;
The startClock method gets triggered from elsewhere
this.model.bind("gameStartedEvent", this.startClock, this);
startClock uses setInterval to call displayTime method every second. Depending on how displayTime is coded [a) displayTime(), b) this.displayTime(), c) clock_view.displayTime() ], displayTime triggers a different error.
startClock: function(){
console.log("start clock");
setInterval(function(){
this.secondsRemaining -= 1;
console.log("working");
displayTime(); //uncaught reference error: displayTime is not defined
this.displayTime(); //Uncaught TypeError: Object [object Window] has no method 'displayTime'
clock_view.displayTime();// `display time gets called but triggers NAN`
if(secondsRemaining == 0) $('#timer').fadeOut(1000);
}, 1000);
},
If displayTime is called from setInterval as displayTime() it says it's not defined. If I do this.displayTime(), I get a object window has no method. If I call it clock_view.displayTime(), it triggers a NAN error, which I think may be caused because the way the variables are defined in the initializer
displayTime is defined directly below startClock like this
displayTime: function () {
var minutes = Math.floor(secondsRemaining / 60);
var seconds = secondsRemaining - (minutes * 60);
if (seconds < 10) seconds = "0" + seconds;
var time = minutes + ":" + seconds;
$('#timer').html(time);
},
Update
This is a fiddle of the whole ClockView in a Backbone format, although it doesn't work because it's missing other parts of the program (such as the model that triggers the event). I'm including it only to make the question more readable
http://jsfiddle.net/mjmitche/RRXnK/85/
Original working clock code http://jsfiddle.net/mjmitche/hDRjR/19/
var displayTime = function () {
var minutes = Math.floor(secondsRemaining / 60);
var seconds = secondsRemaining - (minutes * 60);
if (seconds < 10) seconds = "0" + seconds;
var time = minutes + ":" + seconds;
$('#timer').html(time);
};
$('#timer').css('marginTop', 0);
setInterval(function(){
secondsRemaining -= 1;
displayTime();
if(secondsRemaining == 0) $('#timer').fadeOut(1000);
}, 1000);
This should work. The main points are, how variables are accessed inside the View.
HTML:
<div id="view">
<div id="timer">
<span class="time">2:00</span>
</div>
<div id="options">
<input type="button" class="action_button" value="New Game" id="new_game">
</div>
</div>
View:
var ClockView = Backbone.View.extend({
el: '#view',
initialize: function () {
/** Define your variables in this View */
this.totalWait = 120;
this.secondsRemaining = this.totalWait;
this.hasFocus = true;
this.hasJustFailed = false;
},
events: {
'click #new_game' : 'startClock' /** The button starts the clock */
},
startClock: function () {
console.log("start clock");
var self = this; /** Save 'this' to a local variable */
setInterval(function () {
self.secondsRemaining -= 1;
self.displayTime();
if (self.secondsRemaining == 0) self.$('#timer').fadeOut(1000);
}, 1000);
},
displayTime: function () {
var minutes = Math.floor(this.secondsRemaining / 60);
var seconds = this.secondsRemaining - (minutes * 60);
if (seconds < 10) seconds = "0" + seconds;
var time = minutes + ":" + seconds;
this.$('#timer').html(time);
},
});
var clock_view = new ClockView();

Resources