clearInterval and eventListener - event-handling

My problem is, I'm not being able to use the 'setInterval' attached to a button and use another one to stop it with 'clearInterval'.
My thought process:
Since clearInterval() would need a target, I stored the setInterval() inside a variable. However, I noticed that setInterval() starts running without being triggered by the eventListener attached to it. I was expecting this behaviour of firing on its own only if I had put setInterval() out in the open without being stored on a variable and on the global scope.
So then I tried to encapsulate it inside a function, only this time the clearInterval() seemed to 'lose' the target.
I had a look on some situtations and couldn't find an explanation that would satisfy my case. Right now it looks like I can't have both ways (a btn to 'fire' the timer and a btn to shut it off).
I don't know if this is a matter of scope,event handling or targeting. Had a look on HTMLStandard but couldn't make much use of it.
Thank you
<script>
let repeater = function () {
setInterval(() => {
console.log('loading');
}, 1000);
};
const startButton = document.querySelector('#firstB');
const stopButton = document.querySelector('#secondB');
startButton.addEventListener('click', repeater);
stopButton.addEventListener('click', () => {
clearInterval(repeater);
console.log('finished');
});
</script>

const startButton = document.querySelector("#firstB");
const stopButton = document.querySelector("#secondB");
let repeater;
startButton.addEventListener("click", function () {
repeater = setInterval(() => {
console.log("loading");
}, 1000);
});
stopButton.addEventListener("click", () => {
clearInterval(repeater);
console.log("finished");
});
This should work.

Related

VideoJS 5 plugin add button

I looked everywhere on the internet but I couldn't find any clear documentation or some examples to create my verySimplePlugin for videoJS 5 (Since it uses ES6).
I just want to add a button next to the big play button... Can someone help me?
Thanks...
PS: I'm using it in angularJS but I guess this can not a problem
This is how you can add download button to the end of control bar without any plugins or other complicated code:
var vjsButtonComponent = videojs.getComponent('Button');
videojs.registerComponent('DownloadButton', videojs.extend(vjsButtonComponent, {
constructor: function () {
vjsButtonComponent.apply(this, arguments);
},
handleClick: function () {
document.location = '/path/to/your/video.mp4'; //< there are many variants here so it is up to you how to get video url
},
buildCSSClass: function () {
return 'vjs-control vjs-download-button';
},
createControlTextEl: function (button) {
return $(button).html($('<span class="glyphicon glyphicon-download-alt"></span>').attr('title', 'Download'));
}
}));
videojs(
'player-id',
{fluid: true},
function () {
this.getChild('controlBar').addChild('DownloadButton', {});
}
);
I used 'glyphicon glyphicon-download-alt' icon and a title for it so it fits to the player control bar styling.
How it works:
We registering a new component called 'DownloadButton' that extends built-in 'Button' component of video.js lib
In constructor we're calling constructor of the 'Button' component (it is quite complicated for me to understand it 100% but it is similar as calling parent::__construct() in php)
buildCSSClass - set button classes ('vjs-control' is must have!)
createControlTextEl - adds content to the button (in this case - an icon and title for it)
handleClick - does something when user presses this button
After player was initialized we're adding 'DownloadButton' to 'controlBar'
Note: there also should be a way to place your button anywhere within 'controlBar' but I haven't figured out how because download button is ok in the end of the control bar
This is how I created a simple button plugin for videojs 5:
(function() {
var vsComponent = videojs.getComponent('Button');
// Create the button
videojs.SampleButton = videojs.extend(vsComponent, {
constructor: function() {
vsComponent.call(this, videojs, null);
}
});
// Set the text for the button
videojs.SampleButton.prototype.buttonText = 'Mute Icon';
// These are the defaults for this class.
videojs.SampleButton.prototype.options_ = {};
// videojs.Button uses this function to build the class name.
videojs.SampleButton.prototype.buildCSSClass = function() {
// Add our className to the returned className
return 'vjs-mute-button ' + vsComponent.prototype.buildCSSClass.call(this);
};
// videojs.Button already sets up the onclick event handler, we just need to overwrite the function
videojs.SampleButton.prototype.handleClick = function( e ) {
// Add specific click actions here.
console.log('clicked');
};
videojs.SampleButton.prototype.createEl = function(type, properties, attributes) {
return videojs.createEl('button', {}, {class: 'vjs-mute-btn'});
};
var pluginFn = function(options) {
var SampleButton = new videojs.SampleButton(this, options);
this.addChild(SampleButton);
return SampleButton;
};
videojs.plugin('sampleButton', pluginFn);
})();
You can use it this way:
var properties = { "plugins": { "muteBtn": {} } }
var player = videojs('really-cool-video', properties , function() { //do something cool here });
Or this way:
player.sampleButton()

Protractor how to wait for options

I have code like this:
element(by.model("roleSelection.role")).element(by.cssContainingText('option', newRole)).click();//.then(function() {console.log('role click')})//;
where the options is loaded via a call to the server.
I can wait for the first element by doing this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
return present;
});}, 8000);
and it seems to work. But how can I wait until the "sub-element" is clickable.
I have tried this
browser.wait(function() {
return browser.isElementPresent(by.model("roleSelection.role")).then(function(present){
if (present) {
var elm = element(by.model("roleSelection.role"));
return elm.isElementPresent(by.cssContainingText('option', newRole)).then(function(subpresent) {
return subpresent;
});
}
}); }, 8000);
Have you tried clickable? Something along these lines
var EC = protractor.ExpectedConditions;
var select = element(by.model("roleSelection.role"))
var isClickable = EC.elementToBeClickable(select);
browser.wait(isClickable,5000); //now options should have been loaded by now
Well, try to this: https://angular.github.io/protractor/#/api?view=ExpectedConditions.prototype.elementToBeClickable
But, Please keep in mind, Protractor is suitable for angular webpages and interactions, and animations. For example ng-animate. So, it is not sure to working for example jquery, or other animates.
In this way:
onPrepare: function () {
// disable animations when testing to speed things up
var disableNgAnimate = function () {
angular.module('disableNgAnimate', []).run(function ($animate) {
$animate.enabled(false);
});
};
browser.addMockModule('disableNgAnimate', disableNgAnimate);
}
Or you can switch in script way in browser.executeScript().
Please see this link. It works only jquery animations.
If you not have animate problems. Use setTimeout() JS function.

