ngSwipe and horizontal scroll - javascript

I'm having issues combining ng-swipe and horizontal scrolling on mobile. The use case is that I have a page that on swiping should load next or previous and inside there are modules that show a lot of information. Some of it is scrolled.
So, as soon as you scroll the swipe on the parent kicks in and you get navigated. So I put another pair of ng-swipe on the parent of the scrollable element with this sort of trickery:
self.onInnerSwipe = function($event) {
$event.originalEvent.preventAction = true;
};
And then on the parent:
var shouldActionProceed = function($event) {
return !$event || !$event.originalEvent || !$event.originalEvent.preventAction;
};
self.goToPrev = function($event) {
if (shouldActionProceed($event)){
// Do Magic
}
}
This does the trick in the way that the action doesn't proceed if I'm swiping over that element but the scroll doesn't really work. It sorts of but it doesn't. It starts a bit and then stops.
On Chrome there are this warnings being logged sometimes.
Ignored attempt to cancel a touchmove event with cancelable=false, for
example because scrolling is in progress and cannot be interrupted.
I have prepared a demo here: http://jsbin.com/webologavu/2/ which is overly simplistic but you can reproduce the issue.
Any hints?

I think that it's a concurrency issue with these events. It might work better if you your parent event doesn't rely on the child event. To achieve that:
//add a identifier to your list element
<ul class="myList" your-other-attrs></ul>
//should proceed can rely on the target element to find out
//if the target element belongs (or is) in your list.
var shouldActionProceed = function($event) {
return !$($event.target).hasClass("myList") && //is myList?
$($event.target).parents(".myList").length == 0; //has parent 'myList'?
};
This way, the parent event can work on its on.

Related

Break the 'scroll' event Javascript

