Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Massaging the DOM with AngularJS

Tags:

angularjs

I know manipulating the DOM goes against the rules of Angular but in this case, am having do transverse the DOM to modify a sibling node.

In jQuery you can do something like this:

$(this).parent().addClass('.loading');

While in Angular you would do something like this:

angular.element(this).parent().addClass('.loading');

Certainly this doesn't work because there is no parent() method or addClass() method support on the API.

Which brings me to the question, how else can I accomplish this?

Thanks!

like image 456
J Castillo Avatar asked Dec 21 '22 13:12

J Castillo


2 Answers

Angular elements are wrapped with jqLite by default (Angular's own jQuery implementation). If you have added jQuery to your project, then elements are wrapped with full jQuery.

Here's a list of methods available with jQuery lite http://docs.angularjs.org/api/angular.element

As you can see, you have access to parent() and addClass() So you get a lot of DOM manipulation power w/o adding jQuery as a dependency.

-*-

It's perfectly fine to manipulate the DOM with angular, the best practice is to do it from directives, here's a little example of an element having access to the parent element

HTML

<div ng-app='app'>
    <div id="someparent">
        <div my-directive>
        </div>
    </div>
</div>

In your JS

var app = angular.module('app', []);


app.directive('myDirective', function(){
    return{
        restrict: 'A',
        link: function(scope, element, attributes){
            console.log(element.parent().attr('id'));  // "someparent"
            element.parent().addClass('loading');    // adding loading class to parent
        }
    };
});​​​​​​​​​​​​​

jsfiddle: http://jsfiddle.net/jaimem/Efyv4/1/

Of course when building your app you might want to have directives manipulating only elements within itself.

-*-

Also, as Mark mentions, you can use angular's existing directives such as ngClass instead of creating your own. It's not clear what you want to achieve, but I recommend looking at ngCloak.

like image 136
jaime Avatar answered Dec 23 '22 03:12

jaime


In jQuery, we often have some event trigger, then from the element that triggered the event, we traverse the DOM to find some other element which is then manipulated. E.g., your example:

// some event causes this code to execute:
$(this).parent().addClass('.loading');

In AngularJS, we declare where the manipulation points are in HTML first (e.g., ng-class as @blesh suggests), then events modify $scope properties, and Angular does the DOM manipulation automagically for us. E.g.:

<div ng-controller="MyCtrl" ng-class="loadingClass">parent
   <a ng-click="loadingClass='loading'">child</a>
</div>

Controller:

function MyCtrl($scope) {
    // if you want some other class initially, uncomment next line:
    // $scope.loadingClass = 'notLoading';
}​

Above, clicking the "child" link modifies $scope.loadingClass. Angular will notice the change and apply the new class to the parent div.

For more complicated manipulations, a custom directive like @jm- shows would be required.

jQuery: events drive DOM traversal and DOM manipulation code (imperative).
Angular: events modify $scope and the magic happens (on our declarative HTML).

like image 36
Mark Rajcok Avatar answered Dec 23 '22 02:12

Mark Rajcok