Viewing 7 replies - 1 through 7 (of 7 total)
  • Anonymous User 14254218

    (@anonymized-14254218)

    The script seems to be enqueued correctly, but it is trying to obtain the element of your DOM with ID #myAnimation:

    
    document.getElementById("myAnimation");
    

    There is no such element, therefore it does nothing.

    A general issue I find on most tutorials regarding custom scripts and styles is, that people tend to forget to register them before enqueueing.

    It is not necessary to register the script but it helps with structuring your code.
    StackExchange: When should I use wp_register_script() with wp_enqueue_script() vs just wp_enqueue_script()?

    
    add_action( 'wp_enqueue_scripts', function () {
        wp_register_script('custom_js', 'url/to/custom-js-1.0.js', array('jquery'), '1.0', true);
        wp_enqueue_script('custom_js');
    });
    

    see:

    If you enqueue your script in the footer (see last parameter of wp_register_script/wp_enqueue_script) you most likely do not need to wait for document.ready.

    Thread Starter kasiaw

    (@kasiaw)

    Thank you for your answer. I haven’ digged into “wp_register_script” yet, but as I understand it is not crutial in my situaton.

    I am afraid you have looked at the page at the time, I was moving the js part to another page from the home page (that I could work on the home page design and try to solve js problem at the same time).

    JS code is now here: https://mozolewska.pl/kdk/javascript-test/

    It is still not working, but now I receive error from the console:
    Uncaught ReferenceError: myMove is not defined
    at HTMLButtonElement.onclick

    although it is defined in animache.js file (this error haven’t occured before).

    The difference is, that now I am using defult templete (and before I was using custom front-page template) and the html code was in the front-page template file, and now it is in WordPress editor.

    Anonymous User 14254218

    (@anonymized-14254218)

    You should not use the onclick attribute since it is considered poor practice and it performs in a different scope which will lead to errors.

    You most likely would have to define the whole function in your onclick attribute or use the proper way and use EventListener.

    If you want to call a function on click, query the element (e.g. by giving it a class or unique id) and add a listener of type click.

    Thread Starter kasiaw

    (@kasiaw)

    I am sure you are right about the code. I don’t know a thing about Java Script.
    But I think my biggest problem now is that I am not able to run any “new” JS code on my website. Now I am testing this example: https://morioh.com/p/bd6b4702d394

    But still nothing: https://mozolewska.pl/kdk/javascript-test/

    Anonymous User 14254218

    (@anonymized-14254218)

    For the mods and following users reading this thread:
    This is not an issue related to the theme or WordPress.

    That being said:
    Your issue is related to the location of your script and the way it is loaded. Yes, simple as that ??

    The issue:
    Since browsers render the DOM from top to bottom, the browser will load your script at the moment it encounters it. Since the script is not deferred (see <script>: The Script element) and loaded in the head, it will fully load and execute your script before continuing with the DOM.
    This means the script will run, search for “.counter” elements, won’t find any (since they are not loaded yet) and in the end it quits so the browser can continue rendering the DOM.

    General notes about loading scripts and resources:
    1. Scripts can (and should) be loaded asynchronously or at least at the very end to avoid render blocking threads.
    2. If you need a script to do something with the content of your page, the script will have to be deferred, loaded at the very end (the footer) or listen to the “DOMContentLoaded” element and handle the functions and actions there.

    To simplify my answer I provide a probably “cleaner” (at least in my opinion) solution to the JS code you try to accomplish. Simply put this script in your custom js file and it should run as expected.

    
    /**
     * Animates the counter of the provided element with the given settings.
     * Requires the data-target attribute to be present for the given element.
     *
     * @param {Node|Element} counterElement The element to animate
     * @param {number} speedInMillis The time the animation will take in millis
     * @param {number} fps The fps of the animation
     * @see https://www.ads-software.com/support/topic/problems-with-custom-js-file-in-child-theme/
     */
    function animiateCounter(counterElement, speedInMillis = 1000, fps = 30) {
        // check preconditions
        if (
            !counterElement ||
            !counterElement.hasAttribute("data-target") ||
            fps < 1
        ) {
            // quit if preconditions not met
            return;
        }
    
        // determine initial value from element
        let value = +counterElement.innerText;
    
        // determine target value from attribute
        const targetValue = +counterElement.getAttribute("data-target"),
            // define the interval timeout
            intervalTimeout = (speedInMillis / fps) >> 0,
            // define by how much the value should be incremented
            incrementBy = ((target - value) / intervalTimeout) >> 0,
            // define the interval to animate the counter
            incrementorInterval = setInterval(() => {
                // value exceeds the target value, so interrupt the counter
                if (value >= targetValue) {
                    // clear the interval
                    clearInterval(incrementorInterval);
                    // quit here
                    return;
                }
    
                // increment the value (max out at target value)
                value = Math.min(value + incrementBy, targetValue);
    
                // request animation frame to paint the value
                window.requestAnimationFrame(
                    () => (counterElement.textContent = value)
                );
            }, intervalTimeout);
    }
    
    // wait for the dom content to be loaded
    document.addEventListener("DOMContentLoaded", (event) => {
        document
            // query the counter elements
            .querySelectorAll(".counter")
            // animate each queried counter
            // change the animation values here as needed
            .forEach((counterElement) => animiateCounter(counterElement, 1000, 30));
    });
    

    You can change the animation speed and the number of frames/steps by passing the corresponding arguments to the function at the very end.

    Simply change this line to your liking by adjusting the duration of the animation (in this case 1000) and/or the fps (in this case 30).

    
    .forEach((counterElement) => animiateCounter(counterElement, 1000, 30));
    
    Anonymous User 14254218

    (@anonymized-14254218)

    Just noticed a little error in my math. I think this is good now.

    
    /**
     * Animates the counter of the provided element with the given settings.
     * Requires the data-target attribute to be present for the given element.
     *
     * @param {Node|Element} counterElement The element to animate
     * @param {number} speedInMillis The time the animation will take in millis
     * @param {number} fps The fps of the animation
     * @see https://www.ads-software.com/support/topic/problems-with-custom-js-file-in-child-theme/#post-13831350
     */
    function animiateCounter(counterElement, speedInMillis = 1000, fps = 30) {
        // check preconditions
        if (
            !counterElement ||
            !counterElement.hasAttribute("data-target") ||
            fps < 1
        ) {
            // quit if preconditions not met
            return;
        }
    
        // determine initial value from element
        let value = +counterElement.innerText;
    
        // determine target value from attribute
        const targetValue = +counterElement.getAttribute("data-target"),
            // define the interval timeout
            intervalTimeout = (1000 / fps) >> 0,
            // define by how much the value should be incremented
            incrementBy =
                ((targetValue - value) /
                    ((speedInMillis / 1000) * intervalTimeout)) >>
                0,
            // define the interval to animate the counter
            incrementorInterval = setInterval(() => {
                // value exceeds the target value, so interrupt the counter
                if (value >= targetValue) {
                    // clear the interval
                    clearInterval(incrementorInterval);
                    // quit here
                    return;
                }
    
                // increment the value (max out at target value)
                value = Math.min(value + incrementBy, targetValue);
    
                // request animation frame to paint the value
                window.requestAnimationFrame(
                    () => (counterElement.textContent = value)
                );
            }, intervalTimeout);
    }
    
    // wait for the dom content to be loaded
    document.addEventListener("DOMContentLoaded", (event) => {
        document
            // query the counter elements
            .querySelectorAll(".counter")
            // animate each queried counter
            // change the animation values here as needed
            .forEach((counterElement) => animiateCounter(counterElement, 1000, 30));
    });
    
    Thread Starter kasiaw

    (@kasiaw)

    Thank you very much for all your help!

    I have followed all your suggestions (registered script, placed it in the footer) and for now my problems seem to be solved.

    And thank you for the counter code as well!

    I hope it is not against forum rules to wish you all the best in the New Year! ??

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘Problems with custom JS file in child theme’ is closed to new replies.