Start counter on scroll - counter

We recently implemented this code for a count up number function and it works great:
$('.count').each(function () {
$(this).prop('Counter',0).animate({
Counter: $(this).text()
}, {
duration: 4000,
easing: 'swing',
step: function (now) {
$(this).text(Math.ceil(now).toLocaleString('en'));
}
});
});
However, it starts the count up on page load and we want it to work only when a user scrolls to that section. And, we only want it to run one time per page load. What do we add to make sure it starts only when the element is in view?

Related

How to wait the page to test is loaded in non angular site?

I've tried this:
browser.wait(function () {
return browser.executeScript('return document.readyState==="complete" &&' +
' jQuery !== undefined && jQuery.active==0;').then(function (text) {
return text === true;
});
}, 30000);
If jQuery.active==0 then page is completely loaded. This should work for sites with JQuery and non angular pages.
However, I have many problems of instability to test for non angular sites.
How to fix this?
By default protractor waits until the page is loaded completely. If you are facing any error then it is because protractor is waiting for the default time to be completed, that you have specified in your conf.js file to wait until page loads. Change the value to wait a for longer time if you think your app is slow -
// How long to wait for a page to load.
getPageTimeout: 10000, //Increase this time to whatever you think is better
You can also increase the defaultTimeoutInterval to make protractor wait a little longer before the test fails -
jasmineNodeOpts: {
// Default time to wait in ms before a test fails.
defaultTimeoutInterval: 30000
},
If you want to wait for any particular element, then you can do so by using wait() function. Probably waiting for last element to load is the best way to test it. Here's how -
var EC = protractor.ExpectedConditions;
var lastElement = element(LOCATOR_OF_LAST_ELEMENT);
browser.wait(EC.visibilityOf(lastElement), 10000).then(function(){ //Alternatively change the visibilityOf to presenceOf to check for the element's presence only
//Perform operation on the last element
});
Hope it helps.
I use ExpectedConditions to wait for, and verify page loads. I walk through it a bit on my site, and example code on GitHub. Here's the gist...
Base Page: (gets extended by all page objects)
// wait for & verify correct page is loaded
this.at = function() {
var that = this;
return browser.wait(function() {
// call the page's pageLoaded method
return that.pageLoaded();
}, 5000);
};
// navigate to a page
this.to = function() {
browser.get(this.url, 5000);
// wait and verify we're on the expected page
return this.at();
};
...
Page Object:
var QsHomePage = function() {
this.url = 'http://qualityshepherd.com';
// pageLoaded uses Expected Conditions `and()`, that allows us to use
// any number of functions to wait for, and test we're on a given page
this.pageLoaded = this.and(
this.hasText($('h1.site-title'), 'Quality Shepherd')
...
};
QsHomePage.prototype = basePage; // extend basePage
module.exports = new QsHomePage();
The page object may contain a url (if direct access is possible), and a pageLoaded property that returns the ExepectedCondition function that we use to prove the page is loaded (and the right page).
Usage:
describe('Quality Shepherd blog', function() {
beforeEach(function() {
// go to page
qsHomePage.to();
});
it('home link should navigate home', function() {
qsHomePage.homeLink.click();
// wait and verify we're on expected page
expect(qsHomePage.at()).toBe(true);
});
});
Calling at() calls the ExpectedCondidion (which can be be an and() or an or(), etc...).
Hope this helps...

How execute code every time that I view a page

I'm searching the mode to execute a code (in my case the retrieve of data to visualize from server) every time I view a page (every time the page is called by splitApp.toDetail or splitApp.backDetail). How can i do it?
P.S. The onBeforeRendering and onAfterRendering execute only the first time.
There is a solution for you. There is a event called routeMatched when navigation is triggered every time. You can attach the event in the detail page.
onInit : function () {
this._oRouter = sap.ui.core.UIComponent.getRouterFor(this);
this._oRouter.attachRouteMatched(this.handleRouteMatched, this);
},
handleRouteMatched : function (evt) {
//Check whether is the detail page is matched.
if (evt.getParameter("name") !== "detail") {
return;
//You code here to run every time when your detail page is called.
}
I´m using onBeforeShow in my target views for that.
onBeforeShow : function(evt) {
// gets called everytime the user
// navigates to this view
},
This is a function which is fired by a NavContainer on its children in case of navigation. It´s documented in the NavContainerChild.
If routing is used, another version of Allen's code:
onInit : function () {
this._oRouter = sap.ui.core.UIComponent.getRouterFor(this);
this._oRouter.getRoute("detail").attachMatched(this.handleRouteMatched, this);
},
handleRouteMatched : function (evt) {
//You code here to run every time when your detail page is called.
}

iscroll rubber band effect in jQTouch

I am a new developer and am trying to create a jQTouch application to display some scrollable content throughout multiple pages. I've decided to use iscroll and it only works fine on the home page. I've read that I need to refresh iscroll after each page but I am completely lost on how to do this. Here is my script:
<script type="text/javascript">
var myScroll, myScroll2;
function loaded() {
setTimeout(function () {
myScroll = new iScroll('wrapper1');
}, 100);
setTimeout(function () {
myScroll2 = new iScroll('wrapper2');
}, 100);
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', loaded, false);
</script>
In my html I have a div id="wrapper1" which works fine until I navigate to the second page where the div id="wrapper2" has the rubber band effect.
In case you haven't figured this out yet (although I'm sure you have), you want:
myScroll.refresh()
or
myScroll2.refresh()
Ok finally got this working. To get jQTOuch and iScroll to play nice with each other, the scrolling areas on the page need to be reset each time JQTouch makes them disappear. In other words, once you hide the div, iScroll doesn't know what to scroll the next time it's made visible. So as a result, you get the infamous rubberband effect. To solve this, just add an event listener that resets the scrolling area right after the div is called. Make sure you give it 100 to 300ms delay. This code below assumes your variable is called myScroll:
$(".about").tap(function(){
setTimeout(function(){myScroll.refresh()},300);
});
And on a side note, here's how to establish multiple scrollers using iScroll:
var scroll1, scroll2;
function loaded() {
scroll1 = new iScroll('wrapper1');
scroll2 = new iScroll('wrapper2');
}

jQuery event trigger; callback and timing with respect to animations

Perhaps my question deviates from the simplicity of itself: Given I .trigger() an event, how can I ensure that code following said .trigger() will not execute until the entire event handler function has completed, including all animations, delays, et al., therein?
I hope I'm missing something here; I'm setting up a UI with a bunch of custom events. Some of the events are really just aggregates of other events; for instance:
// ...
'cb-ui.hide': function(event){
// do stuff to hide
},
'cb-ui.close': function(event){
$(this).trigger('cb-ui.hide');
// more stuff for close
},
// ...
Given there is an animation in the cb-ui.hide event, like .fadeOut(1500), it appears (in my testing) that the remaining // more stuff for close doesn't wait for the animation to complete in the triggered event. I was thinking (previous to referencing the docs) that .trigger() would likely have an optional callback argument much like the animation methods:
$(this).trigger('cb-ui.hide', function(event){
// more stuff for close
});
But this doesn't appear to be the case. Since event triggers are not blocking (or don't appear to be at least), what can I do to force the desired functionality, while keeping with the event handler/trigger implementation that I've been building off of?
More specifically:
$('[data-cb-ui-class="window"]').live({
'cb-ui.hide': function(event){
$(this).find('[data-cb-ui-class="content"]').animate({
opacity: 0
}, 1000);
},
'cb-ui.show': function(event){
$(this).find('[data-cb-ui-class="content"]').animate({
opacity: 1
}, 1000);
}
'cb-ui.close': function(event){
$(this).trigger('cb-ui.hide');
$(this).find('[data-cb-ui-class="content"]').animate({
height: 'hide' // happening simultaneously to the animation of 'cb-ui.hide'
// expected to happen in tandem; one after the other
}, 1000);
},
'cb-ui.update': function(event, html){
// none of this is working as expected; the expected being, the 'cb-ui.hide'
// event is triggered (thus fading the [...-content] out) the HTML content is
// updated, then the [...-content] is faded back in from 'cb-ui.show'
// instead its just a mess that results in it fading out
$(this).trigger('cb-ui.hide');
$(this).find('[data-cb-ui-class="content"]').html(html);
$(this).trigger('cb-ui-show');
}
});
$('#foo').trigger('cb-ui.update', ['<p>Hello world!</p>']); // #foo is bound
This example animation should take ~2 seconds, but appears to be taking 1; both animations are occurring simultaneous to each other, rather than in logical order.
Not sure if I understand your question right, but does this make sense?
You can just pass another function to be run after the animation is done.
'cb-ui.hide': function(event, callback){
$('.lol').fadeTo(0,function() {
// fire callback
})
},
'cb-ui.close': function(event){
cb-ui.hide(e,function() {
// other stuff
});
},

How do you animate FB.Canvas.scrollTo?

I've created an app that is a set size (around 2,000 px tall) and have a menu that calls FB.Canvas.scrollTo in order to help the user navigate the long page.
Is there any way to add a smooth scrolling effect? Facebook does not offer any solution on its developer blog.
Using #Jonny's method, you can do this a little more simply with
function scrollTo(y){
FB.Canvas.getPageInfo(function(pageInfo){
$({y: pageInfo.scrollTop}).animate(
{y: y},
{duration: 1000, step: function(offset){
FB.Canvas.scrollTo(0, offset);
}
});
});
}
Just had the same problem today - I came up with a little bit of javascript which makes use of jQuery's animate method which provides some easing - the scroll is still a touch jerky (I'm guessing that's because of the FB.Canvas.scrollTo proxy). Anyway, here's the snippet:
function scrollToTop() {
// We must call getPageInfo() async otherwise we will get stale data.
FB.Canvas.getPageInfo(function (pageInfo) {
// The scroll position of your app's iFrame.
var iFrameScrollY = pageInfo.scrollTop;
// The y position of the div you want to scroll up to.
var targetDivY = $('#targetDiv').position().top;
// Only scroll if the user has scrolled the window beneath the target y position.
if (iFrameScrollY > targetDivY) {
var animOptions = {
// This function will be invoked each 'tick' of the animation.
step: function () {
// As we don't have control over the Facebook iFrame we have to ask the Facebook JS API to
// perform the scroll for us.
FB.Canvas.scrollTo(0, this.y);
},
// How long you want the animation to last in ms.
duration: 200
};
// Here we are going to animate the 'y' property of the object from the 'iFrameScrollY' (the current
// scroll position) to the y position of your target div.
$({ y: iFrameScrollY }).animate({ y: targetDivY }, animOptions);
}
});
}
I just used Francis' technique and implemented a jQuery version
$('html,body').animate(
{scrollTop: $(".scroll_to_me").offset().top},
{duration: 1000, step: function(top_offset){
FB.Canvas.scrollTo(0, top_offset + 30);
}
});
You need to replace the .scroll_to_me with the selector you want to scroll to. Also I added in the + 30 to the offset as the iframe doesn't start at the top of the page, you may want to tweak this.
One way of doing it is by getting the current Y position, then getting the to Y position. Run a for loop with a setTimeout that will bring the user to the final Y position.