How can I implement an Angular directive similar to ngAttr? This means a directive to match all the elements that start with a prefix.
Example: directive myDirective will match the attributes data-my-directive-first, my-directive-second and so on.
ngAttr* is handled in angular in a special way. There is hard wired logic only meant for directives with ng-attr prefix. So, it is not possible what you want to achieve. You can see the logic in collectDirectives function which is used by angular to collect directives from HTML nodes. Here:
https://github.com/angular/angular.js/blob/92374f9633d6121b115d77c10248e40e1f4f2aa1/src/ng/compile.js#L1759
My suggestion would be, have aliases' array and loop through to create directives with same function provided.
Related
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'd like to apply two attribute directives to an element - let's call them my-draggable and my-resizable - and I need to pass each one a callback for drag and resize completion actions. These directives are meant to be used independently if needed.
Now, for a single directive scneario I would do this
scope:{
callback: '&'
}
but if I do that for two, I know this way each directive will create its own isolated scope and that's a no-no, resulting in 'Error: $compile:multidir Multiple Directive Resource Contention'.
I'd very much appreciate some tips in handling this kind of situations.
Here's the fiddle showcasing my (non-functioning) scenario:
http://jsfiddle.net/crotundu/Ed9uP/2/
Thanks a lot!
I have updated your fiddle to call your callback functions in the link function you'll obviously want to change that.
Markup: (note the removal of the parenthesis on the callbacks)
<my-widget data-provider="data"
my-draggable drag-callback="dragDone"
my-resizable resize-callback="resizeDone"></my-widget>
Directives: (you will need to inject in $parse and remove the isolate scope)
$parse(scope[attrs.dragCallback])();
$parse(scope[attrs.resizeCallback])();
A simple example to explain my case:
I have a directive for labels
<input label="{{obj.label}}"/>
But for some other directives I want to use an attribute with name "label"
<other-directive label="My label"></other-directive>
just as an attribute, not processing the label-directive.
I could just rename the attribute to e.g. "my-label":
<other-directive my-label="My label"></other-directive>
but it would be nice to use "label" as an attribute name.
As #ExpertSystem points out in the comments to the question, angular really has no way of knowing out of the box whether your directive should be applied in one case versus another. The only way I can think of to get around this is to include logic in your directive's compile function that knows how to determine whether it should be applied or not. This plunker demonstrates how I would accomplish this. You basically need to return two different link functions from the compilation phase; one if your directive should be applied (in this case adding a label before the input), and a different one if it should be skipped. You are then free to use that as an argument to a separate directive. This may not work if your directive needs to do things like transclusion or isolated scopes (things that angular doesn't like two directives on the same element to do).
I'd be very sparing with how you use this, however, as it will create an inconsistent API for other developers who may be working with this code. They may not know when the directive will apply and when it won't.
I'm new to Angular JS. In my plunkr, I have a typeahead that works when I have the typeahead in the html markup. However, when I dynamically generate the html inside my directive, the typeahead no longer works.
Code Here:
http://plnkr.co/edit/KdrxptYAnpTmKa7ZuKkM?p=preview
and to take it one step further, when I pass in a function, it still does not work:
http://plnkr.co/edit/jqN913hJxuVSFAZxAQt7?p=preview
It is not a trivial problem you are trying to solve here, I'm afraid. Basically you are bumping into the scoping issue. The typeahead directive evaluates it expression (city for city in cities($viewValue) here) in the scope of the DOM element on which it is placed. The way you written your wrapper directive makes it so the expression is evaluated in the directive's scope which is isolated and doesn't "see" your controllers scope.
The are number of ways around it but probably the simplest one is to link your $compiled-ed element in the scope that is $parent of your directive scope:
var linkedInput = $compile(inputHtml)(scope.$parent);
Here is a working plunk: http://plnkr.co/edit/fLFwIKNqIRbnesMjZBGj?p=preview
The other alternative is to loose an isolated scope and "manually" take care of the 2-way data binding with the help from the $parse service.
Say I want to create 'desktop-only' and 'mobile-only' directives that hide or show an element based on and env test. There are a dozen ways I could go about it, but a cool one would be to "partially apply" the existing 'ng-show' directive. So 'desktop-only' would be the equivalent of, and actually delegate to, 'ng-show="env.isDesktop"' but without the need to do the env test in some parent controller and put env in my scope.
Another common example would be a tabs plugin. I could write a tab directive to show and hide elements using show and hide jQuery functions, but this would lose a lot of the functionality already in the ngShow directive. Couldn't I have my tab directive extend the ngShow directive in order to get access to all that variable parsing, integration with ngAnimate, etc...
Is this possible?
Thanks
When using isolate scopes you could manually proxy some variables into the scope: $scope.current.device = $rootScope.current.device;
Appart from that, you could use the afforementioned approach to put a device model on $rootScope and have methods and fields, such as 'hasTouch' that did calls to Modernizr and similar.
So yes, this is possible.