Using iFrames in AngularJS

All we need is an easy explanation of the problem, so here it is.

Using Angular 1.2+, I’m trying to work out an “angular” way to load in an iFrame but I can’t find any tutorials/any real discussion on this anywhere.

Basically, I have a search page which displays a list of links. Clicking a link should call a function in my controller which loads in data (possibly through the $http service?) to an iFrame while keeping the search results in view.

Here’s some rudimentary code (I’ve never really used iFrames before so apologies if this is just totally wrong)

View

<div ng-controller="searchPage">
  <div ng-repeat='post in searchResults'>
    <a ng-click="itemDetail(post._infoLink)">Here's a link!</a>
  </div>
  <div class="detailView" ng-show="itemShown">
    <iframe ng-src="detailFrame"></iframe>
  </div>
</div>

Controller

$scope.itemDetail = function(link){
  $scope.itemShown = true;
  $scope.busy = true;
  $http.get(link).success(function(data){
    $scope.busy = false;
    $scope.detailFrame = data;
  });
}

This code currently gives the error:

 XMLHttpRequest cannot load <url>. Origin http://localhost:5000 is not allowed by Access-Control-Allow-Origin. 

Something simple along these lines would be ideal. In the (attempted) example above, the search results would stay on the screen and get pushed into a sidebar, while the iFrame loads in an external site (on a different domain) into the bulk of the page.

How can this be achieved with Angular?

Extra caveat: The links to load into the iFrame are affiliate links so they’ll often have a ‘middleman’ domain between them, e.g. the clicked-link will be mydomain.com/cloakinglink which redirects to www.zanox.com/whatever which then leads to the final site, www.asos.com/whatever.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

As for AngularJS 1.2, there you should use the $sce service:

<iframe width="500" height="400" ng-src="{{detailFrame}}"></iframe>

$scope.detailFrame= $sce.trustAsResourceUrl("https://www.google.com");

Good luck…

Method 2

Due to Same Origin Policy, you can’t get cross domain data by using XMLHttpRequest.

I’m not quite sure that what you really want to do.

You could try to bind iframe src attribute and clicked link url together to achieve the function if you just want iframe to show the web page which user cliked.

I wrote a simple example:

HTML

<div ng-app ng-controller="searchPage">
  <div ng-repeat="page in searchResults">
      <a ng-click="itemDetail(page._infoLink)">{{page.label}}</a>
  </div>
  <iframe width="500" height="400" ng-src="{{detailFrame}}"></iframe>
</div>

JS

function searchPage($scope){
  $scope.searchResults = [{label:"BBC",_infoLink:"http://www.bbc.co.uk/"},{label:"CNN",_infoLink:"http://edition.cnn.com/"}];

  $scope.itemDetail = function(link){
      $scope.detailFrame = link;
  };
}

Here is the jsFiddle demo

BTW… You could try server proxy if you really want to use XMLHttpRequest to grab data from 3-party web site and dump it to somewhere (You can’t dump data to iframe src attribute! It only accepts the URL of web page).

Method 3

Really struggled on just using regular dom to st iframe.src. Grr… Angular bends the light toward it.

 .state('nav.iframer', {
            url: '/iframer',
            templateUrl: 'app/dashboard/iframer.html',
            controller: function($rootScope, $sce){


                    var f = window.frames.iframer;//
                    this.frameUrl= $sce.trustAsResourceUrl("https://www.google.com");


            },

            controllerAs: 'framed'
        })

template:

<iframe name="iframer" width="900" height="900" ng-src="{{framed.frameUrl}}"></iframe>

Method 4

I think some more clarification is needed along with another example.

$sce is a service that you MUST inject. The reason it it is not included automatically is the overhead of performance, you certainly WANT to be able to only load up services that you NEED.

$sce.trustasResourceURL thus is important

Example:

angular.module('tips')

.controller('TipsCtrl',

function ($http, $scope, UserService, $location, $routeParams, Categories, Tip, error, $sce) {  
    // various code  
    $scope.detailFrame = $sce.trustAsResourceUrl("https://localhost:17308/Home/Index/2"); //hard coded
})

Then the IFrame:

<iframe ng-src="{{detailFrame}}" align="middle" width="1000" height="800" frameborder="0">
    <p>Your browser does not support iframes.</p>
</iframe>

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply