0

I have 2 function that I am trying to run, one after another. For some reason they both run at the same time, but the second one does not load properly. Is there a way to run the first function wait then run the second function?:

//run this first
$('#abc').click(function() {
     $('.test1').show();
     return false;
  });  


//run this second
(function ($) {
    "use strict";
    // A nice closure for our definitions
    function getjQueryObject(string) {
        // Make string a vaild jQuery thing
        var jqObj = $("");
        try {
            jqObj = $(string)
                .clone();
        } catch (e) {
            jqObj = $("<span />")
                .html(string);
        }
        return jqObj;
    }

    function printFrame(frameWindow, content, options) {
        // Print the selected window/iframe
        var def = $.Deferred();
        try {
            frameWindow = frameWindow.contentWindow || frameWindow.contentDocument || frameWindow;
            var wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
            if(options.doctype) {
                wdoc.write(options.doctype);
            }
            wdoc.write(content);
            wdoc.close();
            var printed = false;
            var callPrint = function () {
                if(printed) {
                    return;
                }
                // Fix for IE : Allow it to render the iframe
                frameWindow.focus();
                try {
                    // Fix for IE11 - printng the whole page instead of the iframe content
                    if (!frameWindow.document.execCommand('print', false, null)) {
                        // document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
                        frameWindow.print();
                    }
                    // focus body as it is losing focus in iPad and content not getting printed
                    $('body').focus();
                } catch (e) {
                    frameWindow.print();
                }
                frameWindow.close();
                printed = true;
                def.resolve();
            }
            // Print once the frame window loads - seems to work for the new-window option but unreliable for the iframe
            $(frameWindow).on("load", callPrint);
            // Fallback to printing directly if the frame doesn't fire the load event for whatever reason
            setTimeout(callPrint, options.timeout);
        } catch (err) {
            def.reject(err);
        }
        return def;
    }

    function printContentInIFrame(content, options) {
        var $iframe = $(options.iframe + "");
        var iframeCount = $iframe.length;
        if (iframeCount === 0) {
            // Create a new iFrame if none is given
            $iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>')
                .prependTo('body')
                .css({
                    "position": "absolute",
                    "top": -999,
                    "left": -999
                });
        }
        var frameWindow = $iframe.get(0);
        return printFrame(frameWindow, content, options)
            .done(function () {
                // Success
                setTimeout(function () {
                    // Wait for IE
                    if (iframeCount === 0) {
                        // Destroy the iframe if created here
                        $iframe.remove();
                    }
                }, 1000);
            })
            .fail(function (err) {
                // Use the pop-up method if iframe fails for some reason
                console.error("Failed to print from iframe", err);
                printContentInNewWindow(content, options);
            })
            .always(function () {
                try {
                    options.deferred.resolve();
                } catch (err) {
                    console.warn('Error notifying deferred', err);
                }
            });
    }

    function printContentInNewWindow(content, options) {
        // Open a new window and print selected content
        var frameWindow = window.open();
        return printFrame(frameWindow, content, options)
            .always(function () {
                try {
                    options.deferred.resolve();
                } catch (err) {
                    console.warn('Error notifying deferred', err);
                }
            });
    }

    function isNode(o) {
        /* http://stackoverflow.com/a/384380/937891 */
        return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
    }
    $.print = $.fn.print = function () {
        // Print a given set of elements
        var options, $this, self = this;
        // console.log("Printing", this, arguments);
        if (self instanceof $) {
            // Get the node if it is a jQuery object
            self = self.get(0);
        }
        if (isNode(self)) {
            // If `this` is a HTML element, i.e. for
            // $(selector).print()
            $this = $(self);
            if (arguments.length > 0) {
                options = arguments[0];
            }
        } else {
            if (arguments.length > 0) {
                // $.print(selector,options)
                $this = $(arguments[0]);
                if (isNode($this[0])) {
                    if (arguments.length > 1) {
                        options = arguments[1];
                    }
                } else {
                    // $.print(options)
                    options = arguments[0];
                    $this = $("html");
                }
            } else {
                // $.print()
                $this = $("html");
            }
        }
        // Default options
        var defaults = {
            globalStyles: true,
            mediaPrint: false,
            stylesheet: null,
            noPrintSelector: ".no-print",
            iframe: true,
            append: null,
            prepend: null,
            manuallyCopyFormValues: true,
            deferred: $.Deferred(),
            timeout: 750,
            title: null,
            doctype: '<!doctype html>'
        };
        // Merge with user-options
        options = $.extend({}, defaults, (options || {}));
        var $styles = $("");
        if (options.globalStyles) {
            // Apply the stlyes from the current sheet to the printed page
            $styles = $("style, link, meta, base, title");
        } else if (options.mediaPrint) {
            // Apply the media-print stylesheet
            $styles = $("link[media=print]");
        }
        if (options.stylesheet) {
            // Add a custom stylesheet if given
            $styles = $.merge($styles, $('<link rel="stylesheet" href="' + options.stylesheet + '">'));
        }
        // Create a copy of the element to print
        var copy = $this.clone();
        // Wrap it in a span to get the HTML markup string
        copy = $("<span/>")
            .append(copy);
        // Remove unwanted elements
        copy.find(options.noPrintSelector)
            .remove();
        // Add in the styles
        copy.append($styles.clone());
        // Update title
        if (options.title) {
            var title = $("title", copy);
            if (title.length === 0) {
                title = $("<title />");
                copy.append(title);                
            }
            title.text(options.title);            
        }
        // Appedned content
        copy.append(getjQueryObject(options.append));
        // Prepended content
        copy.prepend(getjQueryObject(options.prepend));
        if (options.manuallyCopyFormValues) {
            // Manually copy form values into the HTML for printing user-modified input fields
            // http://stackoverflow.com/a/26707753
            copy.find("input")
                .each(function () {
                    var $field = $(this);
                    if ($field.is("[type='radio']") || $field.is("[type='checkbox']")) {
                        if ($field.prop("checked")) {
                            $field.attr("checked", "checked");
                        }
                    } else {
                        $field.attr("value", $field.val());
                    }
                });
            copy.find("select").each(function () {
                var $field = $(this);
                $field.find(":selected").attr("selected", "selected");
            });
            copy.find("textarea").each(function () {
                // Fix for https://github.com/DoersGuild/jQuery.print/issues/18#issuecomment-96451589
                var $field = $(this);
                $field.text($field.val());
            });
        }
        // Get the HTML markup string
        var content = copy.html();
        // Notify with generated markup & cloned elements - useful for logging, etc
        try {
            options.deferred.notify('generated_markup', content, copy);
        } catch (err) {
            console.warn('Error notifying deferred', err);
        }
        // Destroy the copy
        copy.remove();
        if (options.iframe) {
            // Use an iframe for printing
            try {
                printContentInIFrame(content, options);
            } catch (e) {
                // Use the pop-up method if iframe fails for some reason
                console.error("Failed to print from iframe", e.stack, e.message);
                printContentInNewWindow(content, options);
            }
        } else {
            // Use a new window for printing
            printContentInNewWindow(content, options);
        }
        return this;
    };
})(jQuery);

