GithubHelp home page GithubHelp logo

uzairfarooq / arrive Goto Github PK

View Code? Open in Web Editor NEW
869.0 24.0 100.0 187 KB

Watch for DOM elements creation and removal

License: MIT License

JavaScript 95.54% HTML 0.89% CSS 3.57%
javascript dom jquery dynamic watch mutation-observers listen detect livequery nodejs

arrive's Introduction

arrive.js

CDNJS version

arrive.js provides events to watch for DOM elements creation and removal. It makes use of Mutation Observers internally.

Download arrive.min.js (latest)

or use Bower to install:

# install arrive.js and add it to bower.json dependencies
$ bower install arrive --save
Node.js / NPM

Node.js users can install using npm:

$ npm install arrive --save

Usage

Watch for elements creation

Use arrive event to watch for elements creation:

// watch for creation of an element which satisfies the selector ".test-elem"
document.arrive(".test-elem", function(newElem) {
    // newElem refers to the newly created element
});

// the above event would watch for creation of element in whole document
// it's better to be more specific whenever possible, for example
document.querySelector(".container-1").arrive(".test-elem", function(newElem) {
});

// you can bind event to multiple elements at once
// this will bind arrive event to all the elements returned by document.querySelectorAll()
document.querySelectorAll(".box").arrive(".test-elem", function(newElem) {
});

Make sure to remove listeners when they are no longer needed, it's better for performance:

// unbind all arrive events on document element
document.unbindArrive();

// unbind all arrive events on a specific element
document.querySelector(".box").unbindArrive();

// unbind all arrive events on document element which are watching for ".test-elem" selector
document.unbindArrive(".test-elem");

// unbind only a specific callback
document.unbindArrive(callbackFunc);

// unbind only a specific callback on ".test-elem" selector
document.unbindArrive(".test-elem", callbackFunc);

// unbind all arrive events
Arrive.unbindAllArrive();

Options

As of v2.0 arrive event accepts an optional options object as 2nd argument. Options object consists of following:

var options = {
    fireOnAttributesModification: boolean, // Defaults to false. Setting it to true would make arrive event fire on existing elements which start to satisfy selector after some modification in DOM attributes (an arrive event won't fire twice for a single element even if the option is true). If false, it'd only fire for newly created elements.
    onceOnly: boolean                      // Defaults to false. Setting it to true would ensure that registered callbacks fire only once. No need to unbind the event if the attribute is set to true, it'll automatically unbind after firing once.
    existing: boolean                      // Defaults to false. Setting it to true would ensure that the registered callback is fired for the elements that already exist in the DOM and match the selector. If options.onceOnly is set, the callback is only called once with the first element matching the selector.
};

Example:

document.arrive(".test-elem", {fireOnAttributesModification: true}, function(newElem) {
    // 'newElem' refers to the newly created element
});

Watch for elements removal

Use leave event to watch for elements removal. The first arugument to leave must not be a descendent or child selector i.e. you cannot pass .page .test-elem, instead, pass .test-elem. It's because of a limitation in MutationObserver's api.

// watch for removal of an element which satisfies the selector ".test-elem"
document.querySelector(".container-1").leave(".test-elem", function(removedElem) {
    // 'removedElem' refers to the newly removed element
});

You can unbind the leave event in the same way as arrive event, using unbindLeave function i.e:

// unbind all leave events on document element
document.unbindLeave();

// unbind all leave events
Arrive.unbindAllLeave();

jQuery Support

If you use jQuery, you can call all arrive functions on jQuery elements as well:

// watch for element creation in the whole HTML document
$(document).arrive(".test-elem", function(newElem) {
  // Note: newElem is a javascript element not a jQuery element
});

// this will attach arrive event to all elements returned by $(".container-1")
$(".container-1").arrive(".test-elem", function(newElem) {
  // Note: newElem is a javascript element not a jQuery element
});

Browser Support

arrive.js is built over Mutation Observers which is introduced in DOM4. It's supported in latest versions of all popular browsers.

Browser Supported Versions
Google Chrome 27.0+
Firefox 14.0+
Safari 6.1+
Internet Explorer 11.0+
Opera 14.0+

