Brian Sexton
Brian Sexton

Reputation: 67

Why does AngularJS throw an error when I try to build a URL for an iframe src attribute?

I have been tinkering with AngularJS directives and I do not understand why my attempt to build an iframe src attribute with an expression is triggering an error. The thrown error references the following URL, but I'm afraid I don't find it very enlightening:

http://errors.angularjs.org/1.3.14/$interpolate/noconcat?p0=https%3A%2F%2Fwww.youtube.com%2Fembed%2F%7B%7BvideoId%7D%7D

What does that really mean and what can I do about it?

Here are the relevant JavaScript and HTML:

angular.module("myModule", [])

	.directive("myDirective", function() {

		return {

			restrict: "EA",

			scope: {

				videoId: "@videoId",
				width: "@width",
				height: "@height"
			},

			// This seems to work as expected.
			//template: '<iframe width="432" height="243" src="https://www.youtube.com/embed/8aGhZQkoFbQ" frameborder="0" allowfullscreen></iframe>',

			// This seems to work as expected except for adding a little extra whitespace after the values.
			//template: '<iframe width="{{width}}" height="{{height}}" src="https://www.youtube.com/embed/8aGhZQkoFbQ" frameborder="0" allowfullscreen></iframe>',

			// This throws an error that refers to http://errors.angularjs.org/1.3.14/$interpolate/noconcat?p0=https%3A%2F%2Fwww.youtube.com%2Fembed%2F%7B%7BvideoId%7D%7D.
			template: '<iframe width="432" height="243" src="https://www.youtube.com/embed/{{videoId}}" frameborder="0" allowfullscreen></iframe>',

			replace: true
		};
	});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>

<my-directive video-id="8aGhZQkoFbQ" width="432" height="243"></my-directive>

My thanks for any enlightenment.

I am leaving the above in place for reference, but here is an edited version using a controller and $sce.trustAsResourceUrl as suggested in Muhammad Reda's answer in case it can help anyone to see it all together:

angular.module("myModule", ["ngSanitize"])

	.directive("myDirective", function() {

		return {

			restrict: "EA",

			scope: {

				videoId: "@videoId",
				width: "@width",
				height: "@height"
			},

			template: '<iframe width="432" height="243" src="{{srcUrl}}" frameborder="0" allowfullscreen></iframe>',

			replace: true,

			controller: function($scope, $sce) {

				$scope.srcUrl = $sce.trustAsResourceUrl("https://www.youtube.com/embed/" + $scope.videoId);
			}
		};
	});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-sanitize.min.js"></script>

<my-directive video-id="8aGhZQkoFbQ" width="432" height="243"></my-directive>

Upvotes: 1

Views: 623

Answers (1)

Muhammad Reda
Muhammad Reda

Reputation: 27023

Your url needs to be wrapped around $sce.trustAsResourceUrl(YOUR_URL)

Documentation.

Add a controller to your directive

angular.module("myModule", ['ngSanitize'])
    .directive("myDirective", function() {
        .....
        controller: function($scope, $sce) {
            $scope.iframeUrl = 'https://www.youtube.com/embed/' + $scope.videoId;
            $scope.iframeUrl = $sce.trustAsResourceUrl($scope.iframeUrl);
        },
        template: '<iframe src="{{ iframeUrl }}" frameborder="0" allowfullscreen></iframe>'
    })

Upvotes: 3

Related Questions