How would I run the first one wait 5 or so seconds and then run the jquery print? I'm having a hard time with this. So the id would run first and then the print would run adter the id="abc" Here is an example of the code in use:

<div id="test">
<button id="abc" class="btn" onclick="jQuery.print(#test1)"></button>
</div>
Xorifelse
  • 7,878
  • 1
  • 27
  • 38
user3683976
  • 121
  • 1
  • 7
  • 2
    there is a lot of code here, can you create a more minimal example that shows what problem you are facing? – Andrew Lohr Aug 13 '18 at 22:46
  • I second what @AndrewLohr said -- there's quite a bit of code here, and I get the feeling that not all of this code is necessary to reproduce the issue you are experiencing. – Jhecht Aug 13 '18 at 22:47
  • the first function is just collapsing content: $('#abc').click(function() { $('.test1').show(); return false; }); the second part of the code is a print functionality that prints to a pdf file. that part I understand. I'm just having issue with them running at the same time. I just want it to run the first wait 5 or so seconds before running the print functionality. I'm having a hard time with it. Both functions are running at the same time. – user3683976 Aug 13 '18 at 22:48
  • I'm with the guys here, there is a lot of code. Also, can you name the two functions that you want to run one after the other? – Alvaro Castro Aug 13 '18 at 22:49
  • is there a reason you use a IIFE? https://developer.mozilla.org/en-US/docs/Glossary/IIFE (the code wrapped in `(function ($) {`) that will cause the second function to run as soon as its defined. – Andrew Lohr Aug 13 '18 at 22:51
  • that's what was in the code from github: https://github.com/DoersGuild/jQuery.print/blob/master/jQuery.print.js and it works just fine as is. In fact both work as defined. It just both are running at the same time. Just need to display the content first before the second function executes – user3683976 Aug 13 '18 at 22:55
  • Neither of those functions does anything immediately. The first one defines a click handler that runs when you click on something. The second one defines a jQuery plugin that runs when you call `$.print()`. What do you mean when you say they need to run after each other? – Barmar Aug 14 '18 at 00:28

1 Answers1

0

If I understand your problem correctly, you want the jQuery click function to be run first, making a div with id="test1" visible and then, once it's visible, you want to run the onclick code which calls jQuery.print.

The very first thing I will suggest is that you don't have two different places where you are handling the click implementation, that can make your code hard to follow.

I would replace your $('#abc').click with the following:

function printDiv(selector) {
    $(selector).show();
    window.setTimeout(function () {
        jQuery.print(selector);
    }, 1);
}

This function, when called, will call jQuery.show on the passed selector, wait 1ms and then call jQuery.print. If you need the timeout to be longer, just change the 1 to whatever you need. To use the function, update your example html to the following:

<div id="test">
    <button id="abc" class="btn" onclick="printDiv('#test1')"</button>
</div>

When the button is clicked, it will now call the previously mentioned function and pass it the ID of the object that you want to print.

As far as your second function goes, where you have the comment **//run this second**, you should leave that alone. All it does is extend you jQuery object with the print functionality. You need it to run straight away and it currently does.

Simon K
  • 2,762
  • 1
  • 11
  • 20
  • I tried running the code and it doesn’t work in Firefox or Internet Explorer. Only works in Chrome. Where it says selector I’m assuming that’s where I put my class, correct? – user3683976 Aug 14 '18 at 17:11
  • I changed the function to use a regular function rather than an arrow function so give that a try. As for where it says selector, that should be populated by the function call from the `onclick` in your HTML. In the example I gave you, it is set to `#test1`. If it's still not working in FF and IE, could you give the actual error? – Simon K Aug 14 '18 at 21:22
  • the print works on all 3 browsers, but the show is not collapsing before print is activated. – user3683976 Aug 14 '18 at 21:49
  • Then you have two options. You can either increase the timeout to a larger value, like I suggested in my answer, or you can create an interval timer which repeatedly checks if the element is visible before calling the print function and cancelling itself. – Simon K Aug 14 '18 at 22:47
  • Thanks Simon. I was able to create an interval timer and now it works on all browsers. – user3683976 Aug 17 '18 at 21:58