Contributing

Report a bug / Request a feature

If you want to report a bug or request a feature, use the Issues section. Before creating a new issue, search the existing ones to make sure that you're not creating a duplicate. When reporting a bug, be sure to include OS/browser version and steps/code to reproduce the bug, a JSFiddle would be great.

Development

If you want to contribute to arrive, here is the workflow you should use:

  1. Fork the repository.
  2. Clone the forked repository locally.
  3. From the dev branch, create and checkout a new feature branch to work upon. (If you want to work on some minor bug fix, you can skip this step and continue to work in dev branch)
  4. Make your changes in that branch (the actual source file is /src/arrive.js).
  5. If sensible, add some jasmine tests in /tests/spec/arriveSpec.js file.
  6. Make sure there are no regressions by executing the unit tests by opening the file /tests/SpecRunner.html in a browser. There is a button 'Run tests without jQuery' at the top left of th page, click that button to make sure that the tests passes without jQuery. Run the test cases in all major browsers.
  7. Push the changes to your github repository.
  8. Submit a pull request from your repo back to the original repository.
  9. Once it is accepted, remember to pull those changes back into your develop branch!

Some features/bugs you can send pull requests for

  • #70: Add Typescript types to the project
  • #69: Option to watch for text change
  • #64: Function firing twice in Firefox 56 on 2.4.1 (regression from bug 54)
  • #60: Issue when expose arrive API to window

Keywords

javascript, js, jquery, node.js, watch, listen, creation, dynamically, removal, new, elements, DOM, dynamic, detect, insertions, event, bind, live, livequery

arrive's People

Contributors

aymericbeaumet avatar beenotung avatar extend1994 avatar ferrybig avatar handtrix avatar madtaras avatar ryneeverett avatar uzairfarooq avatar youngyou 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

arrive's Issues

Recursive Unbind

This is a proposal for an unbindArrive option:

$(document).unbindArrive(".test-elem", {recursive: true}, callbackFunc);

which would remove all bindings to document and it's children (meeting the selector/handler criteria).

HTMLElement.matches in old Opera

I think Arrive.js will not work in Opera 11.5-20 because these browser versions has "matches" function only with "o" prefix (Element.prototype.oMatchesSelector or maybe HTMLElement.prototype.oMatchesSelector)

image
image
image

How to import from npm?

There is no example how to correctly import it when using npm, is it: import arrive from "arrive"; ?

Feature request: respond to arrival of multiple elements

I'm writing code that should run when two specific elements both exist. They could be created in any order. I'd like to do something like this:

document.arrive(['.first', '.second'], function() { ... })

or perhaps this:

document.arrive({first: '.first', second:'.second'}, function() { 
  const first = this.first; 
  const second = this.second;
})

Any interest in adding this sort of thing, or is there a straightforward workaround?

why it rescan elements exponentially?

sorry, maybe it's newbie question, i'm not good at programming. i trying to write script for browser extension tampermonkey that filtering some elements and noticed that 'arrive' processed already existing elements
this page aliespress coupon center show 20 elements, when you scroll down it show another 20 and etc. (20, 40, 60, 80...) but 'arrive' processed exponentially:
20_40__60__80__100_120... <- elements on page
20_60_120_200_300_420... <- 'arrive' processed
so it sum up diagonally '/' (0+20=20, 20+40=60, 60+60=120, 120+80=200...)
tampermonkey simple script i used to check this

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://campaign.aliexpress.com/wow/gcp/ae/channel/ae/accelerate/tupr*
// @require      https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @run-at       document-body
// ==/UserScript==

(function() {
    'use strict';

    let i=0;
    document.arrive('div[exp_type="coupon_exposure"]', function () {
        i++;
/*        if (isInteger(i/2)) {
            this.remove();
        }
*/
        if (isInteger(i/20)) {
            alert(document.querySelectorAll('div[exp_type="coupon_exposure"]').length + ' elements on page\n' + i + ' document.arrive processed');
        }
    });

function isInteger(num) {
  return (num ^ 0) === num;
}

})();

