1

Based on answers here, I have been trying to wrap a jQuery plugin (addtocalendar) in an angular directive. I am using ui-router and previously the plugin would work, but if I navigated away from this child to state to another, the addtocalendar button would disappear entirely.

Now, with the plugin wrapped in a directive, if I navigate away to a different child state and then come back, I am able to see the button, however, I get an error from the plugin that I have specified an invalid date. It seems that the data I am feeding the plugin from Angular gets run once and then is never fed to the plugin again.

Is there a workaround for this?

Here is my HTML:

     // works fine on first page load

      <div addtocalendartest> // angular directive
        <div class="addtocalendar"> //jQuery plugin
        <div class="arrow-up"></div>
          <var class="atc_event">
            <var bind-once class="atc_date_start">{{event.startDate | date:'yyyy-MM-dd HH:mm:ss'}}</var>
            <var bind-once class="atc_date_end">{{event.endDate | date:'yyyy-MM-dd HH:mm:ss'}}</var>
            <var bind-once class="atc_timezone">America/New_York</var>
            <var bind-once class="atc_title">{{event.description}}</var>
            <var bind-once class="atc_description">{{event.Synopsis | characters: 200 :false }}</var>
            <var bind-once class="atc_location">_</var>
          </var>
        </div>
      </div>

And here is the directive I created that contains the plugin logic:

 'use strict';

 angular.module('myApp')
 .directive('addtocalendartest', function() {
   return {
   restrict: 'A',
    link: function(scope, element, attrs) {

     //run jQuery scripts

            var w = window;
            var d = document;           
                (function(w, d) {
                    var atc_url = "//addtocalendar.com/atc/",
                        atc_version = "1.5",
                        b = d.documentElement;
                    if (!Array.indexOf) {
                        Array.prototype.indexOf = function(e) {
                            for (var t = 0, n = this.length; t < n; t++) {
                                if (this[t] == e) {
                                    return t
                                }
                            }
                            return -1
                        }
                    }
                    if (!Array.prototype.map) {
                        Array.prototype.map = function(e) {
                            var t = [];
                            for (var n = 0, r = this.length; n < r; n++) {
                                t.push(e(this[n]))
                            }
                            return t
                        }
                    }
                    var isArray = function(e) {
                        return Object.prototype.toString.call(e) === "[object Array]"
                    };
                    var isFunc = function(e) {
                        return Object.prototype.toString.call(e) === "[object Function]"
                    };
                    var ready = function(e, t) {
                        function u() {
                            if (!n) {
                                if (!t.body) return setTimeout(u, 13);
                                n = true;
                                if (i) {
                                    var e, r = 0;
                                    while (e = i[r++]) e.call(null);
                                    i = null
                                }
                            }
                        }

                        function a() {
                            if (r) return;
                            r = true;
                            if (t.readyState === "complete") return u();
                            if (t.addEventListener) {
                                t.addEventListener("DOMContentLoaded", s, false);
                                e.addEventListener("load", u, false)
                            } else {
                                if (t.attachEvent) {
                                    t.attachEvent("onreadystatechange", s);
                                    e.attachEvent("onload", u);
                                    var n = false;
                                    try {
                                        n = e.frameElement == null
                                    } catch (i) {}
                                    if (b.doScroll && n) f()
                                } else {
                                    o = e.onload;
                                    e.onload = function(e) {
                                        o(e);
                                        u()
                                    }
                                }
                            }
                        }

                        function f() {
                            if (n) return;
                            try {
                                b.doScroll("left")
                            } catch (e) {
                                setTimeout(f, 1);
                                return
                            }
                            u()
                        }
                        var n = false,
                            r = false,
                            i = [],
                            s, o;
                        if (t.addEventListener) {
                            s = function() {
                                t.removeEventListener("DOMContentLoaded", s, false);
                                u()
                            }
                        } else {
                            if (t.attachEvent) {
                                s = function() {
                                    if (t.readyState === "complete") {
                                        t.detachEvent("onreadystatechange", s);
                                        u()
                                    }
                                }
                            }
                        }
                        return function(e) {
                            a();
                            if (n) {
                                e.call(null)
                            } else {
                                i.push(e)
                            }
                        }
                    }(w, d);
                    if (w.addtocalendar && typeof w.addtocalendar.start == "function") return;
                    if (!w.addtocalendar) w.addtocalendar = {};
                    addtocalendar.languages = {
                        de: "In den Kalender",
                        en: "Add to Calendar",
                        es: "Añadir al Calendario",
                        fr: "Ajouter au calendrier",
                        hi: "कैलेंडर में जोड़ें",
                        "in": "Tambahkan ke Kalender",
                        ja: "カレンダーã«è¿½åŠ ",
                        ko: "캘린ë”ì— ì¶”ê°€",
                        pt: "Adicionar ao calendário",
                        ru: "Добавить в календарь",
                        uk: "Додати в календар",
                        zh: "æ·»åŠ åˆ°æ—¥åŽ†"
                    };
                    addtocalendar.calendar_urls = {};
                    addtocalendar.loadSettings = function(element) {
                        var settings = {
                            language: "auto",
                            "show-list-on": "click",
                            calendars: ["iCalendar", "Google Calendar", "Outlook", "Outlook Online", "Yahoo! Calendar"],
                            secure: "auto",
                            "on-button-click": function() {},
                            "on-calendar-click": function() {}
                        };
                        for (var option in settings) {
                            var pname = "data-" + option;
                            var eattr = element.getAttribute(pname);
                            if (eattr != null) {
                                if (isArray(settings[option])) {
                                    settings[option] = eattr.replace(/\s*,\s*/g, ",").replace(/^\s+|\s+$/g, "").split(",");
                                    continue
                                }
                                if (isFunc(settings[option])) {
                                    var fn = window[eattr];
                                    if (isFunc(fn)) {
                                        settings[option] = fn
                                    } else {
                                        settings[option] = eval("(function(mouseEvent){" + eattr + "})")
                                    }
                                    continue
                                }
                                settings[option] = element.getAttribute(pname)
                            }
                        }
                        return settings
                    };
                    addtocalendar.load = function() {
                        ready(function() {
                            var e = {
                                iCalendar: "ical",
                                "Google Calendar": "google",
                                Outlook: "outlook",
                                "Outlook Online": "outlookonline",
                                "Yahoo! Calendar": "yahoo"
                            };
                            var t = -(new Date).getTimezoneOffset().toString();
                            var n = addtocalendar.languages;
                            var r = document.getElementsByTagName("*");
                            for (var i = 0; i < r.length; i++) {
                                var s = r[i].className;
                                if (s.split(" ").indexOf("addtocalendar") != -1) {
                                    var o = addtocalendar.loadSettings(r[i]);
                                    var u = o["calendars"].length == 1;
                                    var a = "http:";
                                    if (o["secure"] == "auto") {
                                        a = location.protocol == "https:" ? "https:" : "http:"
                                    } else if (o["secure"] == "true") {
                                        a = "https:"
                                    }
                                    var f = a + atc_url;
                                    var l = r[i].id;
                                    var c = n["en"];
                                    if (o["language"] == "auto") {
                                        var h = "no_lang";
                                        if (typeof navigator.language === "string") {
                                            h = navigator.language.substr(0, 2)
                                        } else if (typeof navigator.browserLanguage === "string") {
                                            h = navigator.browserLanguage.substr(0, 2)
                                        }
                                        if (n.hasOwnProperty(h)) {
                                            c = n[h]
                                        }
                                    } else if (n.hasOwnProperty(o["language"])) {
                                        c = n[o["language"]]
                                    }
                                    var p = ["utz=" + t, "uln=" + navigator.language, "vjs=" + atc_version];
                                    var d = r[i].getElementsByTagName("var");
                                    var v = -1;
                                    for (var m = 0; m < d.length; m++) {
                                        var g = d[m].className.replace("atc_", "");
                                        var y = d[m].innerHTML;
                                        if (g == "event") {
                                            v++;
                                            continue
                                        }
                                        if (g == d[m].className) {
                                            if (g == "atc-body") {
                                                c = y
                                            }
                                            continue
                                        }
                                        if (v == -1) {
                                            continue
                                        }
                                        p.push("e[" + v + "][" + g + "]" + "=" + encodeURIComponent(y))
                                    }
                                    var b = l == "" ? "" : l + "_link";
                                    var w = document.createElement("ul");
                                    w.className = "atcb-list";
                                    var E = "";
                                    var S = "";
                                    for (var x in o["calendars"]) {
                                        if (!e.hasOwnProperty(o["calendars"][x])) {
                                            continue
                                        }
                                        var T = e[o["calendars"][x]];
                                        var N = l == "" ? "" : 'id="' + l + "_" + T + '_link"';
                                        var C = f + T + "?" + p.join("&");
                                        if (u) {
                                            S = C
                                        } else {
                                            E += '<li class="atcb-item"><a ' + N + ' class="atcb-item-link" href="' + C + '" target="_blank">' + o["calendars"][x] + "</a></li>"
                                        }
                                    }
                                    w.innerHTML = E;
                                    if (r[i].getElementsByClassName("atcb-link")[0] == undefined) {
                                        var k = document.createElement("a");
                                        k.className = "atcb-link";
                                        k.innerHTML = c;
                                        k.id = b;
                                        k.tabIndex = 1;
                                        if (u) {
                                            k.href = S;
                                            k.target = "_blank"
                                        }
                                        r[i].appendChild(k);
                                        if (!u) {
                                            r[i].appendChild(w)
                                        }
                                    } else {
                                        var k = r[i].getElementsByClassName("atcb-link")[0];
                                        if (!u) {
                                            k.parentNode.appendChild(w)
                                        }
                                        k.tabIndex = 1;
                                        if (k.id == "") {
                                            k.id = b
                                        }
                                        if (u) {
                                            k.href = S;
                                            k.target = "_blank"
                                        }
                                    }
                                    r[i].getElementsByClassName("atcb-link")[0].addEventListener("click", o["on-button-click"], false);
                                    var L = r[i].getElementsByClassName("atcb-item-link");
                                    for (var m = 0; m < L.length; m++) {
                                        L[m].addEventListener("click", o["on-calendar-click"], false)
                                    }
                                }
                            }
                        })
                    };
                    addtocalendar.load()
                })(window, document)
            }
        };
      });

