Scroll-view not scrolling with surface fa-size [undefined,true] - javascript

I have a scroll-view has one fa-surface that contains the html for my page. The height for this `fa-surface' is dynamic since it can be larger or smaller depending on the width of the page.
I have set the fa-modifier size to fa-size=[undefined, true] (Read that true sets the height to the surfaces height).
This results in a page that will not scroll. If I put a fixed height in the fa-size it will work, but that does me no good as the page is responsive and the height is dynamic.
Here is the code for the page:
<fa-app style="height:100%">
<fa-scroll-view fa-pipe-from="eventHandler">
<fa-view>
<fa-modifier fa-size="[undefined, true]">
<fa-surface fa-pipe-to="eventHandler">
Misc HTML...
</fa-surface>
</fa-modifier>
</fa-view>
</fa-scroll-view>
</fa-app>
Here is the simple controller for piping the events.
angular.module('newvitalwallApp')
.controller('MainCtrl', function ($scope, $famous) {
var EventHandler = $famous['famous/core/EventHandler'];
$scope.eventHandler = new EventHandler();
});
The live page is on a dev server here if your curious how it is behaving :
http://staging-sqtmp3dxdz.elasticbeanstalk.com/
I am at a loss as to why this is not working.. I am new to famous, but I have scoured the internet for answers on this and have found very little.
Thanks in advance for your input.

I just created a service that will handle true for width and height temporarily, but also logged the issue in the f/a issue tracker so hopefully the team will fix.
var faTrueService = function($famous){
this.height = function(cl){
if($famous.find(cl)[0].renderNode._currentTarget !== null && $famous.find(cl)[0].renderNode._currentTarget.children[0] !== undefined){
return $famous.find(cl)[0].renderNode._currentTarget.children[0].clientHeight;
}
};
this.width = function(cl){
if($famous.find(cl)[0].renderNode._currentTarget !== null && $famous.find(cl)[0].renderNode._currentTarget.children[0] !== undefined){
return $famous.find(cl)[0].renderNode._currentTarget.children[0].clientWidth;
}
};
};
In the template, you can now do the following:
<fa-modifier fa-size="[undefined, faTrue.height('.item-1')]">
<fa-view fa-index="1">
<fa-surface class="item-1" fa-pipe-to="pageScrollHandler">
When Surfaces get deployed, a resize event gets attached to the them that forces the Surface to reevaluate it's size, so the Service will get called on resize automatically.
Since you can't just use Services in a template, I created a helper function that calls the Service on the current Controller or Directive scope I'm working with.
//temp fix for true
$scope.faTrue = {
height : function(cl){
return faTrue.height(cl);
},
width : function(cl){
return faTrue.width(cl);
}
};
The child .fa-surface being targeted might have to get the following styling for this to work:
.fa-surface{
overflow:hidden;
height:auto;
width:auto;
}
I don't understand why the previous answer uses the callback for sync, this doesn't make sense, especially since the size is getting reevaluated on resize of Surfaces, not on an event attached to the scrollview.
Since all the children of the Scrollview now have height, it will automatically adjust it's height as well in Famo.us 0.3.0

So, though I do feel setting the size of the fa-modifier to [undefined,true] should be enough to set the height of the scrolled content, it's not enough.
So I added function that checks the height of the content on scroll and updates the fa-size dynamically. Here's the code I added the original controller:
$scope.$on('$viewContentLoaded', function(){
$famous.find('fa-scroll-view')[0].renderNode.sync.on('start', function(event) {
var test = angular.element( document.querySelector( '#test' ) );
$scope.testHeight = test[0].clientHeight;
});
});
$scope.getTestHeight = function() {
return $scope.testHeight;
}
Then I changed the fa-size in the view to [undefined, getTestHeight()]
There very well may be a better way of doing this, and ultimately I think it should be handled automatically by famous-angular, but for now this solves it.

Related

How to enforce user must scroll pdf within iframe

I have a pdf file within iframe. I want user to scroll must in pdf file before submitting the form. i am trying with this,
var position = $('#myIframe').contents().scrollTop();
But not working. Please help me Thanks in advance.
If you don't mind making a static height for your iframe, I have a solution for you.
HTML and CSS
1. Wrap your iframe in a div container
2. set heights for both your container and iframe (height of container should be the height you want your frame to be seen and the iframe height should be large enough to show entire pdf.)
3. set container div's overflow to scroll
Now you have a scrollable "iframe".
Javscript
Get container element. (var containerEl = $("#container")[0];)
Write a scroll function. Within the scroll function find if the total height of the element (scrollHeight) is less than or equal to how much has been scrolled (scrollTop) plus the inner height (clientHeight) of the
element. If it is, remove disabled property from button
Here's the fiddle. Made some changes to #mJunaidSalaat's jsfiddle.
Well I've tried almost an hour on this, Researched it, finally coming to a conclusion that Unfortunately this is not possible using this method.
The PDF is usually not a DOM element, it's rendered by PDF reader software. Every browser has its own mechanism for rendering PDFs, there is no standard. In some cases, the PDF might be rendered by PDF.js; in those situations you might be able to detect scrolling. But Adobe Reader, Foxit, and some of the native PDF rendering don't provide that option.
I've also created a Github issue for this. But no use.
Sorry. Please update me if you could find any thing or any workaround.
I've made a Fiddle for your solution. You can disable the submit button for user until user scroll on your iframe.
function getFrameTargetElement(objI) {
var objFrame = objI.contentWindow;
if (window.pageYOffset == undefined) {
objFrame = (objFrame.document.documentElement) ? objFrame.document.documentElement : objFrame = document.body;
}
return objFrame;
}
$("#myIframe").ready(function() {
var frame = getFrameTargetElement(document.getElementById("myIframe"));
frame.onscroll = function(e) {
$('.submitBtn').prop('disabled', false);
}
});
Hope it helps.
try this
$("#myIframe").ready(function() {
var frame = getFrameTargetElement(document.getElementById("myIframe"));
frame.onscroll = function(e) {
$('.submitBtn').prop('disabled', false);
}
});

Window resize event in AngularJS

I have been googling for a while and so far I found how to resize window with window resize directive but in my code I'm using window.innerHeight to get initial height. I can use it any time except I need an event to when it changes. JavaScript window resize event does not fire for me for some reason. Here is my code inside of the controller:
function adjustH() {
var bodyElem = document.getElementsByTagName('body')[0];
var topP = window.getComputedStyle(bodyElem, null).getPropertyValue('padding-top');
topP = topP.substring(0, topP.indexOf("px"));
var bottomP = window.getComputedStyle(bodyElem, null).getPropertyValue('padding-bottom');
bottomP = bottomP.substring(0, bottomP.indexOf("px"));
vm.h = window.innerHeight - topP - bottomP - 20;
}
window.onresize = function(event) {
adjustH();
}
Can anybody tell me if it is impossible to do it this way and I have to go the directive route? Or if its possible please tell me what I'm missing.
If you are working with angularJS, did you pass $window as a dependency to you controller.
I have had similar issues with this before and it was because the depoendency was not set.
Hope this helps.
After reading your comment which stated
Also my canvas set to height="{{vm.h}}" but it only resizes when I mouse over
It seems that you need to call $scope.$apply() (or $rootScope.$apply()) in order to update the height property of the element.
If you add more code from your directive/controller, I could give you a more detailed answer.

Jquery scroll event causing performance issues

I'm trying to use the browser scroll event to place a block of html based on the amount a user has scrolled. The code works but it is causing a huge performance issue which basically forces my browser to freeze.
Any insight as to why and what I could do to resolve this would be greatly appreciated.
<script type="text/javascript">
$('#content').scroll(function () {
var scroll = $('#content').scrollTop();
var $controls = $(".controls").clone();
if (scroll > 200) {
$(".controls").remove();
$('#header').append($controls);
}
else {
$(".controls").remove();
$('.banner').append($controls);
}
});
</script>
First, discovering elements in the DOM is an expensive activity, so cache your jQuery objects.
Second, .append() moves elements around so .clone() and remove() should be unnecessary.
This gives :
var $$ = {//cache of jQuery objects
content: $('#content'),
controls: $(".controls"),
header: $("#header"),
banner: $('.banner')
};
$('#content').scroll(function() {
$controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
});
Now, you can work on reducing the frequency at which the handler is called, which can be achieved as follows :
var $$ = {//cache of jQuery objects
content: $('#content'),
controls: $(".controls"),
header: $("#header"),
banner: $('.banner')
};
var scrollHandling = {
allow: true,
reallow: function() {
scrollHandling.allow = true;
},
delay: 50 //(milliseconds) adjust to the highest acceptable value
};
$('#content').scroll(function() {
if(scrollHandling.allow) {
$controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
scrollHandling.allow = false;
setTimeout(scrollHandling.reallow, scrollHandling.delay);
}
});
The scroll function is called for every movement of the scrollbar. That can potentially be a lot of times, so you need to be careful how much code you are running and certainly how much manipulation of the DOM you are doing.
In this case, you'll be repeating a lot of the same actions (clone, append, remove) as the scrolling is occurring, but it appears that you only want to flip between two states as you cross back and forth over that 200 scroll value. You could potentially solve most of the performance issues with something like this:
<script type="text/javascript">
var thresholdCrossed = false;
$('#content').scroll(function () {
var scroll = $('#content').scrollTop();
var threshold = 200;
if (scroll > threshold && !thresholdCrossed) {
var controls = $(".controls").clone();
$(".controls").remove();
$('#header').append(controls);
} else if (scroll <= threshold && thresholdCrossed) {
var controls = $(".controls").clone();
$(".controls").remove();
$('.banner').append(controls);
}
thresholdCrossed = scroll > threshold;
});
</script>
You can do additional work that some of the other answers describe to help reduce wasted resources, but this should give you a general idea of how to hopefully help the main performance concern of constantly modifying the DOM as you scroll. I would probably suggest some combination of this along with the answer provided by #Kolink so that you are truly limiting the DOM manipulation to the least amount necessary.
You are cloning all .controls elements every tick of scrolling, even when it is not needed.
I would suggest cloning the controls on ready and setting it to display:none. Then, just toggle the display based on the scroll position.
On re-reading your question, it looks like you're just moving the controls element from the header to the banner? In that case, you don't even need a clone. However I strongly suggest adding id="controls" to the controls element, and id="banner" - use IDs instead of classes in general if there is only one.
document.getElementById('content').onscroll = function() {
document.getElementById(this.scrollTop > 200 ? "banner" : "header")
.appendChild(document.getElementById('controls'));
};
Every time the scroll bar moves jQuery has to go into the DOM to get the variables you references. To start cache the variables so jQuery doesnt have to do twice the work.
var content = $('#content');
content.scroll(function(){
});

Disable Browser Window Resize

For starters... I have no sinister intention of subjecting users to popups or anything like that. I simply want to prevent a user from resizing the browser window of a webpage to which they've already navigated (meaning I don't have access to / don't want to use window.open();). I've been researching this for quite a while and can't seem to find a straightforward answer.
I felt like I was on track with something along the lines of:
$(window).resize(function() {
var wWidth = window.width,
wHeight = window.height;
window.resizeBy(wWidth, wHeight);
});
...to no avail. I have to imagine this is possible. Is it? If so, I would definitely appreciate the help.
Thanks
You can first determine a definite size.
var size = [window.width,window.height]; //public variable
Then do this:
$(window).resize(function(){
window.resizeTo(size[0],size[1]);
});
Demo: http://jsfiddle.net/DerekL/xeway917/
Q: Won't this cause an infinite loop of resizing? - user1147171
Nice question. This will not cause an infinite loop of resizing. The W3C specification states that resize event must be dispatched only when a document view has been resized. When the resizeTo function try to execute the second time, the window will have the exact same dimension as it just set, and thus the browser will not fire the resize event because the dimensions have not been changed.
I needed to do this today (for a panel opened by a chrome extension) but I needed to allow the user to change the window height, but prevent them changing the window width
#Derek's solution got me almost there but I had to tweak it to allow height changes and because of that, an endless resizing loop was possible so I needed to prevent that as well. This is my version of Dereck's answer that is working quite well for me:
var couponWindow = {
width: $(window).width(),
height: $(window).height(),
resizing: false
};
var $w=$(window);
$w.resize(function() {
if ($w.width() != couponWindow.width && !couponWindow.resizing) {
couponWindow.resizing = true;
window.resizeTo(couponWindow.width, $w.height());
}
couponWindow.resizing = false;
});
If need some particular element to handle resize in some particular mode, and prevent whole window from resizing use preventDefault
document.getElementById("my_element").addEventListener("wheel", (event) =>
{
if (event.ctrlKey)
event.preventDefault();
});

How to use jQuery jScrollPane and scrollTo plugins in the same script

I'm building my first js/jQuery site and I've run into a hiccup. I'm trying to use both jScrollpane (Kelvin Luck) and scrollTo (Ariel Flesler) plugins in one script. If I comment one out, the other works. Are they mutually exclusive? Do I need to unbind functionality out of jScrollpane to remove a 'scrollTo' call conflict or something? (I have no idea how to do that).
I'm using jScrollPane 2beta11 and scrollTo 1.4.2. Here's my stripped-down code using both:
// JavaScript Document
$(document).ready(function() {
//jScrollPane Init
$('#scrollingDiv').jScrollPane({
});
//scrollTo Refresh
$('div.scroll-pane').scrollTo( 0 );
$.scrollTo( 0 );
//Buttons
var $scrollDiv = $('#scrollingDiv');
var next = 1;
$('#but-rt').click(function(){
$scrollDiv.stop().scrollTo( 'li:eq(1)', 800 );
next = next + 1;
});
});
I'm aware that jScrollPane has it's own scrollTo functionality, but I need scrollTo's jQuery Object selectors in my particular project. I know I've got my HTML/CSS lined up fine because each function works as long as the other is commented out.
(By the way, I plan on using "next" variable to increment scrollTo button once I figure out how... not related to my problem tho.)
Any help is much appreciated. Let me know if there's anything else I need to supply. Thanks!
-Patrick
See how to use ScrollTo functionality of JscrollPane from the following url,
http://jscrollpane.kelvinluck.com/scroll_to.html
Hope this will help you...
I too was trying to use both jScrollpane (Kelvin Luck) and scrollTo (Ariel Flesler) plugins in one script. I've come across an easy solution which doesn't even require Ariel Flesler's AWESOME Script, if you don't necessarily require animated scrolling.
I wanted to be able to scroll to a label in a list of items when the page loads.
Here's how i did it:
$(function()
//Declare the ID or ClassName of the Scroll Element
//and the ID or ClassName of the label to scroll to
MyList = $('#MyElementID OR .MyElementClassName');
MyLabel = $('#MyElementID OR .MyElementClassName');
// Initiate the Scrollpane
MyScroll = $(MyList).jScrollPane();
// Connect to the jScrollPaneAPI
jScrollPaneAPI = MyScroll.data('jsp');
// Get position co-ordinates of the Label
var MyLabelPosition = $(MyLabel).position();
// Convert position co-ordinates to an Integer
MyLabelPosition = Math.abs(MyLabelPosition.top);
// Scroll to the Label (0-x, vertical scrolling) :)
jScrollPaneAPI.scrollTo(0, MyLabelPosition-3, true);
});
There's a small bug with the exact positioning when a list gets longer,
will post a fix asap...
They are mutually exclusive because jScrollPane removes the real scrolling and replaces it with complex boxes-in-boxes being moved relative to each other via JS.
This is how I successfully mixed them -- I had a horizontal list of thumbnails; this code scrolled the thumbnails to the center:
Activated jScrollPane:
specialScrolling = $('#scrollingpart').jScrollPane();
In my serialScroll code, where I usually would call
$('#scrollingpart').trigger('goto', [pos]);
in my case, inside my
onBefore:function(e, elem, $pane, $items, pos)
I put code like this:
jScrollPaneAPI = specialScrolling.data('jsp');
//get the api to manipulate the special scrolling are
scrollpos=(Math.abs(parseInt($('.jspPane').css('left'), 10)));
//get where we are currently scrolled -- since this is a negative number,
//get the absolute value
var position = $('#scrollingpart .oneitem').eq(pos).position();
//get the relative offset location of the item we are targetting --
//note "pos" which is the index number for the items that you can access
//in serialScroll's onBefore:function
itempos=Math.abs(position.left);
//get just the x-axis location -- your layout might be different
jScrollPaneAPI.scrollBy(itempos-scrollpos-480, 0, true);
//the 480 worked for my layout; the key is to subtract the 2 values as above
Hope this helps someone out there!
This doesn't cater for all use cases (it only handles scrollToY and scrollToElement), but offers a consistent API so you can just use $( /* ... */ ).scrollTo( /* number or selector */ ) and it will work on any element, jScrollPane or native.
You could extend the method condition to cater for all the other jScrollPane methods by inferring the value passed in target though.
(function scrollPaneScrollTo(){
// Save the original scrollTo function
var $defaultScrollTo = $.fn.scrollTo;
// Replace it with a wrapper which detects whether the element
// is an instance of jScrollPane or not
$.fn.scrollTo = function $scrollToWrapper( target ) {
var $element = $( this ),
jscroll = $element.data( 'jsp' ),
args = [].slice.call( arguments, 0 ),
method = typeof target === 'number' ? 'scrollToY' : 'scrollToElement';
if ( jscroll ) {
return jscroll[ method ].call( $element, target, true );
}
else {
return $defaultScrollTo.apply( $element, args );
}
};
}();

Categories