Angular JS and DOM readyness for jQuery

facebooktwittergoogle_pluslinkedin

Currently I’m writing a lot of HTML GUI Prototypes and I’m doing that with full Angular JS integration. This morning I faced a simple problem: I wanted to hide some control elements until the user hovers over the element.

Coming from the jQuery side, that’s how I wanted to solve that:

$(addCrudControls());

function addCrudControls() {
$('.crud').hide();
    $('.panel').hover(
        function() {
            $(this).find('.crud').show();
        },
        function() {
            $(this).find('.crud').hide();
        }
    );
});

custom.js

Notice the difference? You have to remove the brackets after the method. Otherwise you’re not passing the function but you’re calling the function and pass it’s return value instead.

So, pretty strait forward: Waiting for the DOM do be ready ($(handler) is just a simplified version of $(document).ready(handler)) and then bind your events to the elements you want.

This didn’t work with Angular JS if you’re using partial rendering with views. I had the following example:

    <!-- header and navigation stuff -->
    <div class="main">
    <!-- Angular JS loads the view in this part -->
    </div>
    </div>
</body>
</html>

index.html

Of course my .crud and .panel elements are then in the loaded view, so in a different file. The problem now is, that the ready event of the DOM is triggered before Angular loads the view and therefore the script is executed to early.

The solution is to use the angular listener $viewContentLoaded. So in your module, where you define your controller functions you add the following:

function stuffController($scope) {
    $scope.$on('$viewContentLoaded', addCrudControls);
}

module.js

And it should work!

Update!

Okay…it should work. It also does work, but it throws an ugly error due to a Typo on my side. This line:

function stuffController($scope) {
    $scope.$on('$viewContentLoaded', addCrudControls());
}

module.js

Should rather be:

function stuffController($scope) {
    $scope.$on('$viewContentLoaded', addCrudControls);
}

module.js

Notice the difference? You have to remove the brackets after the method. This way you’re passing the function and with the brackets you’re calling the function and passing its return value instead. Big difference for just a pair of brackets…

16 thoughts on “Angular JS and DOM readyness for jQuery

  1. Just looking into Angular now….is it a full replacement for jQuery or do the two work together, say the way Backbone and jQuery do?

    • Hi Terry,

      That depends on how you use jQuery. I ran into a couple of problems using both together and came to the following conclusion: You should not use two framework to manipulate the DOM structure of your application. If you do that, you will run into problems sooner or later.

      Therefore use Angular for most of your JavaScript features and use jQuery only for the “fancy effects”. Angular JS comes with certain functions from jQuery, they call it jqlite. Actually you can do most of the things you want to do with jQuery also with Angular, you just have to look into the API. And if you let Angular do the work, you won’t have any conflicts.

      For example the functions I’m talking about in this post, I now already solved with Angular instead of jQuery (I can show you that later) by writing a custom declarative. In fact I got rid of all jQuery functions within the last couple of days.

      Hope this answers your question.

      Cheers,
      Joel

  2. If jQuery is available then AngularJS will use jQuery, otherwise it uses it’s built in jqlite.

  3. Dear Joel,

    Thank you very much for the informative blogpost. I am a student and i am designing a website using Angular JS , Slim and the front end with HTML5 , PHP. I am confused how to integrate my front end with the back end using the business logic in jquery/php and angular js.

    It would be great help if you send me your application code so I can see how the integration of these technologies work.

    Thanks & Best Regards,
    BASMAH ALTAF

    • Hi Basmah,

      Unfortunately I can not just publish my application code as this is part of a project that belongs to the company I work for. But I can give you some hints wherever possible and will certainly also blog soon again about those technologies.

      Concerning PHP: Do you use a specific framework there? I used DooPHP in a past project to provide REST Services to my front end and I can recommend that. But there are certainly other similar projects which also help there.

      Anything in particular you’d like to get some help?

      Cheers,
      Joel

  4. I tried this, but it didn’t work:


    $scope.$on('$viewContentLoaded', function () {
    alert('loaded');
    } );

    Any idea what the problem might be?

    • Erm, no, I have no idea. I copy pasted the exact same code into my controller and it worked as expected. So I suggest you put that thing in the wrong place.

      Is it in your controller and and is the controller correctly bound to your DOM?

      Cheers,
      Joel

  5. Pingback: Build your own HTML code with Angular JS | alea iacta est

  6. Take a look at directives – that would be the cleanest way of solving this problem. The way you’re doing it will work but isn’t very ‘Angular’.

  7. Excellent/helpful writeup. This saved me some time.

    I converted my Jquery onready function to a named function and then fired it up from my controller using your suggestion:

    $scope.$on(‘$viewContentLoaded’, MyNamedFunc());

    Previously I was using dom selectors which were returning no matches, because the elements had yet to be added to the dom(I was also using angular views w/ templates).

    Thanks again!

  8. Pingback: Execute Document Ready Code on Angular Partials/Views « DullSharpness

  9. Hi Joel,

    Thanks for wonderful write up, but it didn’t work for me. I have a jQuery plugin to style radio and checkbox controls. when I call the function it doesn’t get element rendered by Angular.

    I tried putting up code the way you have mentioned but it still shows no element in DOM.

    Could you please suggest whats wrong I am doing?
    $scope.$on(“$viewContentLoaded”, function () {
    console.log( $(‘.controlwrapper input’));
    });

    Thanks,
    Sunder

Comments are closed.