0

There seems to be a bug where model data fetched from an http call is present in the $scope but not in a directive. Here is the code that illustrates the problem:

Jsfiddle: http://jsfiddle.net/supercobra/hrgpc/

var myApp = angular.module('myApp', []).directive('prettyTag', function($interpolate) {
return {
    restrict: 'E',
    link: function(scope, element, attrs) {
      var text = element.text();
        //var text = attrs.ngModel;   
        var e = $interpolate(text)(scope);
        var htmlText = "<b>" + e + "</b>";
        element.html(htmlText);
    }
};
});

function MyCtrl($scope, $http, $templateCache) {
$scope.method = 'JSONP';
$scope.url = 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero';

$scope.fetch = function () {
    $scope.code = null;
    $scope.response = null;

    $http({
        method: $scope.method,
        url: $scope.url,
        cache: $templateCache
    }).
    success(function (data, status) {
        $scope.status = status;
        $scope.data = data;
    }).
    error(function (data, status) {
        $scope.data = data || "Request failed";
        $scope.status = status;
    });
};

}

The HTML

<div ng-controller="MyCtrl">
<h1>Angular $http call / directive bug</h1>
<p>This fiddle illustrates a bug that shows that model w/ data fetched via an http call
is not present within a directive.</p>
<hr>
<h2>HTTP call settings</h2>
<li>Method: {{method}}
    <li>URL: {{url}}
        <br>
        <button ng-click="fetch()">fetch</button>
        <hr/>
         <h3>HTTP call result</h3>

        <li>HTTP response status: {{status}}</li>
        <li>HTTP response data: {{data}}</li>
            <hr/>
            <h2>Pretty tag</h2>
            <pretty-tag>make this pretty</pretty-tag>

            <hr/>
            <h3 style="color: red" >Should show http response data within pretty tag</h3>
            [<pretty-tag>{{data}}</pretty-tag>] // <=== this is empty

</div>

Jsfiddle: http://jsfiddle.net/supercobra/hrgpc/

Any help appreciated.

1 Answer 1

1

You are replacing the content of the directive in your directive implementation. Since the $http request is async, the directive completes before the data is retrieve and assigned to the scope.

Put a watch on data variable inside the directive and then re-render the content, something like

 scope.$watch(attrs.source,function(value) {
                var e = $interpolate(text)(scope);
                var htmlText = "<b>" + e + "</b>";
                element.html(htmlText);
            });

Based on @Marks feedback and your request i have update fiddle http://jsfiddle.net/cmyworld/V6sDs/1/

Sign up to request clarification or add additional context in comments.

4 Comments

So at least that works. Thanks. This also makes the directive locked to watch the $scope.data variable. Any way not to do that?
@supercobra, <pretty-tag attr1="data">{{data}}</pretty-tag>, then watch that attribute: scope.$watch(attrs.attr1, function(value) { ... })
This tells me all directives should have a built-in watch mechanism because their data could come from http calls...
As long as you keep the reference to data object, and clear and fill it instead of replacing the reference, this watch would work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.