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);
      }
   };
 });
Community
  • 1
  • 1
Kyle Giard-Chase
  • 243
  • 3
  • 15

1 Answers1

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

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • 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. – Kyle Giard-Chase Oct 04 '15 at 20:19
  • Ended up being something else on my end. Works great with pagination as well. Thanks again for your help! – Kyle Giard-Chase Oct 05 '15 at 14:45