if remove some elements from page (commented 'this.remove'), like every 2nd, the sequence will remain 20_60_120_200_300_420...
is it normal or not? when i use filtering action in script it will do its actions again and again on the same elements :/

Cannot read property '0' of undefined

I couldn't possibly give steps to repro. It's a site you need to be logged into, with another script creating the element in question. All I know is it used to work fine. Not sure if it's a browser update, or a TamperMonkey update, or what, but one day it quit working and started throwing this error. I was able to work around it by delaying the injection of the element in question.

Good chance it's either TM in general, or some setting, because the original script still appears to work fine in ViolentMonkey. At any rate, it strikes me as an error which should never really occur, so perhaps it could be accounted for regardless.

arrive

Watching for multiple elements

It seems like when making two calls to arrive, the latter overwrites the former.

$(document).arrive("#foo", function() {});
$(document).arrive("#bar", function() {}); // this overwrites the first

Even when using document on one and window on the other, the first one is overwritten.
Is this expected behavior?
Can I watch for two separate elements somehow?

Detect page title change

I throught that this code will execute every time when page is changing. I was fear it can trigger itself, because it executes a function that changes itself, but it didn't work at all (for example, if I just call removeCapsFromElement(document.querySelector("title")) I can see it's changing for a split second, but when I replace it by

document.arrive( "title", {fireOnAttributesModification: true}, pageName => removeCapsFromElement(pageName))

, it doesn't work at all. Where is my mistake?

Fire only once, total

I don't think the { onceOnly: boolean } option works the way i want. I think it applies to each element it finds in the selector. I don't want this, I want something that I don't think the library can do: I want the observer to fire only once, regardless of how many elements I set it on.

e.g.,

$(document).arrive("li", { fireOnce: true}, function() {
   // tell me the FIRST TIME a li element shows up.
});

This is useful because I don't want to fire it until a li is visible on the page, but I also don't want to run the body of the function more than once.

Honestly, this and a lot of other useful features could be used if the API let you pass in a jquery instead of a string.

$(document).arrive($("li").first(), function() {
   // tell me the FIRST TIME a li element shows up.
});

Of course, the library is a black box to me, and I don't know if that's a feasible implementation.

arrive.js with iframes?

I have a parent page that embeds a child iframe. I set up arrival listeners for elements in child iframe; however, these listeners are never called. Is it possible to use arrive.js with iframes?

P.S. I'm running google-chrome --disable-web-security to bypass same-origin checks.

'HTMLDocument' is undefined

SCRIPT5009: Unhandled exception at line 16, column 408 in ms-appx://xXx/js/third_party/arrive-2.0.0.min.js
0x800a1391 - JavaScript runtime error: 'HTMLDocument' is undefined
File: arrive-2.0.0.min.js, Line: 16, Column: 408

Watch for multiple classes

Hi Uzair, it's a nice library that you have developed, Unfortunately, I just found it today and needed it badly in the projects that I already developed. Your library could have saved a lot of hours :).

I just checked it for an element which contains multiple class names, but it didn't fire. Am I doing it right?

$(document).leave(".jfk-butterBar .jfk-butterBar-info .jfk-butterBar-shown", function() {
var $removedElem = $(this);
alert('loaded');
})

arrive.js not triggering consistently

Thanks for this library; it has made things much easier to work with compared to raw mutation observers and mutation-summary.

