5

I have an issue with a data binding inside a directive, which call another directive.

Here is the main directive :

var app = angular.module('app');

app.directive("myMainDirective", function ($http) {
return {
    scope: {
        paramId: '='
    },
    link: function (scope) {
        $http.get('some/url/' + scope.paramId+ '.json'
        ).success(function (data) {
                scope.idFromServer = data;
            });
    },
    template: '<span other-directive id="idFromServer"></span>'
}
});

Here is the other directive :

var app = angular.module('app');

app.directive("otherDirective", ['$http', function(http) {
return {
    template: "<span>{{name}}</span>",
    scope: {
        id: "="
    },
    link: function(scope) {
        http.get('another/url/' + scope.id + '.json').then(function(result) {
            scope.name = result.data.name;
        }, function(err) {
            scope.name = "unknown";
        });
    }
}
}])

And the html code wich call the main directive :

<span my-main-directive param-id="myObject.id"></span>

When calling "other-directive", the "idFromServer" is not bind, and is "undefined", so it results to diplay "undefined".

I'm probably missing something stupid, but I don't see what ... (My piece of code is probabley not the best, I'm pretty new to angularjs, and specially the directives, and I tried a lot of ways to accomplish what I want.)

10
  • When something is not working, it is helpful to specify any error messages, or the expected output and the actual output. Commented Apr 17, 2015 at 19:16
  • Matthieu - If you are using Chrome, you can right mouse click inside your page and choose inspect element, then click the console tab in the window that pops up... Do you see errors? What is it telling you? Commented Apr 17, 2015 at 19:21
  • Sorry, I forget to say what the problem is (I've edited my question). Commented Apr 17, 2015 at 19:22
  • I just have a 404 error, because the "another-directive" fails to get the hhtp get, because id is "undefined" : GET localhost:63342/another/url/undefined.json 404 (Not Found) Commented Apr 17, 2015 at 19:24
  • Make sure that you have IIS set up to be allowed to serve JSON files, you have to specify a mimeType in either IIS or on the web.config to be able to access them. See the answer on this question:stackoverflow.com/questions/17626776/… Commented Apr 17, 2015 at 19:27

3 Answers 3

4

Per my comments, here's one way that might work, using a scope.$watch:

scope.$watch('id', function(id) {
    $http.get('some/url/' + id + '.json')
        .success(function (data) {
            scope.idFromServer = data;
        });
};

This would go inside the link function on the nested directive.

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

3 Comments

Yeah, adding this scope.$watch did the trick !! Is it a "good angular way" to do that ?
I'd probably move it out of the scope of the second directive an into the scope of the main one, then put some way to observe changes in the second one. The answer below me provides a really good example of that. They're just different ways to skin the cat, both are "good anuglar" ways of doing it.
@BenBlack that is what I've done,,your is also too good answer. :)
2

One of the way I'd suggest is don't use two way(=) binding on idFromServer variable, use {{idFromServer}} Interpolation directive to assign value to attribute, & then use $attr.$observe it will call when interpolation is evaluated.

myMainDirective

app.directive("myMainDirective", function ($http) {
return {
    scope: {
        paramId: '='
    },
    link: function (scope) {
        $http.get('some/url/' + scope.paramId+ '.json'
        ).success(function (data) {
                scope.idFromServer = data;
            });
    },
    template: '<span other-directive id="{{idFromServer}}"></span>'
}
});

otherDirective

app.directive("otherDirective", ['$http', function(http) {
    return {
        template: "<span>{{name}}</span>",
        scope: true, //isolated scope
        link: function(scope, element, attr) {
            attr.$observe(attr.id, function(newVal) {
                http.get('another/url/' + newVal + '.json').then(function(result) {
                    scope.name = result.data.name;
                }, function(err) {
                    scope.name = "unknown";
                });
            });
        }
    }
}])

1 Comment

I'd suggest $attr.$observe would be more best angular way as per me ;)
1

Since javascript is asynchronous, your two ajax requests are running at basically the same time and id is undefined when the request in other-directive runs.

If you want to try testing this, just set a default value for idFromServer. The request in other-directive will run with the default value.

EDIT: in response to your comment, that is quite a broad question and there are many solutions. The best answer I can give you is simply, never ever run any logic in your link function, just define the directive's behavior and properties - that's what the link function is for. The template is used right away and you can't change that.

In this case, you could get the data prepared in a parent scope and pass the data in attributes.

1 Comment

That's what I was starting to think. With a default value, it works indeed well to get the correct json file for that default value, but how can I force "id" to be resolved before calling the template ?

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.