Join two observables in RX.js

I'm trying to create new observable based on two others. I have:
var mouseClickObservable = Rx.Observable.fromEvent(this.canvas, "click");
var mouseMoveObservable = Rx.Observable.fromEvent(this.canvas, "mousemove");
function findObject(x, y) {/* logic for finding object under cursor here. */}
var objectUnderCursor = this.mouseMoveObservable.select(function (ev) {
return findObject(ev.clientX, clientY);
});
I want to create objectClicked observable, that should produce values when user clicks on an object. I could just call findObject again, like this:
var objectClicked = this.mouseClickObservable.select(function (ev) {
return findObject(ev.clientX, clientY);
});
but it's very time-consuming function.
Another way, which I currently use, is to store last hovered object in a variable, but I assume, there should be pure functional way of doing this. I tryed to use Observable.join like this:
var objectClicked = this.objectUnderCursor.join(
mouseClickObservable,
function (obj) { return this.objectUnderCursor },
function (ev) { return Rx.Observable.empty() },
function (obj, ev) { return obj })
but it produces multiple values for one click
I don't see any code where you actually subscribe to any of these observables you have defined, so it is hard to provide a good answer. Do you actually need to call findObject on every mouse move? Are you needing to provide some sort of hover effect as the mouse moves? Or do you just need to know the object that was clicked, in which case you only need to call findObject once when clicked?
Assuming you only need to know what object was clicked, you don't even worry about mouse moves and just do something like:
var objectClicked = mouseClickObservable
.select(function (ev) { return findObject(ev.clientX, ev.clientY); });
objectClicked.subscribe(function(o) { ... });
If you indeed need to know what object the mouse is hovering over, but want to avoid calling your expensive hit test also on a click, then indeed you need to store the intermediate value (which you are needing to store anyway to do your hovering effects). You can use a BehaviorSubject for this purpose:
this.objectUnderCursor = new Rx.BehaviorSubject();
mouseMoveObservable
.select(function (ev) { return findObject(ev.clientX, ev.clientY); })
.subscribe(this.objectUnderCursor);
this.objectUnderCursor.subscribe(function (o) { do your hover effects here });
mouseClickObservable
.selectMany(function () { return this.objectUnderCursor; })
.subscribe(function (o) { do your click effect });

