Giter Site home page Giter Site logo

angular-inview's Introduction

InView Directive for AngularJS CircleCI

Check if a DOM element is or not in the browser current visible viewport.

<div in-view="ctrl.myDivIsVisible = $inview" ng-class="{ isInView: ctrl.myDivIsVisible }"></div>

This is a directive for AngularJS 1, support for Angular 2 is not in the works yet (PRs are welcome!)

Version 2 of this directive uses a lightwight embedded reactive framework and it is a complete rewrite of v1

Installation

With npm

npm install angular-inview

With bower

bower install angular-inview

Setup

In your document include this scripts:

<script src="/node_modules/angular/angular.js"></script>
<script src="/node_modules/angular-inview/angular-inview.js"></script>

In your AngularJS app, you'll need to import the angular-inview module:

angular.module('myModule', ['angular-inview']);

Or with a module loader setup like Webpack/Babel you can do:

import angularInview from 'angular-inview';

angular.module('myModule', [angularInview]);

Usage

This module will define two directives: in-view and in-view-container.

InView

<any in-view="{expression using $inview}" in-view-options="{object}"></any>

The in-view attribute must contain a valid AngularJS expression to work. When the DOM element enters or exits the viewport, the expression will be evaluated. To actually check if the element is in view, the following data is available in the expression:

  • $inview is a boolean value indicating if the DOM element is in view. If using this directive for infinite scrolling, you may want to use this like <any in-view="$inview&&myLoadingFunction()"></any>.

  • $inviewInfo is an object containing extra info regarding the event

    {
      changed: <boolean>,
      event: <DOM event>,
      element: <DOM element>,
      elementRect: {
        top: <number>,
        left: <number>,
        bottom: <number>,
        right: <number>,
      },
      viewportRect: {
        top: <number>,
        left: <number>,
        bottom: <number>,
        right: <number>,
      },
      direction: { // if generateDirection option is true
        vertical: <number>,
        horizontal: <number>,
      },
      parts: { // if generateParts option is true
        top: <boolean>,
        left: <boolean>,
        bottom: <boolean>,
        right: <boolean>,
      },
    }
    
    • changed indicates if the inview value changed with this event
    • event the DOM event that triggered the inview check
    • element the DOM element subject of the inview check
    • elementRect a rectangle with the virtual (considering offset) position of the element used for the inview check
    • viewportRect a rectangle with the virtual (considering offset) viewport dimensions used for the inview check
    • direction an indication of how the element has moved from the last event relative to the viewport. Ie. if you scoll the page down by 100 pixels, the value of direction.vertical will be -100
    • parts an indication of which side of the element are fully visible. Ie. if parts.top=false and parts.bottom=true it means that the bottom part of the element is visible at the top of the viewport (but its top part is hidden behind the browser bar)

An additional attribute in-view-options can be specified with an object value containing:

  • offset: An expression returning an array of values to offset the element position.

    Offsets are expressed as arrays of 4 values [top, right, bottom, left]. Like CSS, you can also specify only 2 values [top/bottom, left/right].

    Values can be either a string with a percentage or numbers (in pixel). Positive values are offsets outside the element rectangle and negative values are offsets to the inside.

    Example valid values for the offset are: 100, [200, 0], [100, 0, 200, 50], '20%', ['50%', 30]

  • viewportOffset: Like the element offset but appied to the viewport. You may want to use this to shrink the virtual viewport effectivelly checking if your element is visible (i.e.) in the bottom part of the screen ['-50%', 0, 0].

  • generateDirection: Indicate if the direction information should be included in $inviewInfo (default false).

  • generateParts: Indicate if the parts information should be included in $inviewInfo (default false).

  • throttle: a number indicating a millisecond value of throttle which will limit the in-view event firing rate to happen every that many milliseconds

InViewContainer

Use in-view-container when you have a scrollable container that contains in-view elements. When an in-view element is inside such container, it will properly trigger callbacks when the container scrolls as well as when the window scrolls.

<div style="height: 150px; overflow-y: scroll; position: fixed;" in-view-container>
	<div style="height: 300px" in-view="{expression using $inview}"></div>
</div>

Examples

The following triggers the lineInView when the line comes in view:

<li ng-repeat="t in testLines" in-view="lineInView($index, $inview, $inviewpart)">This is test line #{{$index}}</li>

See more examples in the examples folder.

Migrate from v1

Version 1 of this directive can still be installed with npm install [email protected]. If you already have v1 and want to upgrade to v2 here are some tips:

  • throttle option replaces debounce. You can just change the name. Notice that the functioning has changed as well, a debounce waits until there are no more events for the given amount of time before triggering; throttle instead stabilizes the event triggering only once every amount of time. In practival terms this should not affect negativelly your app.
  • offset and viewportOffset replace the old offset options in a more structured and flexible way. offsetTop: 100 becomes offset: [100, 0, 0, 0].
  • $inviewInfo.event replaces $event in the expression.
  • generateParts in the options has now to be set to true to have $inviewInfo.parts available.

Contribute

  1. Fork this repo
  2. Setup your new repo with npm install and npm install angular
  3. Edit angular-inview.js and angular-inview.spec.js to add your feature
  4. Run npm test to check that all is good
  5. Create a PR

If you want to become a contributor with push access open an issue asking that or contact the author directly.

angular-inview's People

Contributors

carauzs avatar dganoff avatar ehsan89 avatar eknuth avatar farshad9037 avatar graingert avatar jrencz avatar lopsided avatar martyix avatar maxilev avatar oferze avatar pads avatar pmanijak avatar ricolo avatar simonv3 avatar thenikso avatar wli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-inview's Issues

in-view-container doesn't work with example

I'm using in-view-container for a scrollable div and I'm trying this like the example:

in-view="lineInView($index, $inview, $inviewpart)"

but $index is always undefined! can this be fixed easily so that it will work like in the example?

inViewOffset

I'm using inViewOffset with a container (using -webkit-overflow: touch) and it doesn't seems to work fine when going upwards… (it works downwards) there is any known issue with this? There is any fix that i should do to use this directive on mobile devices?

1.4.0: TypeError: Cannot set property 'inViewTarget' of undefined

Hey! Great module!

However, I'm getting an error with latest inview 1.4.0 on the following line:

$event.inViewTarget = element[0];

inview-exception

Sorry for I don't have enough time to isolate the issue properly.

1.3 branch works fine for me.

I'm using directive this way: <p in-view="pInView()">Something!</p>.

[NPM] angular-inview published as 1.5.0 is in fact 2.0-alpha1

it has the following banner:

// # Angular-Inview
// - Author: [Nicola Peduzzi](https://github.com/thenikso)
// - Repository: https://github.com/thenikso/angular-inview
// - Install with: `bower install angular-inview`
// - Version: **2.0-alpha1**

Could you please release the right version?

[2.0] offset cannot be defined

any attempt to create an offset results in TypeError: Illegal invocation.
It is so due to the fact that in offsetRect an attempt to write read-only properties of ClientRect is made.
ClientRect properties are getters but setters are not defined.

inview elements dynamically?

Hi there, is there a way to pick the item for in-view dynamically? If yes, could you document it, if no, might it be a future thingie?

Usage of directive is unreliable when using viewport CSS units (vh,vmin,vmax)

In my website I've got a header with a height of 100vh. Below the header is a list of items I use the in-view directive on. I found that it incorrectly triggered the in view events.

After some debugging I found out that using the 100vh css unit produces unreliable results for the getBoundingClientRect() method. It returned this value:

{
  bottom: 58,
  height: 102,
  left: 144.5,
  right: 320.5,
  top: -44,
  width: 176
}

When I change the header to use a percentage unit (100%) the values are far more reliable:

{
  height: 102,
  width: 176,
  left: 144.5,
  bottom: 955,
  right: 320.5
}

This bug occurs on Chrome Version 41.0.2272.104 (64-bit) on Mac OS 10.10.2 (Yosemite).

inViewOffset relative to scroll height?

Would be a very useful feature to specify the offset relative to the scrollable area height, so, if for example, the scroll area height is 300px then indicating in-view-offset-rel="[-1,1]" the offset should be -300px and 300px. And if i use in-view-offset-rel="[-0.5,0.5]" then the offset should be -150px and 150px. This way, if the scrollable area changes it's size the offset keeps working anyway… What do you think? do you think that something like this could be added to angular-inview?

