0

I've searched hi and lo and can't find a post that is relevant/helpful for my particular situation.

I have an app that loads various widgets, some of which load JSONP that contains 3rd party JS that needs to be executed.

I've been able to get all the way to loading the JS in the widget element (directive template), however, I can't figure out how to get that JS to actually execute.

I've thought about maybe doing this in compile, but am new to that so not sure if it's the right approach. I tried using eval() but that didn't work. I tried .$digest and .$apply but that didn't work either. I just need to get the JS to execute as if I put it in the HTML without any Angular. When I do it via a basic jquery/HTML page, it works as expected.

Here is the relevant code:

angular.module('protoApp')
.directive('thirdPartyWidget',['$http',function($http){
    return {
        restrict: 'E',
        scope: {},
        template: '<div id="myWidget"></div>',
        replace: true,
        link: function($scope, $el, $attrs){
            $http({
                method: 'JSONP',
                responseType: 'jsonp',
                url: $scope.url,
                data: thirdPartyWidgetProperties
            })
            .then(function(response){

                // this will properly insert JS into my $el
                // but this JS will not do anything/run.
                $el.append(response.data.html);
            });
        }
    }
}]);

(I'm aware that I should be using a service instead of $http directly here, but I'm just trying to get this to work as simply as possible.)

As an example, one of the JS scripts is for Google Analytics. I'm expecting that after the JSONP is loaded into the $el, there should be a request to GA, just as it does in the non-AngularJS version.

When I inspect the DOM, I can see the script is indeed being appended into the $el, but it doesn't run or do what it should. It's just there like this:

<div class="ng-isolate-scope"><div id="remoteProfiles"></div><script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-99999-99', 'website_name.com');
    ga('send', 'pageview');
</script>
<script type="text/javascript">...3rd party widget stuff...</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.1/require.min.js"></script>
<!--<script src="//requirejs.org/docs/release/2.1.11/comments/require.js"></script>--></div>

So, see, it's there. How do I get it to actually run?

Any info, suggestions, posts, anything you can point me to would be appreciated.

durron597
  • 31,968
  • 17
  • 99
  • 158
coblr
  • 3,008
  • 3
  • 23
  • 31
  • PROGRESS UPDATE: I've been able to split the jsonp response html into an array. I removed all instances of . This gave me the JS that was being injected onto the page that I could then run through eval(). I know, I know, that's not good either, but it does get the GA code to run. The more important JS code that I need doesn't run, so this isn't a usable solution, but it does get a little farther. – coblr Apr 13 '15 at 16:58

1 Answers1

1

So, the only way I got this working was to basically put all initializing JS outside of Angular altogether. The code it loads is beastly. It loads require and does lots of requireJS things that Angular just made a funny face at. It loads HTML with JS logic so that it's all encapsulated for any site. Angular just choked on the script tags and didn't want to deal with any of it.

I did have a version where all the code was in the index.html file, with only a div and an ID in my directive. This was ugly and I wanted to keep looking.

Using this post (AngularJS: How to make angular load script inside ng-include?) and this directive (https://gist.github.com/subudeepak/9617483#file-angular-loadscript-js), I was able to get all my scripts to load within the directive's template. I did have to create a couple of global variables ($document and $window were not making them available to the scripts in my template), but it's much much cleaner than just having everything in the index.html file. If the directive never loads, neither do my extra scripts.

I did forego all the stuff around the directive, and just took it and incorporated it directly into my existing architecture (already had a module for things like this, and didn't need the closure).

Community
  • 1
  • 1
coblr
  • 3,008
  • 3
  • 23
  • 31