Make function wait until element exists

前端 未结 11 1847
一向
一向 2020-11-28 17:40

I\'m trying to add a canvas over another canvas – how can I make this function wait to start until the first canvas is created?

function PaintObject(brush) {         


        
相关标签:
11条回答
  • 2020-11-28 18:07

    Here is a solution using observables.

    waitForElementToAppear(elementId) {                                          
    
        return Observable.create(function(observer) {                            
                var el_ref;                                                      
                var f = () => {                                                  
                    el_ref = document.getElementById(elementId);                 
                    if (el_ref) {                                                
                        observer.next(el_ref);                                   
                        observer.complete();                                     
                        return;                                                  
                    }                                                            
                    window.requestAnimationFrame(f);                             
                };                                                               
                f();                                                             
            });                                                                  
    }                                                                            
    

    Now you can write

    waitForElementToAppear(elementId).subscribe(el_ref => doSomethingWith(el_ref);
    
    0 讨论(0)
  • 2020-11-28 18:07

    Just use setTimeOut with recursion:

    waitUntilElementIsPresent(callback: () => void): void {
        if (!this.methodToCheckIfElementIsPresent()) {
            setTimeout(() => this.waitUntilElementIsPresent(callback), 500);
            return;
        }
        callback();
    }
    

    Usage:

    this.waitUntilElementIsPresent(() => console.log('Element is present!'));
    

    You can limit amount of attempts, so an error will be thrown when the element is not present after the limit:

    waitUntilElementIsPresent(callback: () => void, attempt: number = 0): void {
        const maxAttempts = 10;
        if (!this.methodToCheckIfElementIsPresent()) {
            attempt++;
            setTimeout(() => this.waitUntilElementIsPresent(callback, attempt), 500);
            return;
        } else if (attempt >= maxAttempts) {
            return;
        }
        callback();
    }
    
    0 讨论(0)
  • 2020-11-28 18:15

    If you have access to the code that creates the canvas - simply call the function right there after the canvas is created.

    If you have no access to that code (eg. If it is a 3rd party code such as google maps) then what you could do is test for the existence in an interval:

    var checkExist = setInterval(function() {
       if ($('#the-canvas').length) {
          console.log("Exists!");
          clearInterval(checkExist);
       }
    }, 100); // check every 100ms
    

    But note - many times 3rd party code has an option to activate your code (by callback or event triggering) when it finishes to load. That may be where you can put your function. The interval solution is really a bad solution and should be used only if nothing else works.

    0 讨论(0)
  • 2020-11-28 18:16

    Another variation of Iftah

    var counter = 10;
    var checkExist = setInterval(function() {
      console.log(counter);
      counter--
      if ($('#the-canvas').length || counter === 0) {
        console.log("by bye!");
        clearInterval(checkExist);
      }
    }, 200);
    

    Just in case the element is never shown, so we don't check infinitely.

    0 讨论(0)
  • 2020-11-28 18:18

    If you want a generic solution using MutationObserver you can use this function

    // MIT Licensed
    // Author: jwilson8767
    
    /**
     * Waits for an element satisfying selector to exist, then resolves promise with the element.
     * Useful for resolving race conditions.
     *
     * @param selector
     * @returns {Promise}
     */
    export function elementReady(selector) {
      return new Promise((resolve, reject) => {
        const el = document.querySelector(selector);
        if (el) {resolve(el);}
        new MutationObserver((mutationRecords, observer) => {
          // Query for elements matching the specified selector
          Array.from(document.querySelectorAll(selector)).forEach((element) => {
            resolve(element);
            //Once we have resolved we don't need the observer anymore.
            observer.disconnect();
          });
        })
          .observe(document.documentElement, {
            childList: true,
            subtree: true
          });
      });
    }
    

    Source: https://gist.github.com/jwilson8767/db379026efcbd932f64382db4b02853e
    Example how to use it

    elementReady('#someWidget').then((someWidget)=>{someWidget.remove();});
    

    Note: MutationObserver has a great browser support; https://caniuse.com/#feat=mutationobserver

    Et voilà ! :)

    0 讨论(0)
提交回复
热议问题