Confusing attributes in angularjs directive's link function - angularjs

I'm writing an angular.js directive, which would conditionally hide the element.
So it would look like this:
link: function(scope, elem, attrs) {
...
elem.hide()
}
I found a lot of examples that were doing exactly that, but somehow my elem attribute is an array not an element, so it does not have a hide() method.
What am I missing?
Thanks!

Most people are loading jQuery before they load angular, which extends its jqLite to the full jQuery.
The hide method doesn't seem to be part of jqLite API (https://docs.angularjs.org/api/ng/function/angular.element), hence such method is not exposed.
That doesn't mean you need jQuery, but that it is not the correct way to handle your problem. There are already the ng-show and ng-if directives to conditionnaly hide an element based on the controller, couldn't you use them?
In your html, add <div ng-show="isDisplayed">, and in your linking function scope.isDisplayed = false

Related

Angular JS manipulating dom by element from link function

we know that we can access dom from directive by element because element is injected in link function.
see the approach
var app = angular.module("myApp", []);
app.directive('busyBox',function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.on('click', function(){
if(attrs.id=='btnadd')
{
var divElement = angular.element(document.body.querySelector('.parent')).append('<div class="child">Some text</div>');
// console.log(divElement);
// element.parent().find('.parent').append('<div>Some text</div>')
//element.closest('.parent').append('<div class="child">child</div>')
//angular.element(document).find('.parent').append('<div class="child">child</div>');
}
else if(attrs.id=='btnDel')
{
angular.element(document.body.querySelector('.child')).remove();
// m.removeChild(m.firstChild);
}
});
}
}
})
the above code is working but if i do not use angular.element() instead if i use element(document.body.querySelector('.parent')) the code is not working.
the element is injected in link function link: function(scope, element, attrs)
when element is there in directive then why should i use angular.element() ?
please tell me how could i use element from directive to access dom instead of angular.element().
thanks
The element exposed to the postLink function is a jqLite class object which is a tiny, API-compatible subset of jQuery that allows AngularJS to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most commonly needed functionality with the goal of having a very small footprint.
The find() method is limited to lookups by tag name. If you want the find() method to work with class selectors, load jQuery before the angular.js file.
If jQuery is available, angular.element is an alias for the jQuery function. If jQuery is not available, angular.element delegates to AngularJS's built-in subset of jQuery, called "jQuery lite" or jqLite.
To use jQuery, simply ensure it is loaded before the angular.js file. You can also use the ngJq directive to specify that jqlite should be used over jQuery, or to use a specific version of jQuery if multiple versions exist on the page.
— AngularJS angular.element API Reference
Can't we use element. closest function instead of find to get the div?
The jQuery closest function is not part of AngularJS jqLite. To use the closest function with the element value exposed to the directive postLink function, load the jQuery library before loading the AngularJS library.
For the list of jqLite functions, see AngularJS angular.element API Reference
please tell me how could i use element from directive to access dom instead of angular.element()
If you want to use the element object that is passed into the link function of the directive to manipulate the DOM, you have to use various methods that the element object exposes, like find.
Do not use it like this:
element(document.body.querySelector('.parent'))
Instead you can do:
// works only if you are using jQuery
element.find('.parent');
// for JQLite, the find method is limited to lookup by tag name:
element.find('div');
Note that as mentioned in the answer from #georgeawg, that you might be using JQLite or JQuery ... where the JQLite functionality is not as full featured as JQuery.

jQuery used inside Angular

I know this is a subject discussed too many times. I know that jQuery may create problems. I know most sites advise try to avoid the use of jQuery, however my question is:
How may I manipulate the DOM inside an Angular directive if not using jQuery? Even in Angular docs there is intensive use of jQuery lite inside directives. I 'd appreciate your opinions in that.
In link function you can actually manipulate DOM.
app.directive('sampleDirective', function() {
return {
...
link: function(scope, ele, attr, ctrl) {
//here actually you can manipulate DOM using ele.
}
}
})
Angular has bilt-in jqLite(subset of jQuery). Find it here.
Note: Do DOM manipulations only in directive.

Dynamic template depending on dropdown user selection

Trying to use dynamic template that should change depending on user selection.
so when a dropdown option is selected then load another html template.
I like to do this cleanly and in a modular way with controller that can be uni-tested.
I have been reading this
https://coderwall.com/p/onjxng/angular-directives-using-a-dynamic-template
Others include using
ng-include to load the template
Anyone knows of better way to implement?
You can use $templateCache and $compile in your directive. It is not always a better way, depending on what you want to achieve.
link: function (scope, element, attrs) {
$templateCache.get('yourtemplate.html').then(function(tmpl) {
element.html(tmpl);
$compile(element.contents())(scope);
});
}
You get the idea: you can also have a directive acting as a proxy to other directives by not using $templateCache and adding directly to your element the markup for another directive (and compiling it).

Angular directive doesn't work for elements added to the DOM by jquery plugin

I'm creating a fall back image directive that looks like this http://plnkr.co/edit/wxy4Sp2K02iXoQNsvkah
angular.module('directives').directive('myDirective', function() {
return {
restrict: 'C',
link: function(scope, element, attrs) {
console.log('linking');
}
}
});
My directive doesn't work for elements that are added to the DOM by the typeahead.js plugin (https://github.com/twitter/typeahead.js).
<div class='tt-suggestion'>
<div><span class="my-directive">bla</span></div>
</div>
I guess it's because Angular is not informed about the elements that are added by jQuery and hence it doesn't invoke the directive. How do I notify Angular of these changes?
You can use the Angular compile service to do this: http://docs.angularjs.org/api/ng/service/$compile
Basicly it works like this:
document.getElementById("test").innerHTML = $compile("")($scope);
ideally you shouldnt be mixing jquery and angular because they both are based on different philosophy.
jquery-- is event driven i.e. have event listeners which cause changes to model and then the programmer has to code numerous lines to change the view i.e. changing css,text etc
angular-- woo hoo! just change the model which is binded to $scope and :) your view is automatically updated
to automatically react on changing of such events angular has a compiler which studies entire html code before the app is loaded so even if there is a template which you might use later you must enclose it in so that angular compiles this so that all the special angular directive and controller perform as expected even when you remove or add templates to the dom.
here you are using typehead.js and jquery to manually manipulate the view which is against angular philosophy because when you do such maipulation angular compiler wouldnt be aware of it as it runs only when the app is initialized. Thats why before appending you should use $compile to make the angular compiler aware of this template .
in your case i would suggest the typehead present on this url
http://angular-ui.github.io/bootstrap/

Directive requiring a parent

I need a directive ngTree to get the controller of a parent ngTree element. Note that require: "^ngTree" would return the controller of current directive.
I know I could do a ngTreeHelper and put a div with it, between any two ngTree divs and require: "^ngTreeHelper" would work, but it's ugly. I wonder if there is something else I could do.
There's not a great built in way to do this. However it is done in angular's form directive.
Swiping the code from there, this is what you need
var ngTreeController = $element.parent().controller('ngTree');
This is in the form directive's controller, but you should be able to do this from a link function too.

Resources