Reputation: 10887
I have been developing an advanced web-based GUI in AngularJS. Recently, I decided to use the call document.getElementsByClassName()
(I hate using element collecting methods, but here I had to use one) and my boss flipped his lid for accessing the document
element. He says that I "need to use only Angular calls for everything", even for element collection! Is there an "Angular way" to collect elements by class name? If so, which way is better to use within the Angular framework? Please provide reasons why. Thanks!
UPDATE: Why I need to use an element collector...
So, I really wish I didn't have to do this, but I do...
I am using a third-party directive that I found online called the Bootstrap DateTimePicker. Its pretty cool and very nice looking, yet it might have a bug...
First, I make a directive bound to an attribute, stating that the element I pass in is meant to be a "DateTimePicker". I then pass that element to the DateTimePicker
function.
When invoked, this function creates a new div with absolute positioning and appends it to the body of the page.
Now, I open a dialog in my GUI that has a table in it. On each row of the table, I have two DateTimePickers
: one for end-date and one for start-date.
My problem is that, once I leave my screen and the elements which the DateTimePickers
were bound to are destroyed, the DateTimePickers
still remain! If I open the dialog box again, it creates a ton more of these divs as well!
Until I could determine a true solution to this issue, I decided to use the element collector as a temporary quick-fix. I grab all of the elements with the datetimepicker
class and perform a:
elem[i].parentNode.removeChild(elem[i]);
Upvotes: 0
Views: 154
Reputation: 10887
Well, I have my answer. This does not solve the question "Grab all elements with a certain class name without touching the document element" yet it does solve my problem and eliminates my need to use document.getElementsByClassName
.
First of all, it turns out that every element using the DateTimePicker directive have an element.datetimepicker("remove")
function.
I use a directive for each DateTimePicker
:
components.directive('DateTimePicker', function() {
// Requires bootstrap-datetimestamp.js
return {
restrict: 'E',
replace: true,
scope: {
dateTimeField: '='
},
template:
'<div>' +
'<input type="text" readonly data-date-format="yyyy-mm-ddThh:ii:ssZ" data-date-time required/>'+
'</div>',
link: function(scope, element, attrs, ngModel)
{
var input = element.find('input');
input.
datetimepicker(
{
//stuff
})
.on('changeDate', function(ev)
{
//more stuff
});
...
Directive drastically shortened for the sake of your eyeballs...
I then need to remove the DateTimePicker
and the input
it is bound to from the DOM on destruction of the dialog box that the input
is a child of. To do so, I added this to my directive:
scope.$on("$destroy",function handleDestroyEvent()
{
input.datetimepicker("remove");
input = null;
});
And it works! The DateTimePicker
gets removed, the DateTimePicker
's handles to the input
are cleaned up, and I've marked my input
for the GC! WooHoo! Thanks everybody!
Upvotes: 1
Reputation: 3497
Not having your exact use case but knowing that you are attempting to aggregate elements by class name in your controller makes me agree with you boss. Think of the controller as an object which exposes data and and services to your declarative html page. The data is bound into the markup for presentation and possible modification. THe services are usually wrapped in functions on your controller which are then tied to event handling directives like ng-click or ng-change. These services should operate exclusively on your data and never touch the DOM. If you need to modify a DOM element in your declarative markup then that should be done through directives like ng-class etc.
In any case, It would be useful to know what you are trying to accomplish so as to give you a better idea of the "angular way" to approach the problem.
Upvotes: 2
Reputation: 2312
If you include jQuery in your project before AngularJS, Angular will use jQuery instead of jqLite for the angular.element
function. This means you should be able to use jQuery's selectors for finding / referencing DOM elements.
Upvotes: -1