I am presently making heavy use of arrive.js calls in the early stages of a Chrome extension rewrite and find that sometimes arrive.js is missing the changes. In these situations, often if I restart Chrome it works again. I know that there are a lot of changes that I can make to improve performance (combine redundant arrive.js calls, scope them to more specific parents instead of document.body, cancel them when I know that they are no longer relevant, and maybe drop down to raw mutation observers in certain circumstances. but I am wondering if you have any information about Chrome limitations with respect to using a large number of mutation observers and if the behavior that would occur in such a circumstance matches the behavior I am experiencing.

Add an option to automatically unbind arrive events after firing once

I often do this to unbind event after they fire once:

document.arrive(".test", function() {
  document.unbindArrive(".test");
});

but this could fire arrive event more than once if multiple elements are injected at the same time. Something like this would be better:

document.arrive(".test", { onlyOnce: true }, function() {
  // no need to unbind, it should be unbinded automatically after firing once
});

issue when expose arrive API to window

hi, and thanks for your wrapper library over Mutation Observers
we use arrive.js in one site, and when trying to expose the arrive API in window, we get the error bellow:

// the call in arrive.js line 441:
exposeApi(window.prototype);

// the error:
Uncaught TypeError: Cannot set property 'arrive' of undefined
    at Object.exposeApi (arrive.js:427)
    at eval (eval at <anonymous> (arrive.js:440), <anonymous>:1:1)
    at arrive.js:440
    at Object.r.1 (arrive.js:449)

it seems that the window.prototype is undefined. why this may happen? Is there any way to override this property of window object?

is there any workaround on this? maybe using Window.proto instead will fix it?

unbindArrive by selector doesn't work

Example:
document.arrive('.some_class', {existing: true}, function () { if (some_trigger) document.unbindArrive('.some_class') }

After unbinding event still fires.

The first argument to 'leave' event should be optional

So, to listen for removal of .test-elem, one can simply write:

$(".test-elem").leave(function() {
    var removedElem = this;
});

instead of:

$(".container-1").leave(".test-elem", function() {
    var removedElem = this;
});

Error in readme.md

It says getElementsByClass, but it should probably say getElementsByClassName.

jQuery selectors are not supported

If you use $.arrive('any jquery selectors') that are not explicitly supported by matchesSelector function you will get an error
For example div:contains("Title") or div:first

Could you please fix this?

Possible Human Error |

Hello! So I am having the issue where even once the element appears it does not fire. I am not sure if it is my fault, but to my knowledge it is 100% fine. To make your life easier, it is currently on my site test.mylitenup.net | Use the username "s" which will allow you to see the Enroll Now button which should be firing the arrive but it doesn't and this is thrown to the console "Uncaught DOMException: Failed to execute 'matches' on 'Element'".

Feature suggestion: Add timeout

It would be great to add a timeout option in arrive.js.
For example, if the element does not appear in the first 15 seconds, call the timeout() callback

Promise and Async/Await Support

Not sure if this is possible, or if it is already implemented. It would be nice to use Async/Await with this library.

Example

const element = await document.arrive('#elementId', {onceOnly: true, existing: true});
// do stuff with element

Instead of this:

document.arrive('#elementId', {onceOnly: true, existing: true}, function() {
  const element = this;
  // do stuff with element
});

Remove dependency on jquery-2.1.0.min.js

I want to publish a Firefox extension using this library but I got this:
This add-on uses arrive.min.js library which contains jQuery version 2.1.0. jQuery versions older than 3.0 are no longer allowed in extensions. These versions are not supported by the jQuery team and may contain security vulnerabilities

Function firing twice in Firefox 56 on 2.4.1 (regression from bug 54)

I have the following (simplified) code in my userscript for xkcd.com, running at document-start (using GreaseMonkey).

document.arrive('ul.comicNav', { onceOnly: true, existing: true }, func); //from @require
function func() { 
 console.log('test');
}

Not even adding document.unbindArrive('ul.comicNav') or Arrive.undbindAllArrive() seems to stop this.

This suggests that, even though I am unbinding the Arrive (either automatically or explicitly), both ul.comic.Nav instances are still causing func() to fire.

I have done regression testing, and this behavior seems to be due to the fix for #54. Ironically, in Firefox, it seems to be causing the very thing you were trying to prevent in that bug.

Issue with binding to callback

When I bind to the callback function, the "this" variable isn't the element, its the window.

ie:

document.arrive(".my_class", function (item) {
   console.log(this, item);
}.bind(null, myItem))

The this variable is returned as the window object. Can this be fixed?

Use with webpack

Would love to be able to use this with webpack. Is that possible?

Can't get it to work in pure JS

import * as arrive from 'arrive/src/arrive.js';

$(document).arrive('.smthing', () => { console.log('bla'); }); works document.arrive('.smthing', () => { console.log('bla'); }); doesn't work

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.