4 ms·
One nit-pick, isolate scopes (that is where you do `scope: { 'property': '=' }) are not the only (or even the best) way to bind data to a directive. In fact if
by lucisferre 13y ago
One nit-pick, isolate scopes (that is where you do `scope: { 'property': '=' }) are not the only (or even the best) way to bind data to a directive. In fact if you look at the AngularJS internals it's pretty much never used and instead they just use the current scope (whatever scope that directive is declared in).
This can be done by calling `$scope.$watch(attrs.myBinding)` directly with expression values passed in through element attributes. If necessary `scope: true` can be used create a child scope that inherits from the current scope. This is a good idea if your directive uses it's own controller. However this isn't necessary for most simple directives.
An isolated scope does exactly that, creates a scope for the directive completely isolated from the prototype chain of the containing scope (and thus the application's scope). This is used for complex directives like ng-repeat that need to create and expose their own scopes with the templates that you put inside the repeat blocks.
I know I initially fell into the trap of using isolate scopes to solve this problem. After looking through Angular's own directives for examples I learned other approaches.
I'm not sure exactly what the considered best practices are here (because there is almost no detail on issues like this in the documentation) but at least basing it off how the Angular core team builds their own directives I would suggest avoiding isolate scopes unless scope isolation is specifically necessary.
- embwbam 13y agoInteresting. I started with $scope.$watch(attrs.myBinding) first, and switched it to isolate scopes after doing more research. I'd be interested to hear if someone who knows for sure could chime in as to what the best practice is and why. I can update the article to match.
- cjcenizal 13y agoI really enjoyed your post. I agree that it's a good "directive smell" if your directive is reusable and application-agnostic. In that vein, I think you're right that an isolate scope is generally a better default because it makes it clear that the directive expects no dependencies on the inherited scope, and it prevents the directive from overwriting any scope properties set by an ancestor. I think using an inherited scope makes sense if you're building very app-specific directives that are tightly-coupled to their ancestor.
- mortalapeman 13y agoA single element cannot have more than once isolated scope. It only makes sense to use an isolated scope when a directive has a template associated with it. Otherwise, one should rely on the $parse + the "attrs" object + $scope.$watch to correctly handle expressions.
- embwbam 13y agoThat seems strange. What happens if two attribute directives ask for an isolate scope? Does it give them the same one, or just fail? I used isolate scopes in the article because I thought they were easier to understand, but I'm thinking of updating it.
- embwbam 13y agoAfter looking into it, angular seems to throw an error if two directives ask for an isolate scope.
- yesimahuman 13y agoI had the same issue learning directives. In particular, I had a hard time getting "container" directives working right with isolated scope. I've come up with a rule of thumb: if this directive is a small, self-contained widget, opt for isolated scope. If not, keep it simple and either not create any scope (for really basic wrapper directives), or create a new scope using the scope prototype chain. But I still have a ton to learn, so I'm not sure that's the best approach.
- RaphiePS 13y agoThe problem with isolate scope is that you need to pass in all the data through attributes. This is great if you want something reusable that won't collide. My rule of thumb is that if it's got its own template, it should be isolated. However, this can really bite you in the butt. If you're doing something like <div my-directive>{{foo}}</div> where my-directive uses isolate scope, {{foo}} is broken. So I'd never use isolate scope for an attribute directive.
- gtremper 13y agoI thought you could do this since the scope of the transcluded part is a sibling to the isolate scope. "The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope. In a typical setup the widget creates an isolate scope, but the transclusion is a sibling (rather than a child) of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope." http://docs.angularjs.org/guide/directive http://docs.angularjs.org/guide/directive
- RaphiePS 13y agoOoh, I didn't consider transclusion. For the example I used (an attribute directive), would I make its template literally <div ng-transclude></div>