Now, I want to make fade from top effect when my element be in the viewport by adding 'activate' class for it...
I don't want to use any external libraries that do it direct.
My code is:
window.addEventListener('scroll', function(e) {
var cards = document.querySelectorAll('cards');
for ( let card of cards ) {
if(!card.classList.contains('fadeFromTop')) {
card.classList.add('fadeFromTop');
}
}
}
but when my element goes out from the viewport, it still checks if the element has that class
I didn't add the if statement that checks if the element is inside the viewport.
Is there a way to break and stop the scroll event when all cards have the class 'fadeFromTop' ?
I tried to search on google but what I find is the element.removeEventListener(); and I can't understand what does it do...

Sencha Touch list and scrollToRecord

I have a long sencha touch list and I am trying desperately to scroll that list into somewhere in the middle on startup.
The function
btnScroll:function() {
var list = Ext.getCmp("myList");
var position = 4;
list.scrollToRecord(list.getStore().getAt(position));
}
works if I tap the button: scrollBtn.setHandler(btnScroll);, but it does not work in
MyList.constructor:function() {
...
this.callParent();
this.btnScroll();
}
It just fails without error message. Same goes if I do it in the calling function:
btnOpenList:function() {
var list = new MyList();
list.show();
list.btnScroll();
}
It works sometimes(!) if I use setTimeout(this.btnScroll,70); instead, but never if I use setTimeout(this.btnScroll,50); or setTimeout(this.btnScroll,120);
I think it happens because the list elements are not rendered/positioned. But I did not find any afterrender event.
So how would I define a scroll position in which the list should start?
You could do it in painted event. just add to your list or to container that contains all components that u need to bind the painted event.. and then get your list there and add event to btn.. or whatever you want.. by the template:
element.clearListeners();
element.addListener('tap',function(){
//...
});

jQuery UI - Slider unbinds after one use

I'm still a novice, so please go easy on me!
I'm making a JavaScript game. The game works fine, as do the basics of the user interface, like making menu selections or switching screens. But I'm also trying to implement jQuery UI sliders in one of my options menus, which is where I run into trouble.
I can only use the slider once, after which it becomes "stuck." It responds to mouseover - it'll highlight as though it's ready to scroll - but will not budge if I try to move it again.
So far, I've ruled out any problems with the build of jQuery/jQUI I'm using; the demo page works fine.
I have no idea what the problem might be, but I suspect it has something to do with the way I've put together my UI. The way my UI works is by creating a "View" object that contains pointers to a parent DOM element. I then use jQuery to construct its children and use the "loadElement" method to add it to the view's list of children elements:
function CView (parent, target, visible, jQElements) {
this.parent = parent;
this.visible = visible;
this.parentDisplay = parent.css("display");
this.parentPosition = parent.css("position");
this.elements = [];
for(element in jQElements) {
this.elements.push(element);
}
if (!this.visible) {
this.parent.css({ // Default to hidden state
"opacity": 0,
"display": "none"
});
}
this.parent.appendTo(target);
};
CView.prototype.loadElement = function(element) {
element.appendTo(this.parent);
this.elements.push(element);
return element;
};
All these elements can be shown and hidden together with a method call on the View object. Currently, hiding a view unbinds all event listeners in the elements of that view. I don't think this is the problem, since I get this problem immediately after creating a new view.
The issue, I think, might be in this code, which is for swapping views- Perhaps I'm unbinding some kind of document-level listener that jQUI uses?
var swapView = GameUI.swapView = function(view, callbacks) {
$(document).off(); // unbind key listeners
currentView && currentView.hideView(); // also unbinds event listeners
currentView = view;
view.showView(callbacks);
};
There's one more thing that might be relevant, the way I construct the slider and put it in:
var $volumeSlider = jQuery("<div/>", {
class: "options-menu-volume-slider"
});
var resetVolumeSlider = function () {
$volumeSlider.slider({
range: "min",
value: GameUI.options.volume,
min: 0,
max: 100
})
};
resetVolumeSlider();
If you need to see more code, let me know. I really am not sure what's going wrong here. Any and all help is appreciated. (Also, I don't know how to host my game online to demo it. It's basically just an HTML page that runs a bunch of JS.)
It turns out that this problem was caused by my call to $(document).off(), which I used to remove potentially dangling document-level keypress handlers. This had the unfortunate result of also destroying event handlers for jQuery UI.
In the future, my views will have keypresses bound at the parent div level with tab indices set for each div, so that I don't have to make the call to $(document).off() and can simply use hideView() to unbind.

animate scrollTop fires scroll event

I have some code that listens to the scrolling of a page and it's responsible for two things, performing the necessary action (which works) when the "page" has changed but also animate the scrollTop to the nearest "page" but in doing so the scroll event is fired so it sequentially crawls through all the "pages" until it reaches the end of the document.
How can I stop animate scrollTop from firing the scroll event? Is it even possible?
"pages" because this is an iPad html page and each 1024x768 view is a "page"
You can find a answer at this post : https://stackoverflow.com/a/1659231/237838
You could make write your own code to set the animation value, and set
a flag indicating that the change comes from an animation.
For example: (Untested)
var scrollAnimating = false
jQuery.fx.step.scrollTop = function(E) {
scrollAnimating = true;
E.elem.scrollTop = E.now;
scrollAnimating = false;
};
$('#gototop').click(function() {
$('body').animate({scrollTop:0},3000);
$(window).scroll(function () {
if (!scrollAnimating)
$('body').stop();
});
return false;
})

Make (possibly dynamically loaded) element clickable via JavaScript, but give precedence to links contained within

I am adding a custom data attribute data-js-href to various HTML elements, and these elements should behave just like a link when clicked. If a link within such an element is clicked, the link should take precedence and the data-js-href functionality should be ignored, though. Furthermore, the solution also needs to work with elements that are dynamically added at a later time.
So far, I have come up with the following solution. It basically checks if the click was performed on a link, or any child element of a link (think <a href='…'><img src='…' alt='…' /></a>).
// Make all elements with a `data-js-href` attribute clickable
$$('body').addEvent('click:relay([data-js-href])',
function(event, clicked) {
var link = clicked.get('data-js-href');
if (link && !event.target.match('a')) {
var parents = event.target.getParents();
for (var i = 0; i < parents.length && parents[i] != clicked; i++) {
if (parents[i].match('a')) {
return;
}
}
document.location.href = link;
}
});
It works, but it feels very clumsy, and I think that there has to be a more elegant solution. I tried something along the lines of
$$('body').addEvent('click:relay([data-js-href] a)',
function(event, clicked) {
event.stopPropagation();
}
but to no avail. (I littered the code with some console.log() messages to verify the behavior.) Any idea is welcome.
you can do this with 2 delegated events - no reverse lookups and it's cheap as they will share the same event. the downside is, it is the same event so it will fire for both and there's no stopping it via the event methods (already bubbled, it's a single event that stacks up multiple pseudo event callbacks and executes them in order--the event has stopped but the callbacks continue) That's perhaps an inconsistency in mootools event vs delegation implementation but it's a subject of another issue.
Workarounds for now can be:
to have the 2 event handlers communicate through each other. It will scale and work with any new els added.
to add the delegators on 2 different elements. eg. document.body and #mainWrap.
http://jsfiddle.net/dimitar/J59PD/4/
var showURL = function(howLong) {
// debug.
return function() {
console.log(window.location.href);
}.delay(howLong || 1000);
};
document.id(document.body).addEvents({
"click:relay([data-js-href] a))": function(e) {
// performance on lookup for repeat clicks.
var parent = this.retrieve("parent");
if (!parent) {
parent = this.getParent("[data-js-href]");
this.store("parent", parent);
}
// communicate it's a dummy event to parent delegator.
parent.store("linkEvent", e);
// let it bubble...
},
"click:relay([data-js-href])": function(e) {
// show where we have gone.
showURL(1500);
if (this.retrieve("linkEvent")) {
this.eliminate("linkEvent");
return;
}
var prop = this.get("data-js-href");
if (prop)
window.location.href = prop;
}
});
Discussed this with Ibolmo and Keeto from the mootools team on IRC as well when my initial attempt failed to work and both callbacks fired despite the event.stop: http://jsfiddle.net/dimitar/J59PD/
As a result, there was briefly a ticket open on the mootools github issues: https://github.com/mootools/mootools-core/issues/2105 but it then went into a discussion of what the right thing to do from the library standpoint is and how viable it is to pursue changing the way things work so...

Categories