I have registered a trigger on window resize. I want to know how I can trigger the event to be called. For example, when hide a div, I want my trigger function to be called.
I found window.resizeTo() can trigger the function, but is there any other solution?
window.dispatchEvent(new Event('resize'));
Where possible, I prefer to call the function rather than dispatch an event. This works well if you have control over the code you want to run, but see below for cases where you don't own the code.
window.onresize = doALoadOfStuff;
function doALoadOfStuff() {
//do a load of stuff
}
In this example, you can call the doALoadOfStuff function without dispatching an event.
In your modern browsers, you can trigger the event using:
window.dispatchEvent(new Event('resize'));
This doesn't work in Internet Explorer, where you'll have to do the longhand:
var resizeEvent = window.document.createEvent('UIEvents');
resizeEvent.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(resizeEvent);
jQuery has the trigger method, which works like this:
$(window).trigger('resize');
And has the caveat:
Although .trigger() simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.
You can also simulate events on a specific element...
function simulateClick(id) {
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
var elem = document.getElementById(id);
return elem.dispatchEvent(event);
}
With jQuery, you can try to call trigger:
$(window).trigger('resize');
Combining pomber's and avetisk's answers to cover all browsers and not causing warnings:
if (typeof(Event) === 'function') {
// modern browsers
window.dispatchEvent(new Event('resize'));
} else {
// for IE and other old browsers
// causes deprecation warning on modern browsers
var evt = window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(evt);
}
A pure JS that also works on IE (from #Manfred comment)
var evt = window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(evt);
Or for angular:
$timeout(function() {
var evt = $window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, $window, 0);
$window.dispatchEvent(evt);
});
I wasn't actually able to get this to work with any of the above solutions. Once I bound the event with jQuery then it worked fine as below:
$(window).bind('resize', function () {
resizeElements();
}).trigger('resize');
just
$(window).resize();
is what I use... unless I misunderstand what you're asking for.
I believe this should work for all browsers:
var event;
if (typeof (Event) === 'function') {
event = new Event('resize');
} else { /*IE*/
event = document.createEvent('Event');
event.initEvent('resize', true, true);
}
window.dispatchEvent(event);
Response with RxJS
Say Like something in Angular
size$: Observable<number> = fromEvent(window, 'resize').pipe(
debounceTime(250),
throttleTime(300),
mergeMap(() => of(document.body.clientHeight)),
distinctUntilChanged(),
startWith(document.body.clientHeight),
);
If manual subscription desired (Or Not Angular)
this.size$.subscribe((g) => {
console.log('clientHeight', g);
})
Since my intial startWith Value might be incorrect (dispatch for correction)
window.dispatchEvent(new Event('resize'));
In say Angular (I could..)
<div class="iframe-container" [style.height.px]="size$ | async" >..
window.resizeBy() will trigger window's onresize event. This works in both Javascript or VBScript.
window.resizeBy(xDelta, yDelta) called like window.resizeBy(-200, -200) to shrink page 200px by 200px.
Related
How can I stop executing other event handlers with pure javascript in case if they are attached to same element in IE8?
I can stop event propagation with Event.stopImmediatePropagation method, but it's not supported by IE8.
// document.getElementById('my-elem').attachEvent('click', firstHandler);
document.getElementById('my-elem').addEventListener('click', firstHandler);
// document.getElementById('my-elem').attachEvent('click', secondHandler);
document.getElementById('my-elem').addEventListener('click', secondHandler);
function firstHandler(ev){
ev.stopPropagation();
alert('1');
}
function secondHandler(ev){
ev.stopPropagation();
alert('2');
}
<div id="my-elem">
How to stop propagation ?
</div>
A very simplified (and probably error prone) polyfill/shim. Capture the original attachEvent/detachEvent methods, and create new ones that will check a flag.
Also it will only prevent events that were attached before the one calling stopImmediatePropagation.
if (!Event.prototype.stopImmediatePropagation) {
(function() {
var attachEvent = Element.prototype.attachEvent,
detachEvent = Element.prototype.detachEvent;
Element.prototype.attachEvent = function(type, callback) {
attachEvent.call(this, "on"+type, function(event) {
if (!event.immediatePropagationStopped) {
callback(event);
}
});
};
Element.prototype.detachEvent = function(type, callback) {
detachEvent.call(this, type, callback);
};
}());
Event.prototype.stopImmediatePropagation = function() {
this.immediatePropagationStopped = true;
};
}
document.getElementById("test").attachEvent("click",function(e){
console.log("hi");
});
document.getElementById("test").attachEvent("click",function(e){
e.stopImmediatePropagation();
console.log("hi2");
});
document.getElementById("test").attachEvent("click",function(e){
console.log("hi3");
});
<div id="test">Click me</div>
While this did work in the IE 8 emulation mode in my IE 11 browser, as I mentioned earlier this is simplified. So it doesn't do much error checking and other needed checks. Find a proper polyfill for add/removeEventListener, preventDefault, stopPropagation, stopImmediatePropagation if you want production usable code.
Modernizr lists ES5 DOM SHIM as having a polyfill for stopImmediatePropagation so it might have polyfills for the others
I need to add gestures in my Meteor app. I don't understand how.
Now I have put my code in Template.XX.rendered and than I call the gesture inside the events scope:
Session.setDefault('deletable', false);
Template.xx.rendered = function(){
$('body').hammer();
};
Template.xx.events({
'swipeleft #hammerDiv': function(e, t) {
Session.set('deletable', true);
},
'swiperight #hammerDiv': function(e, t) {
Session.set('deletable', false);
}
});
Template.territories.helpers({
deleteButton : function(){
return Session.get('deletable');
}
});
this simple code make possible to appear a delete button in the swiped item. All seems to work with chrome and mouse swipe, but when I emulate the app in my android device (meteor run android-device), swipe gesture don't works. If I test in my device with Chrome browser all works done.
Is there any compatibility problem? Is my code wrong? Any suggestions?
Thanks a lot!
I found the definitive solution that works for me:
I changed hammer() properties set to a fast swipe and touch;
I've added preventDefault() in each swipe events;
Set is now set to pass this._id to the helper to check if the swiped
item has the same object id and then, if true, it shows delete
button.
The code:
Session.setDefault('deletable', null);
Template.xx.rendered = function(){
$('body').hammer({
drag_min_distance:1,
swipe_velocity:0.1
});
};
Template.xx.events({
'swipeleft #hammerDiv': function(e, t) {
e.preventDefault();
Session.set('deletable', null);
},
'swiperight #hammerDiv': function(e, t) {
e.preventDefault();
Session.set('deletable', this._id);
}
});
Template.xx.helpers({
deleteButton : function(){
var thisItem = Session.get('deletable');
if (thisItem == this._id){
return true
}else{
return false;
}
}
});
Alternatively, instead of apply preventDefault() within events, it's possible to change the hammer() target and add a new property like this:
$('#hammerDiv').hammer({
drag_min_distance:1,
swipe_velocity:0.1
prevent_default:true
});
I use the following iScroll 5 code (generally, not so important: just a common scrolling page-by-page):
var myScroll = new IScroll('.scroller', {
mouseWheel: true,
scrollbars: true,
keyBindings: {
// doesn't matter
},
preventDefault: false,
fadeScrollbars: true,
snap: 'section', // <-- that's the key
wheelAction: 'scroll',
});
myScroll.on('beforeScrollStart', function (e) {
myScroll.preventDisabling = true;
});
myScroll.on('scrollMove', function (e) {
});
myScroll.on('scrollStart', function (e) {
// !!! I need the detection somewhere here !!!
if (!myScroll.preventDisabling) {
myScroll.disable();
disabledWasCalledInMeanwhile = true;
}
myScroll.preventDisabling = false;
});
var disabledWasCalledInMeanwhile = false;
// that's just to prevent jumping to another page before scrolling is finished
myScroll.on('scrollEnd', function (e) {
disabledWasCalledInMeanwhile = false;
window.setTimeout(function () {
if (!disabledWasCalledInMeanwhile)
myScroll.enable();
}, 250);
$('.labels>*').toggleClass('active', false)
.eq(this.currentPage.pageY).toggleClass('active', true);
});
myScroll.on('scrollCancel', function (e) {
myScroll.enable();
});
So, is there any chance to detect in beforeScrollStart or scrollStart the page I am going to scroll to? That's important to know for triggering that page items animation. Thanks!
I've used iScroll for a number of years (it is a excellent library), and I don't know of a built-in method of doing it. All the scroll events (except scrollEnd) before the iScroll snap is determined. However, with a slight modification of the library, I believe it is possible.
First, go into iScroll.js source and find the _nearestSnap method. At the bottom of the method, you will find the object you seek returned. Before the return, grab that data and pass it to a custom event. Unfortunately, iScroll's event system doesn't permit you to pass custom variables to events, so you'll have to do a work-around. In addition, you'll need to track the "flick" event because it won't trigger the _nearestSnap method.
iScroll modification in _nearestSnap method
this.customSnap({
x: x,
y: y,
pageX: i,
pageY: m
});
Update to class instance. Note the addition of "customSnap" method and the flick event.
myScroll = new IScroll('#wrapper', {snap: "p"});
myScroll.customSnap = function(data) {
console.log(data);
};
myScroll.on('flick', function() {
console.log(data.currentPage);
});
That should do it. Not necessarily the cleanest update, but in my testing, it does work.
http://jsfiddle.net/9pa4th4y/
We have multiple animations against the same object. We need to take different actions when each of these animations end.
Right now, we bind to the webkitAnimationEnd event, and use a gnarly if/then statement to handle each animation differently.
Is there a way to essentially create custom webkitAnimationEnd events, allowing us to fire a specific event handler when a specific animation ends? For instance, fire handler1 when animation1 ends and fire handler2 when animation2 ends.
We're building for Webkit browsers, specifically Mobile Safari.
Thanks!
For a simple event-trigger, you can pass a function to jQuery's trigger() method and use the returned value of that function to call a trigger a specific event (which can then be listened-for:
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animName + 'FunctionTrigger';
}
}
$('body').on('bgAnimFunctionTrigger fontSizeFunctionTrigger', function(e){
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});
JS Fiddle demo.
You can, of course, also use the called function to either trigger the event itself or assess the passed parameters to determine whether or not to return an event at all:
One method to assess for a particular event to trigger is to use an object:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animations[animName] ? animations[animName] : false;
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});
JS Fiddle demo.
Though, in this case, the return false should be altered so as not to provide the error Uncaught TypeError: Object false has no method 'indexOf' (which I've not bothered, as yet, to account for).
The following causes the called-function (animEndTrigger()) to directly trigger() the custom event (which requires an element on which to bind the trigger() method) and also avoids the Uncaught TypeError above:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e, el) {
if (!e || !el) {
return false;
}
else {
var animName = e.originalEvent.animationName;
if (animations[animName]) {
$(el).trigger(animations[animName]);
}
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
animEndTrigger(e, this);
});
JS Fiddle demo.
Of course you're still, effectively, using an if to perform an assessment, so I can't be particularly sure that this is any tidier than your own already-implemented solution.
I need to pass data between two autonomic user scripts - ideally without touching the unsafeWindow object - and I thought using custom events would be the way to go. I thought of something like this (let us disregard the MSIE model for the purpose of the example):
addEventListener("customEvent", function(e) {
alert(e.data);
});
var custom = document.createEvent("HTMLEvents");
custom.initEvent("customEvent", true, true);
custom.data = "Some data...";
dispatchEvent(custom);
This works nicely in the standard Javascript environment and within one user script, but when the event is fired by the user script and caught outside of it or inside another user script, the data property is undefined in Chromium. I suppose I could just save the passed data in the sessionStorage, but it is far from seamless. Any other elegant solutions? Perfection need and can be achieved, I can feel it.
Yes, you can use a MessageEvent or a CustomEvent.
Example usage:
//Listen for the event
window.addEventListener("MyEventType", function(evt) {
alert(evt.detail);
}, false);
//Dispatch an event
var evt = new CustomEvent("MyEventType", {detail: "Any Object Here"});
window.dispatchEvent(evt);
pass object with more details as attributes:
var event = new CustomEvent('build', { detail: { 'detail1': "something", detail2: "something else" }});
function eventHandler(e) {
log('detail1: ' + e.detail.detail1);
log('detail2: ' + e.detail.detail2);
}
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
new CustomEvent is not supported in IE https://caniuse.com/#search=CustomEvent
Here is a version which also works on IE9+:
//Listen for the event
window.addEventListener("MyEventType", function(evt) {
alert(evt.detail.test); //alerts "Any Object Here"
}, false);
//Dispatch an event
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent('MyEventType', false, false, { test: "Any Object Here" });
window.dispatchEvent(evt);