sgarcia.dev
sgarcia.dev

Reputation: 6170

AngularJS - Dynamic DOM manipulation without hardcoding dom id's in the controller

I'm still getting started with angular, and it seems that the "Angular way of things" is to separate the view from the controller, and as such, my DOM manipulation in angular seems very clunky so far since I have to do a lot of manual dom element selecting. My app currently looks something like this;

HTML:

<div ng-controller="appController as appCtrl">
    <div>
        <div id="element1"></div>
        <div id="element2"></div>
        <div id="element3"></div>
        <button ng-click="appCtrl.animateStuff()"></button>
    </div>
</div>

CONTROLLER:

app.controller('appController', ['animationFactory', 'domFactory', appControllerFunc]);
function appControllerFunc(animationFactory, domFactory) {
    This = this;
    This.animateStuff = function() {
        animationFactory.animate(domFactory.getNgElementById('element1'));
        animationFactory.animate(domFactory.getNgElementById('element2'));
        animationFactory.animate(domFactory.getNgElementById('element3'));
    }
}

FACTORIES:

app.factory('domFactory', [domFactoryFunc]);
function domFactoryFunc() {
    var domFactoryContainer = {
        getNgElementById: function(id) {
            return angular.element(document.getELementById(id));
        }
    }
    return domFactoryContainer;
}

app.factory('animationFactory');
function animationFactoryFunc() {
    var animationFactoryContainer = {
        animate: function(ngelement) {
            // animates ngelement
        }
    }
    return animationFactoryContainer;
}

Is there a way to somehow send DOM elements to the controller from the view's ng-click? Something like ngclick="ctrl.animateStuff([#element1],[#element2],[#element3])" so my controller just needs to get the parameters and manipulate them without even knowing anything about the DOM? Or can directives be used for this? if so, how?

Upvotes: 1

Views: 743

Answers (2)

orange
orange

Reputation: 8090

If you can't use Angular's ngAminate (which doesn't require DOM manipulation as it uses css), you can build a custom directive. Directives are where DOM manipulation is allowed and you'd get the actual element passed into the directive, so there's no need for hard-coded ids.

But I recommend following @NewDev's suggestion.

This would be a possible stub for the directive:

module.directive('myAnimation', function() {
  return {
    restrict: 'A',
    scope: {
      enabled: '='
    },
    link: function(scope, element) {
      // watch on enabled and start animation when set to true
    }
  }
});

And your markup:

<div my-animation enabled='enabled'></div>
<div my-animation enabled='enabled'></div>
<div my-animation enabled='enabled'></div>
<button ng-click="enabled=true"></button>

Upvotes: 1

New Dev
New Dev

Reputation: 49590

To unblock you right now, you could do

<div id="element1" ng-click="ctrl.animateStuff($event)"></div>    

that would pass the event to your function and you could extract the DOM element from it.

I'm not familiar with GSAP, but you should be able to hook it into ngAnimate-way of doing things.

And, I would repeat myself - DON'T access or make any assumption about the DOM in your controller - you are breaking Angular's best practices and will often find yourself with problems and headaches.

Upvotes: 0

Related Questions