I'm working on a project with AngularJS where I have an issue with 2 scopes conflicting:
- I have controllers defining scopes in different places of my DOM (it works great)
- I just added 3 directives to implement a "help" tooltip function just as chardin.js plugin in jQuery (http://heelhook.github.io/chardin.js/) : one main directive to be able to trigger them all at once, one 'child' directive on the trigger button, and one 'child' directive used to mark each DOM element on which I want the tooltip.
When I have only those 3 directives, it works great, but when I implement my controllers and my directives at the same time, I cannot use my controllers anymore (the scope seems to be completly wrong...)
The structure I have is something like this :
html -> main controller
4 sections -> 4 controllers
and I added 1 directive on the body (the main one), 1 directive to a button somewhere, and 1 directive on various elements of the 4 sections...
I'm aware my explanations are confused, but I really did my best for my first message here!
If you want to see at the code I have written for my directives, here it is:http://plnkr.co/edit/GrwgkH?p=preview
Thanks a lot for your help
S.
Try wrapping your controller's scope models in some object. Primitive values (e.g., number, string, boolean) are hidden in child scopes by its own property with the same name.
Read more in Understanding Scopes on AngularJS github wiki.
I ended up having issues with Primitive values as well. I ended up using sugar.js and Object.extended() to create a $scope.context object that I stored my model data on. This allowed for easy caching of the data as well.
Related
I am developing a page that has a news feed on it; when I think of it logically, this feed has several states on it (news, settings, favorites, etc.).
A feed should be able to be on many types of pages, such as for a product or a person or whatnot, so the way I understand it is that the feed itself should have states because their parent page can have all sorts of other states that the feed does not care about, and vice versa.
I can't figure out how to accomplish this -- at first I thought that I would be able to accomplish this using a named view on the parent page but can't figure out if a view can have a state, or how I would code that.
How should I be implementing this structure?
What you are looking for sounds a lot like a directive:
A directive usually has an HTML template associated to it
A directive backs this HTML template with a scope that can (and usually should) be independent of the page scope, with only a few explicitly defined parameters (values and/or functions) passed to it
A directive can define specific behaviours and functions, just as a regular page would via its controller
A directive can nonetheless communicate with its parent page, whether because it shares its scope (usually a bad idea) or because there is two-way binding of select fields
Optionally a directive can communicate with other directives (in your application, this could be useful if you define a "rss feed" directive and a "rss news item" for example)
The states would be variables, some of which you pass to your directive from your page, some you compute inside the directive. They would in turn parameterize the directive HTML template with the usual angular behaviours (e.g. ng-hide/show some subcomponents).
Angular directive doc : https://docs.angularjs.org/guide/directive
A good tutorial : http://www.sitepoint.com/practical-guide-angularjs-directives/
Does that answer your question ?
Why is injecting a Controller in a directive done through require but other dependencies through the array annotation?
Require a Controller
If you want to share the same instance of a controller, then you use require.
require ensures the presence of another directive and then includes its controller as a parameter to the link function. So if you have two directives on one element, your directive can require the presence of the other directive and gain access to its controller methods. A common use case for this is to require ngModel.
^require, with the addition of the caret, checks elements above directive in addition to the current element to try to find the other directive. This allows you to create complex components where "sub-components" can communicate with the parent component through its controller to great effect. Examples could include tabs, where each pane can communicate with the overall tabs to handle switching; an accordion set could ensure only one is open at a time; etc.
In either event, you have to use the two directives together for this to work. require is a way of communicating between components.
Courtesy of Josh David Miller
How to require a controller in an angularjs directive
For the array annotation reason take a look at this stuffs
Why is the function in angular's DI inline annotation a array element?
Controllers are never really injected into something else. When you use require, you're just gaining access to other controllers on the parent element or current element. These "other directives" have to exist on their own on the same element, or parent element, hence the name 'require.'
Another way of putting it is, with require you're not asking for something to be passed in, instantiated, or created, you're just saying "I want that to exist on this element... and oh by the way I can access it in the link function since I know it exists."
I have a page that has a number of directives. There are a number of directives in the header/navigation each with there own scope. There is also a ng-repeat of 25 items and each one of those creates a directive each with its own scope.
One of the directives includes a form that includes a custom filter to display form errors, it looks like this:
<span>{{ createProjectForm.name.$error | nagParseErrors }}</span>
Now the concern I have right now is that nagParseErrors is being executed about 33 times when anything in any scope changes even though this data createProjectForm.name is binded to (with ng-model) is only contained in the controller scope and the directive's scope containing the form (which is just being passed to the directive from the controller scope). I know it is related to the number of scopes (or directives) on the page because if I limit the ng-repeat from 25 items to 1, the filter is only called 9 times. This also happend for built-in filters (like json, and it even runs more times).
Is there something I might be doing wrong here or is this in fact how it should work in AngularJS?
BTW, I realize now that displaying the errors might be better off as a directive than a filter I am planning on going the directive route however I would like to clear up my understanding of filters here since I will probably run into this at some point down the road.
This has been addressed numerous times. All AngularJS expressions will be constantly re-evaluated throughout the lifecycle of the app. This is how two-way databinding in AngularJS works.
So, there's nothing wrong with your code. It's just that you need to make sure your filter is idempotent (returns the same output given the same input).
For more info take a look at Why Scope.$apply() calls $rootScope.$digest() rather than this.$digest()? and scope docs.
I have some issues regarding scope in nested directives. I have two directives: column and nested-menu. Their structure can be something like:
column
nested-menu
nested-menu
nested-menu
other content
nested-menu
other content
column
other content
The column has a variable to which all the nested-menu's should react. I have tried to make this work in several ways that I found Googling, such as broadcasting events from the column directive (for some reason, the nested-menu's only saw the event when I broadcasted it from $rootScope), setting a directive controller in column and storing the variable there (I can read it, but I can't $watch it).
It's important that both directives have an isolated scope, as they're supposed to be reusable in several areas, and sometimes even nested in themselves.
I have made a simplified Plnkr of a base structure, that's not working.
http://plnkr.co/edit/1GP7SKacO777og8PysNF
Thank you!
I am not sure how you want this to behave exactly. But here is a plunker that solves the two directives interacting with each other.
The nested-menu only expects column in its parent currently, But you could change it to expect another nested-menu in its parent if you wish.
Here is the working plunker. Hope this helps.
http://plnkr.co/edit/IAn9Ib8sSkQwKx6mpsm5?p=preview
These are the ways i tried to require one directive's controller in another one.
1) http://jsfiddle.net/Xarm2/1/
2) http://jsfiddle.net/82UKq/1/
In both the cases you can see in the firebug console, that the required directive's controller is either undefined or an empty object.
1) How can i access 'd1Cntrl' inside the d2 directive.
2)Please let me know one use case that will need me to require an directive controller in another directive.
See this nifty screencast from John Lindquist on directive to directive communication
For example, if you have an input element where you would like to apply two custom validations where one validation should only run if first validation passes (e.g. pattern matching validation should only activate if element has a value).
Few thinks i could like to put it here
1) Directives are not creating their own scope, For ex.
<superhero strength>The Hulk</superhero>
<superhero flight speed strength>Superman</superhero>
<superhero speed>The Flash</superhero>
these three directives will share the same scope, unless we explicitly say scope:true or scope:{} in the superhero definition. If you we are not creating new scope, then the last superhero will be in effect.
2) If we create a new scope at superhero level, that same scope is shared by the sibling directives like strength, flight etc..
3) If we require an directive controller inside another directive, the api that is defined on the directives controller using this keyword will be exposed to the requiring directive. Please note that the methods that are defined in the controller scope $scope wont be visible.
Please feel free to edit if the sentences making is wrong or the points were wrong.