waney
waney

Reputation: 402

Include external js widget in angular template

I need to include script tag which will render widget on my angularjs template.

For example I'd include this

<script type="text/javascript" src="http://100widgets.com/js_data.php?id=106"></script>

But angular will not render it.

Upvotes: 10

Views: 2411

Answers (2)

Sander Elias
Sander Elias

Reputation: 754

Due to safety constraints, Angular does not parse <script> tags inside templates.
Then the widget you are referring to, is utilizing document.write. Document.write is unavailable once your page is done loading.
So, there seems to be no easy way out here.

However, as what you are trying to do, is something that is quite usual in add-script, krux created postscribe. A way around this issue. On my turn I created a small directive that utilizes this library.

In your template it will look something like this:

<div ps-src="http://100widgets.com/js_data.php?id=21"></div>

the directive:

  function psScr($document) {
    return {
      restrict: 'A',
      scope: {
        psSrc: '@'
      },
      link: link
    }

    function link(scope, elm) {
      if (typeof postscribe !== 'undefined') {
        postscribe(elm[0], `<script src='${scope.psSrc}'></script>`);
      } else {
        // If postscibe isn't loaded, first load the needed libarary
        var script = document.createElement('script');
        script.src = 'https://gitcdn.xyz/repo/krux/postscribe/master/dist/postscribe.js';
        script.onload = function () {
          // once postscibe is in, kick it into action.
          link(scope,elm); 
        };
        document.head.appendChild(script);
      }
    }
  }

  angular.module('psSrcModule', [])
    .directive('psSrc', psScr);

You can see it in action in this plunk

Not all of the widgets behave nicely in combination with postscribe though, some of them seem to display some artefacts in the html. I currently lack the time to find out who is to blame for this (100widgets or postscribe), but if you really need this, this is something that can be worked out.

Upvotes: 0

beaver
beaver

Reputation: 17647

Since the 100widgets scripts manipulate DOM and add other <script> tags to HTML file it could not work properly. Morover some of these widgets are Flash based so the script add reference to SWF objects. I think one possibility is to analyze the output of the request to url in src attribute (in your example http://100widgets.com/js_data.php?id=106) and trying to add the corresponding DOM manipulation and scripts to the template in which you desire the widget will appear.

Following is an example showing a page (page1) NOT WORKING (simply added the script tag as you typed) and a second page (page2) whose template has the insertions needed to show up the calendar widget.

PS: due to sandbox restriction this snippet could not work here on SO; try this CodePen version in debug mode: http://codepen.io/beaver71/pen/MyjBoP, or create your own version deployed on your local web server.

(function() {
  'use strict';

  angular.
  module('myApp', ['ui.router']).
  config(configRouteProvider).
  controller('AppCtrl', AppCtrl);

  function AppCtrl($location, $rootScope) {
    $rootScope.$on('$stateChangeStart', onStateChangeStart);

    function onStateChangeStart(event, toState, toParams, fromState, fromParams, options) {
      console.log('From:', fromState.name,
        'to:', toState.name);
    }
  }

  function configRouteProvider($stateProvider, $urlRouterProvider) {
    $stateProvider
      .state('home', {
        url: '/',
        templateUrl: 'views/home.html'
      })
      .state('page1', {
        url: '/pag1',
        templateUrl: 'views/page1.html',
      })
      .state('page2', {
        url: '/pag2',
        templateUrl: 'views/page2.html',
      });
    $urlRouterProvider.otherwise('/');
  }

}());
body {
  margin: 0px;
}
hr {
  margin: 0px;
}
.tabs {
  padding: 8px;
  background-color: black;
  color: white;
}
.tabs a,
.tabs a:visited,
.tabs a:active,
.tabs a:hover {
  color: white;
}
.my-tab {
  height: 100%;
  width: 100%;
  position: absolute;
  padding: 8px;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
  <script src='https://code.angularjs.org/1.4.0/angular.min.js'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js'></script>
</head>

<body ng-app="myApp" ng-controller="AppCtrl as app">
  <div class="tabs">
    <a href="#" ui-sref="home">Home</a>
    <a href="#" ui-sref="page1">Page1</a>
    <a href="#" ui-sref="page2">Page2</a>
  </div>
  <hr />
  <div ui-view></div>

  <script id="views/home.html" type="text/ng-template">
    <div class="my-tab">
      <h3>Home</h3>
      <p>bla bla bla</p>
    </div>
  </script>

  <script id="views/page1.html" type="text/ng-template">
    <div class="my-tab">
      <h3>Page1</h3>
      <p>Using script type="text/javascript"... NOT WORKING:</p>
      <script type="text/javascript" src="http://100widgets.com/js_data.php?id=106"></script>
    </div>
  </script>

  <script id="views/page2.html" type="text/ng-template">
    <div class="my-tab">
      <h3>Page2</h3>
      <p>Workaround</p>
      <!--code1-->
      <div class="scriptcode">
        <!--ecode1-->
        <a target='_blank' href='http://100widgets.com/calendars/106-calendar.html'>
          <embed align="middle" id="calendar" width="170" height="156.111111111" allowscriptaccess="always" quality="high" salign="lt" wmode="transparent" src="http://100widgets.com/js-files/postit.swf?UTCoffset=0&amp;gid=0&amp;text1=St Valentines is on 14th February 2012&amp;&amp;event_time=&amp;rec=&amp;rnd=0&amp;gha=0&amp;ghb=0&amp;ghf=1&amp;gbc=FFB200&amp;gfc=040244&amp;gtc=F9F9FF&amp;gnu=http://mycalendar.org/widget/&amp;fna=&amp;ims="
          type="application/x-shockwave-flash" />
        </a>
        <!--code2-->
      </div>
      <!--ecode2-->
      <!--below commented cause it's not necessary -->
      <!--script type="text/javascript">
        var js = document.createElement("script");
        js.type = "text/javascript";
        js.src = "http://100widgets.com/stat.js.php";
        document.body.appendChild(js);
      </script-->
    </div>
  </script>
</body>

Upvotes: 2

Related Questions