Reputation: 15109
Is there a way I could emulate jQuery's .parents()
method in Angular, without having to actually include jQuery?
The final goal is to get all the parents of a DOM element.
EDIT: Why I need this?
I'm creating a directive (a dropdown-like widget). The dropdown should listen the entire <body>
for clicks and close itself (if it's open) if a click is made outside of the widget's area.
Now, I know how to create a simple directive that would listen for mouse events, like this one:
app.directive('mouseTrap', function() {
return function(scope, elem) {
elem.bind('click', function(event) {
scope.$broadcast('click', { event: event } );
});
};
});
...which I would then use like this: <body mouse-trap .... >
and
$scope.$on('click', function(msg, obj) {
console.log("click!");
});
That is where I need to check if any of the parents of the clicked object is the top-level div of my widget, and if not, close the widget.
Upvotes: 8
Views: 19146
Reputation: 2524
I'm not certain you'd want to be using DOM parent references when trying to interface with Angular controllers. But not knowing what your goal is, the standard methods .parentNode, is what you're looking for. Then you'd have to loop until you hit body, or html, or null. So if you want native javascript:
var currentParent = nodeToFindParentsOf.parentNode();
var parents = [];
while(currentParent){
parents.push(currentParent);
currentParent = currentParent.parentNode();
}
I'm also paranoid of while loops. So would tend to wrap that whole thing in a function and put a safety valve on it to let me know what's going on, in case of crazyness in my code or in the DOM, so I'd get a clean error, instead of locking up the browser.
function getAllParentsOfNode (nodeToFindParentsOf) {
var currentParent = nodeToFindParentsOf.parentNode();
var parents = [];
var safetyCount = 1000;
while(currentParent){
parents.push(currentParent);
currentParent = currentParent.parentNode();
if (--safetyCount === 0) {
throw new Error("Something went wrong. Found 1000+ parents!")
}
}
return parents;
}
Upvotes: 4
Reputation: 1229
EDIT: Although this answer was accepted, it's not correct. See comment and better answers below.
It does look like jQLite supports this already so if you're using angular you should be able to do this without pulling in JQuery itself.
From the docs here:
Supported instance methods: (links to jQuery Docs) A subset of the operations which jQuery supports are currently implemented. All of them are implemented using the chained operation syntax of jQuery. e.g:
$("div.foo").each(function() {
$(this).removeClass("foo").addClass("bar");
});
$("div.bar, div.baz").css({ "border": "1px solid red" }).children().addClass("child");
.parent([selector)]
.parents([selector)]
Upvotes: -2
Reputation: 3774
Angularjs includes jqLite which contains some of the jQuery functions. details here: https://docs.angularjs.org/api/ng/function/angular.element
As noted in the site, it includes
parent() - Does not support selectors
The function provided is similar to the jQuery parent() function but will not take selectors, so you wont be able to filter using selector. From the jQuery documentation:
This method is similar to .parents(), except .parent() only travels a single level up the DOM tree
So short answer: no it doesnt. But it does provide a small subset of it.
Upvotes: 3
Reputation: 184
Angular's jqLite supports parent()
method, so you could get all the parents in a loop like this:
var p = element.parent();
var allParents = [];
while (p.length > 0) {
allParents.push(p[0]);
p = p.parent();
}
Upvotes: 7