thanks,

Unregister inview from an element?

I use the this component to lazy load images. When the image is loaded, I don't need any updates anymore (e.g.the element left the viewport or entered again).
Can you add a support to unregister from the event or call the inview callback just once?

Thanks in advance!

package.json is missing

Hello!

Could you please create a package.json file and specify build and test dependencies in it? Right now it's not that easy to setup a development environment out of the plain clone.

Thanks!

pass $element within inViewFunc()

related to #9 comment

we should be able to access DOM $element within the inViewFunc
aka

              return this.scope.$apply(function() {
              return inViewFunc(_this.scope, {
                '$inview': $inview,
                '$inviewpart': $inviewpart,
                '$element':_this.element
              });
            });

angular 1.2.0 compatibility issue

I've tried the directive with angular#1.2.0-rc.2, the expression fires correctly whenever the DOM element enter or quit the view, but the $inview value is always true.

when using offset, the first element does not call the callback

Hi,

First of all, thanks for your work on this plugin. Very usefull.
A little issue :

When I use the offset option, in-view-offset="-300", the first element is in view but if he is lower than 300px in height, the callback is not called. I just want that the elements trigger the callback 300px before being in view but the first one has to trigger the callback also.. Don't know if it's understandable..

Thanks in advance for your answer :)

Cheers man !

Exit View

Is there something that can be watched for when the parent element exits the view?

How to manually trigger the inview check?

Reading through the code I noticed that the inview check gets triggered at link time & when scrolling the page. But I'm wondering how I should trigger the check manually.

in-view directive not triggering unless click event follows for absolutely-positioned container scrolling

The name says most all of what's happening.

I discovered this directive and used it to solve an issue where I needed lots of instances of Angular Bootstrap's popup-datepicker, which has VERY terrible init time, so this avoided instantiating dozens of times and locking up the browser.

At some point after getting around to styling the page, (I just noticed this so I can't pinpoint a cause) in-view stopped triggering for overflow scrolling of the container.

When this did work, I never even thought to add an in-view-container attribute on the overflowed element, but now I have. No change.

Even stranger, I have been able to trigger in-view expressions by clicking on the page after scrolling. I can wait arbitrary periods of time and it will not fire until I've clicked.

Any idea what might be going on? I haven't looked into alternatives and admit I haven't dug into the internals yet.

Thanks!

IE8

Don't kill me! But seems like this directive does not work with IE8 with Angularjs JS 1.2.16. I have all my other directives working after following the ajs guides. I know it's not officially supported, but if you have any ideas on what may be causing it, would appreciate any insights. I'll spend some time later to try to fix it and submit a pull-request if I figure it out.
I used a test virtual machine from modern.ie (Win7 + IE8 + VirtualBox)

Thanks for the awesome directive.

Does not play well with fixed position divs with overflow

Great plug in.

Consider a fixed height div with overflow:

<div style="height: 100px; overflow-y: scroll; position: fixed;" ng-repeat="thumb in thumbs">
  <img ng-src="{{thumb.uri}}" in-view="detectThumbInView($index, $inview, $inviewpart)">
</div>

With the inview function:

$scope.detectThumbInView = function(index,inView,position) {
  console.log(index,inView,position);
}

Two problems:

  1. The user scrolling within the div does not trigger detectThumbInView at all
  2. Scroll the div so the original images when the page was rendered are no longer in view. Now scroll the main window. The method logs out to the console the index of the images originally in view when the page was rendered, not the current images in view.

$inview allways true (horizontal scrolling)

In my case the body is set to height: 100% and I'm using the attribute in-view="show = $inview" but when I log {{show}} it's always true. My items are display: inline-block and I made sure that my window triggers the scroll event.

When I change my css to vertical scrolling it works well! Is there any setting I have to change?

Thanks,
Florian

Combine with animate.css or nganimate

it is possible to use this module with animate.css or nganimate to produce a fade to the element ".text-headline"?

<h1 in-view="inviewHandler($inview, 'text-headline')" class="text-headline">Hola</h1>

Thanks in advance.

allow for in-view-offset as a percentage of viewport

instead of just a numerical value, allow a user to trigger the inview callback after the item in question has reached, for example, the top 50% of the viewport.

In this case, in-view-offset could be a percentage based on the bottom or top offset of the screen.

$hasBeenInView? property

I think it would be a welcome addition to track whether or not an element with the in-view attribute has been in view at least once.

This way, I could have a callback function that only executes once [per session]:

.button(in-view='!$hasBeenInView && $inview && doSomething()')

Not triggering after collection changed

I have a div element with in-view inside a ng-repeat but when the div updates, the element does not call the function when it appears on viewport.

In fact, only the elements who are showing at page load are calling the function.

Any idea?

Error after latest angular 1.2.25 update

With angular 1.2.25 update this directive fails cause it has problems with DOM element passed as argument to controller. Can this issue be fixed to work with that angular version?

consider publishing to npm as well

Hope all is well :)

