0

I'm inserting the src atturbute for an <iframe> using AngularJS.

For some reason though, whenever I call grab this value it is returned multiple times. I know this because I was checking using console.log(src) to debug before I got the solution working.

This minor glitch doesn't seem to be causing any errors (or slowing my application down), but I'm curious to know what's happening?


Update

I have reduced the code in my controller by moving the bulk of the work to my custom recentStations service (available if required).

The result within the HTML view is still the same, as is the behaviour of returning multiple results.


Controller

app.controller('contentCtrl', ['$scope', 'recentStations', function($scope, recentStations){

    $scope.getCurrentSrc = function(){
        return recentStations.getCurrentSrc();
    };
    
}]);

HTML

<div id="content" data-ng-controller="contentCtrl">
    <iframe data-ng-src="{{ getCurrentSrc() }}" seamless></iframe>
</div>
Community
  • 1
  • 1
David Gard
  • 11,225
  • 36
  • 115
  • 227
  • $sce could cause that. What's happening inside trustAsResourceUrl? – schlingel Aug 25 '15 at 13:00
  • It sounds like the confusing is that `scope.getCurrentSrc` is being called multiple times. I'd expect it to be called once per `$digest` cycle, which will be several times on load, plus again every time Angular decides that some thing interesting has happened. – DRobinson Aug 25 '15 at 13:05
  • 1
    You can get hint http://stackoverflow.com/questions/14973792/why-angularjs-will-invoke-function-name-twice – Vineet Aug 25 '15 at 13:09
  • @schlingel - `$sce` is not the culprit, the behaviour still occurs even if you just return a simple `Hello World` string. Thanks. – David Gard Aug 25 '15 at 13:22
  • @Vineet - Thanks for the link, I'll have a look through. – David Gard Aug 25 '15 at 14:01
  • @DRobinson - Thanks, your description seems to tie in with the link provided by `Vineet`. – David Gard Aug 25 '15 at 14:02
  • Yep, I think it's a fairly common confusion when starting with Angular. If it's a problem for you, and you want to prevent it, you can bind to a variable in your view, rather than a function call (like a `$scope.src` kind of thing). Then in the controller you'll just have to watch the appropriate pieces of `src` to rebuild it when necessary. – DRobinson Aug 25 '15 at 14:05
  • @DRobinson - Thanks, a `watch` is what I'm looking in to currently. In this instance, the app is fairly lightweight so I doubt this behaviour will impact performance, but I'd rather do it properly so that going forward I don't have this problem when performance is more critical. – David Gard Aug 25 '15 at 14:19

2 Answers2

1

A potential way to work around the additional function calls is to bind to a simple value, in your case the src, and use a $watch on dependant values to rebuild it.

Here's an example for your controller:

$scope.$watch(getLink, buildSource);

function getLink(){
    return recentStations.getCurrent().link;
}

function buildSource(link){
    var url = 'http://iris2.rail.co.uk/tiger/';
    var src = url + link;

    $scope.src = $sce.trustAsResourceUrl(src);
};

The HTML would bind as follows:

<iframe data-ng-src="{{ src }}" seamless></iframe>

However, you're still doing a (smaller) function call every $digest; now it's the getLink function called every time. This is because you appear to have to call recentStations.getCurrent() to get the link. If there's a way for you to bind its value to src, it can be simply checked every $digest cycle.

DRobinson
  • 4,441
  • 22
  • 31
  • Thank you, that's really helpfull. I've had to amend for my usage as I've changed my requirements slightly, but your answer works perfectly for my original question. – David Gard Aug 25 '15 at 14:57
0

This behavior is caused by angularjs dirty checking. AngularJS implements dirty checking for two way data binding.

maddygoround
  • 2,145
  • 2
  • 20
  • 32
  • Thanks. Any suggestions as to how I can avoid this behavior? Note that I've updated the code in my question. – David Gard Aug 25 '15 at 14:20