repka
repka

Reputation: 2979

How to avoid creating element with angularJS?

I have an <iframe> element that I want to be created only when user clicks a button. Being new to angular, I just placed it into the page and added ng-if directive binding element presence to some boolean in my model. It works as expected with exception that for the brief moment before the page fully loads and angular runs the element is created. In fact I can see the outgoing request to load the frame in my browser's F12 tools.

What is the proper Angular approach to create the element only upon user request? I realize I can change frame's src, but wondering if there's more elegant solution.

Here's full page code:

<!doctype html>
<html>
<body ng-app="bomberApp" ng-controller="MooCtrl">
<button ng-click="showFrame()">Click!</button><br>
<iframe src="//xkcd.com" ng-if="show" ng-init="show=false"></iframe>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.js"></script>
<script>
var bomberApp = angular.module('bomberApp', []);
bomberApp.controller("MooCtrl", function($scope) {
    $scope.showFrame = function(){
        $scope.show = !$scope.show;
    }
});
</script>
</body>
</html>

Upvotes: 1

Views: 366

Answers (2)

Christian Gill
Christian Gill

Reputation: 524

You can make a custom directive and create the iframe when the button is clicked just using plain JavaScript DOM functions.

Here is a working Plunkr

 angular.module('testApp', [])
    .directive('generateIframe', function() {
      return {
        restrict: 'E',
        template: '<div><button ng-click="vm.create()">{{vm.message}}</button><br><div id="iframe-container"></div></div>',
        scope: {
          src: '@'
        },
        controller: function($scope) {
          var vm = this;
          vm.src = $scope.src;
          vm.iframeCreated = false;
          vm.message = 'Create';

          vm.create = function() {
            var iframeContainer = document.getElementById('iframe-container');
            if (!vm.iframeCreated) {
              var iframe = document.createElement('iframe');
              iframe.src = vm.src;
              iframe.class = 'some-class'; // add it if you need to style it
              iframe.id = 'created-iframe';
              iframeContainer.appendChild(iframe);
              vm.iframeCreated = true;
              vm.message = 'Remove';
            } else {
              var iframe = document.getElementById('created-iframe');
              iframeContainer.removeChild(iframe);
              vm.iframeCreated = false;
              vm.message = 'Create';
            }
          }
        },
        controllerAs: 'vm'
      }
    });

Upvotes: 3

Selfish
Selfish

Reputation: 6200

The problem comes from the rendering order of the page: Your iframe is there before the <script> tag which loads Angular!

Go ahead, utilize your <head> area to load the scripts, and you will find that once Angular is loaded before the iFrame, it will not show:

<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.js"></script>
  <script>
    var bomberApp = angular.module('bomberApp', []);
    bomberApp.controller("MooCtrl", function($scope) {
      $scope.showFrame = function() {
        $scope.show = !$scope.show;
      }
    });
  </script>
</head>

<body ng-app="bomberApp" ng-controller="MooCtrl">
  <button ng-click="showFrame()">Show me the Money!</button>
  <br>
  <iframe src="//xkcd.com" ng-if="show" ng-init="show=false"></iframe>
</body>

</html>

Upvotes: 3

Related Questions