I currently manage https://github.com/angular-ui/angular-google-maps and I have support users who pull in our library via npm and bower. I was hoping to use your library as a dependency, but for the time being I will have to concat or wrap your library into mine. This is because I cannot add your lib as a dependency for npm. This would be very useful for users of webpack and or browserify.

$event.inViewTarget is not working

Using AngularJS 1.3.12 I get the following error:

Referencing DOM nodes in Angular expressions is disallowed! Expression: lineInView($index, $inview, $inviewpart, $event.inViewTarget)

Continuously scrolling is not responsive enough

Hi, first of all, thank you for creating this great module!
I noticed a possible bug: inview does not trigger until user does not stop scrolling. So if user is continuously scrolling (for example using touchpad on laptop), inview does not trigger. Can you confirm that is happening? Is that expected behaviour and limitation of angular inview, or a bug?
Thank you!

Should include npm instructions

The Installation instructions should include

npm install angular-inview

Also, https://www.npmjs.com/package/angular-inview doesn't link to this github page.

in view not working

I have implemented in-view directive in my code , but I just want the view-port displaying content to be on page, to decrease page load, does this directive help me to solve this issue??
the documentation is somehow weak, could you please put some sample working file?
I have my repeating blocks are several ng-repeat blocks

'neither' event not triggered

When an element is initially inview=true & inviewpart='top', scrolling till inview=true and neither top nor bottom of the element is inview will not trigger an event with inview=true & inviewpart='neither'.

Searching through the source code for 'neither' hits nothing.

It works incorrectly when used for infinite scrolling

I'm using this module to implement infinite scrolling feature.

I have a table and a "Show More" button below it. The content of the table is populated dynamically when client clicks on the button. I'm adding in-view directive to the button in order to trigger loading of additional rows.

I'm getting the weird result: when you reach button for the first time - it's OK, event is triggered and additional rows are added to the table. But as soon as you scroll a little further - the event is triggered again, however the button is not in the viewport at all. It looks like it remembers the old position of the button (before additional rows are added to the table) or something. I'm not sure what is the actual issue. It must be related to implementation details.

If time permits, I will be able to reconstruct the issue using Plunker.

Lagging on scroll list

I have a long list, if i scroll the list the list is lagging. The in view attr is on all list items.

Wrong branch on NPM

Running npm install angular-inview installs what is purportedly version 1.5.0, but is in fact 2.0-alpha1.

2.0-alpha1 doesn't work properly (debounce, $event and $inviewpart are all broken. This caused a couple of hours of wasted time for me as I tried to figure out if it was a problem with my code that was causing the issue.

Perhaps you could try releasing 1.5.1 with no changes and seeing if that updates npm?

Window bindings

The plugin binds to the window, even before the directive is called.
angular.element(window).bind('checkInView click ready scroll resize', checkInViewDebounced);

These events should probably be bound when the directive is first called and removed when the last directive us destroyed.

Upgrading to v1.4

Hi,

After upgrading I get an error, which is normal because I saw the breaking change in the code.

Anyway, I don't know how to upgrade to the latest version and I don't want to be stuck at v1.3

Here is my code:

div.row(in-view="visible = $inview")

the expression visible would then be used later for nested divs

Tests fails for 1.4.2

Hello!

I've cloned the repo and launched karma tests and some of them failed for me.

Here's the log:

INFO [karma]: Karma v0.12.24 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 38.0.2125 (Linux)]: Connected on socket htxSxdWvp5nLxjx9kfQk with id 9414609
Chrome 38.0.2125 (Linux) Directive: inViewContainer should fire inview with windows scroll FAILED
    Expected 7 to equal 6.
    Error: Expected 7 to equal 6.
        at /home/sfomin/angular-inview/test/angular-inview.spec.js:136:51
        at null.<anonymous> (/home/sfomin/angular-inview/test/angular-inview.spec.js:30:18)
    Expected spy inviewSpy to have been called with [ 21, true, 'top' ] but actual calls were [ 10, true, 'both' ], [ 11, true, 'top' ], [ 20, true, 'both' ], [ 21, true, 'both' ], [ 22, true, 'top' ], [ 10, false, undefined ], [ 11, false, undefined ]
    Error: Expected spy inviewSpy to have been called with [ 21, true, 'top' ] but actual calls were [ 10, true, 'both' ], [ 11, true, 'top' ], [ 20, true, 'both' ], [ 21, true, 'both' ], [ 22, true, 'top' ], [ 10, false, undefined ], [ 11, false, undefined ]
        at /home/sfomin/angular-inview/test/angular-inview.spec.js:138:45
        at null.<anonymous> (/home/sfomin/angular-inview/test/angular-inview.spec.js:30:18)
Chrome 38.0.2125 (Linux) Directive: inViewContainer should trigger inview with container scroll for all nested children FAILED
    Expected spy inviewSpy to have been called with [ 22, true, 'top' ] but actual calls were [ 21, true, 'bottom' ], [ 22, true, 'both' ]
    Error: Expected spy inviewSpy to have been called with [ 22, true, 'top' ] but actual calls were [ 21, true, 'bottom' ], [ 22, true, 'both' ]
        at /home/sfomin/angular-inview/test/angular-inview.spec.js:149:43
        at null.<anonymous> (/home/sfomin/angular-inview/test/angular-inview.spec.js:30:18)
Chrome 38.0.2125 (Linux) Directive: inViewContainer in fixed containers should properly handle fixed positioned containers FAILED
    Expected 3 to equal 2.
    Error: Expected 3 to equal 2.
        at /home/sfomin/angular-inview/test/angular-inview.spec.js:162:49
        at null.<anonymous> (/home/sfomin/angular-inview/test/angular-inview.spec.js:30:18)
    Expected 6 to equal 5.
    Error: Expected 6 to equal 5.
        at /home/sfomin/angular-inview/test/angular-inview.spec.js:168:51
        at null.<anonymous> (/home/sfomin/angular-inview/test/angular-inview.spec.js:30:18)
Chrome 38.0.2125 (Linux): Executed 8 of 8 (3 FAILED) (1.837 secs / 1.825 secs)

I've tried both master and v1.4.2 revision.

Please advise, thanks!

Chrome 32 offsetTop function behaviour not as expected - scrollTop doubled up

On Chrome 32 the value of scrollTop is duplicated for the body and html tags.

In the offsetTop() method, which iterates up an element's parents we have:

    offsetTop = function(el) {
        var parent, result;
...
       parent = el.parentElement;
...
        while (parent) {
            if (parent.scrollTop != null) {
                result -= parent.scrollTop;
            }
            parent = parent.parentElement;
        }

I inserted some debug to see what the various browsers's report of the scrollTop would be.

Chrome 32:

DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, SECTION:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, BODY:877, HTML:877

You can see here Chrome reports the offset twice, once for BODY and again for HTML

In FF 26:

DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, SECTION:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, BODY:0, HTML:756

You can see this is reported just for HTML.

In Safari 6.0.5, it's just for body:

DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, SECTION:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, DIV:0, BODY:7980, HTML:0

The problem is in Chrome the scrollTop is double counted and thus introduces erroneous results with the in-view directive.

Plugin breaks when minified.

This is because of the dependency injection.

For example:

controller: function($scope) {
should be
controller: ['$scope', function($scope) {
and so on.

in-view-offset has no effect

Ive treid using the in-view-offset with various numbers 1, 10, 100, 1000, 10000 and get the same results every time.

I guess its not working?

Example:
in-view="$myvar = $true" in-view-offset="100000"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.