Ignore multiple button taps after first one on iPhone webapp using jQuery Mobile?

Assume button A in an HTML5 webapp built with jQuery Mobile.
If someone taps button A, we call foo(). Foo() should get called once even if the user double taps button A.
We tried using event.preventDefault(), but that didn't stop the second tap from invoking foo(). event.stopImmediatePropagation() might work, but it also stops other methods further up the stack and may not lead to clean code maintenance.
Other suggestions? Maintaining a tracking variable seems like an awfully ugly solution and is undesirable.
You can set a flag and check if it's OK to run the foo() function or unbind the event for the time you don't want the user to be able to use it and then re-bind the event handler after a delay (just a couple options).
Here's what I would do. I would use a timeout to exclude the subsequent events:
$(document).delegate('#my-page-id', 'pageinit', function () {
//setup a flag to determine if it's OK to run the event handler
var okFlag = true;
//bind event handler to the element in question for the `click` event
$('#my-button-id').bind('click', function () {
//check to see if the flag is set to `true`, do nothing if it's not
if (okFlag) {
//set the flag to `false` so the event handler will be disabled until the timeout resolves
okFlag = false;
//set a timeout to set the flag back to `true` which enables the event handler once again
//you can change the delay for the timeout to whatever you may need, note that units are in milliseconds
setTimeout(function () {
okFlag = true;
}, 300);
//and now, finally, run your original event handler
foo();
}
});
});
I've created a sample here http://jsfiddle.net/kiliman/kH924/
If you're using <a data-role="button"> type buttons, there is no 'disabled' status, but you can add the appropriate class to give it the disabled look.
In your event handler, check to see if the button has the ui-disabled class, and if so, you can return right away. If it doesn't, add the ui-disabled class, then call foo()
If you want to re-enable the button, simply remove the class.
$(function() {
$('#page').bind('pageinit', function(e, data) {
// initialize page
$('#dofoo').click(function() {
var $btn = $(this),
isDisabled = $btn.hasClass('ui-disabled');
if (isDisabled) {
e.preventDefault();
return;
}
$btn.addClass('ui-disabled');
foo();
});
});
function foo() {
alert('I did foo');
}
});

Click not firing first time after rebind with live() method

I understand that this is a probably a noob-ish question, but I've had no luck with the other threads I've found on the same topic.
I've devised a workaround to hack a views exposed filter to hide and show products with a stock count of "0". The exposed filter for the stock count (input#edit-stock) is hidden with CSS and inside a custom block is a link to manipulate the form and trigger the query (with ajax). This is working great, but with one exception - after resetting the form with the views-provided "reset" button, toggle() will not rebind properly to the link, and click won't fire the first time. Works fine on the 2nd click. I'm sure that the solution is very simple, but I'm at a loss..
How to rebind toggle() effectively?
Sorry, I'm unable to provide a live example. Many thanks for any input.
CUSTOM BLOCK:
<a id="toggle" href="#">exclude</a>
JQUERY:
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
$('a#toggle').unbind('toggle').toggle(include, exclude).html('exclude');
});
});
if i get the problem right you need to reset the toggle. Why instead of unbind toggle and rebinding it you just don't simulate a click if the link is == to include?
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
//if the link is include, click it so that it resets to exclude, else do nothing
if ($('a#toggle').html() == 'include'){
$('a#toggle').click();
}
});
});
fiddle here: http://jsfiddle.net/PSLBb/
(Hope this is what you were looking for)