UPDATE/ANSWER Thanks to @charlietfl, the answer is to include $timeout so that Angular can load before the jQuery plugin, e.g:

'use strict';

angular.module('myApp')
  .directive('addtocalendartest', function($timeout) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        $timeout(function(){
          // jQuery plugin logic goes here
        }, 5000);
      }
   };
 });
3
  • 1
    assuming it gets values from text you probably need to use $timeout to let angular compile first Commented Oct 4, 2015 at 19:52
  • That was it - thank you! Commented Oct 4, 2015 at 20:06
  • don't need 5 seconds for it though, probably don't need to set any duration unless data is being pulled in from server....a resolve in routing would help that problem though Commented Oct 4, 2015 at 20:07

1 Answer 1

1

Use $timeout to let angular compile the text first so that plugin isn't trying to read expressions.

$timeout(function(){
     addtocalendar.load();
});

If the data needs to be resolved from server request first you can use a resolve in router so that it exists at time template gets loaded

Sign up to request clarification or add additional context in comments.

2 Comments

Answer works really well going from one child state to another, but I just tested this with pagination and it doesn't seem to work. Do you have any suggestions for making it work with pagination? I'm back to having no button appear at all if I'm flipping through one page to the next.
Ended up being something else on my end. Works great with pagination as well. Thanks again for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.