4

I am using iframe in one of my jsp page and I need to assign an external address as src of this iframe. It is working as expected. However sometimes when the external source is not available I want to show an static image. I have tried a number of ways but couldn't succeed.

Than I tried using AngularJS (My latest crush) way to achieve this but looks like I am missing some thing. A piece from my file is attached below :-

<iframe ng-src="{{iframesrcurl}}" frameborder="0" width="100%" height="1100px" scrolling="auto" onload="load($event)" onerror="loadingError">
                                <h3>No such page</h3>
</iframe>

JS file has

myAppName.controller("myAppController", function ($scope, $sce) {
    $scope.iframesrcurl=$sce.trustAsResourceUrl('http://www.w3schools.com');
    console.log('iframesrcurl is '+$scope.iframesrcurl);
});

function load(e) {
    alert("Inside load function");
    alert(e);
}

function loadingError() {
    alert('Inside error function');
}

Problem is onload and onerror functions are never called.

Please guide me for this. I am looking for pure html, javascript or Angular ways of doing this but jquery specific tricks too will be appreciated.

EDIT

This question is similar but it is using knockout.js which I am not allowed to use in my project. Please suggest Angular way of doing this.

Community
  • 1
  • 1
Amit
  • 13,134
  • 17
  • 77
  • 148
  • What you're doing isn't the "angular" way. Here's the beginning of the angular way: http://stackoverflow.com/questions/15882326/angular-onload-function-on-an-iframe – Jaime Torres Dec 18 '14 at 13:19
  • @JaimeTorres Thanks for the link. However I am not able to get any notification when external source is not available. onError part is not working. If you have any working demo please share. – Amit Dec 18 '14 at 13:32
  • There is no "onError" that will work for cross-site URLS because of security concerns. If the page is on your domain, you can simply check the content of the frame and determine if it makes sense. If you are trying to load external resources, you may be SOL. A plnkr for angularizing what you've done: http://plnkr.co/edit/jTmWOLMN7LdiCZPIvuof – Jaime Torres Dec 18 '14 at 14:00
  • I've never tried this, but this YQL usage may work: http://stackoverflow.com/a/16756395/1497479 – Jaime Torres Dec 18 '14 at 14:02

1 Answers1

1

I originally answered your question in a very complex method that matched your callbacks. Then I re-read your question, and realized that wasn't the goal. The goal is to create something that either shows an image or a frame. Assuming that frame needs to get outside of your domain (based on your usage of $sce, I believe that to be the case), this solution will work.

Full Plnkr: http://embed.plnkr.co/jTmWOLMN7LdiCZPIvuof/preview

HTML:

  <body ng-app='myApp' ng-controller="myAppController">
    <h1>Hello StackOverflow!</h1>

    <iframe-nanny desired-uri="desiredFrameSource" error-image-uri="errorImageSrc"></iframe-nanny>
  </body>

Controller:

myAppName.controller("myAppController", function($scope, $sce) {
  $scope.desiredFrameSource = 'http://www.w3schools.com/test';
  $scope.errorImageSrc = 'https://cdn2.iconfinder.com/data/icons/contact-flat-buttons/512/thumb_down-512.png';
});

We define our URL's in the controller for convenience. These can obviously be variable. To test a failed URI, we can use

  $scope.desiredFrameSource = 'http://www.w3schools.com/test';

to test a successful URI:

  $scope.desiredFrameSource = 'http://www.w3schools.com/';

Simple enough I hope. The magic happens in the directive now. It either emits an iframe or an image, depending on the results of a YQL query. If you need additional alerts, you can send in callbacks/attributes to the directive and do cute things with it.

Directive:

myAppName.directive('iframeNanny', function($q, $http, $compile, $sce) {
  return {
    restrict: 'E',
    scope: {
      desiredUri: '=',
      errorImageUri: '='
    },
    link: function(scope, element, attrs) {
      var loadedUri = '';

      function isURLReal(fullyQualifiedURL) {
        var URL = encodeURIComponent(fullyQualifiedURL);
        var dfd = $q.defer();
        var yqlUri = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22' + URL + '%22&callback=JSON_CALLBACK';

        $http.jsonp(yqlUri)
          .success(function(data, status) {
            console.log(data.results.length);
            if (data.results.length) {
              console.log('success!')
              dfd.resolve(true);
            } else {
              dfd.reject(false);
            }
          }).error(function(data, status) {
            dfd.reject('failed');
          });

        return dfd.promise;
      }

      scope.$watch('desiredUri', function(uri) {
        if (loadedUri !== uri) {

          isURLReal(uri).then(function() { 
            console.log('directive: uri valid');
            loadedUri = uri;

            scope.trustedUri = $sce.trustAsResourceUrl(scope.desiredUri);

            var iFrameHtml = '<iframe src="{{trustedUri}}" frameborder="0" width="100%" height="1100px" scrolling="auto"></iframe>';

            var markup = $compile(iFrameHtml)(scope);
            element.empty();
            element.append(markup);
          }).catch(function() {
            console.log('directive: uri invalid');
            var badRequestImgHtml = '<img src="{{errorImageUri}}">';

            var markup = $compile(badRequestImgHtml)(scope);

            console.log(scope.errorImageUri);
            element.empty();
            element.append(markup);
          });
        }
      });
    }
  };
});

This has been an interesting problem to solve. Great question!

Jaime Torres
  • 10,365
  • 1
  • 48
  • 56
  • Thanks @Jaime, Looks like their is some problem with the plunker Code their is not working as expected. – Amit Dec 19 '14 at 06:01
  • What's the issue with the plunker? It seems to work when I change the url, switching between the image and the w3schools page dependent on the existence of 'test' in the url. – Jaime Torres Dec 19 '14 at 11:52
  • I got it working now.. Thanks for your help. I really appreciate. Is their any other way so that we can avoid using YQL for this ? – Amit Dec 19 '14 at 11:54
  • Yes. If all of your requests are on your domain or you have control of the server side and you can use the server as a proxy for the requests, then you aren't restricted by CORS. Unless the property you're contacting responds with an appropriate 'Access-Control-Allow-Origin' in its header, you will need some form of proxy as security restrictions make the request, let alone interrogate the results of it. – Jaime Torres Dec 19 '14 at 13:09