1

I'm using AngularJS to dynamically create a page. I have some Tab (jquery) click handlers that were working fine on a previous, static version of the page.

The problem is, the $(.prevButton) and $(.nextButton) elements are created by AngularJS and evidently Jquery doesn't register them. I can paste the following code in the console once the page has been created, and all works fine.

How can I force jquery to "rescan" the DOM so that it registers all of these dynamically created elements? Or is there another technique to avoid this problem?

$(document).ready(function () {
    $('.prevButton').click(function () {
    var r = $(this).attr('tabGroup');
    var e = ($('.nav-tabs[tabGroup=' + r + '] li.active').prev().find('a[data-toggle="tab"]'));
    if (e.length > 0) {
        e.click();
    }
    return false; //prevent the page from jumping around
});

$('.nextButton').click(function () {
    var r = $(this).attr('tabGroup');
    var f = ($('.nav-tabs[tabGroup=' + r + '] li.active').next().find('a[data-toggle="tab"]'));
    if (f.length > 0) {
        f.click();
    }
    return false; //prevent the page from jumping around
});
}

Many thanks for any tips!

5
  • It says right in the angular docs not to use jquery as a crutch to do dom manipulation but instead write directives and use the angular events! Commented Mar 22, 2013 at 21:37
  • @NickLarsen I'm not manipulating the dom, am I? Commented Mar 22, 2013 at 21:40
  • 1
    adding handlers and firing events, I'd say you're manipulating the DOM. Commented Mar 22, 2013 at 21:44
  • Attaching events to elements is manipulating the DOM, you can even see the handlers in a console inspector. I have added some links to the manual, but I cannot help your specific case without seeing your HTML, otherwise the best I can show you is what's in the manual. Commented Mar 22, 2013 at 21:52
  • if the tabs are a jQuery plugin, should be fairly easy to integrate as an angular directive. Not clear what the click handlers for f.click(); do. All you've shown is an inefficient prev/next system Commented Mar 23, 2013 at 14:28

2 Answers 2

2

Get rid of the usage of jQuery. Use the ngClick directive to specify which functions to call on element click and add functions to the current scope (that's what an angular controller is good for) to handle those clicks.

From the comments, in angular one of the most amazing features is that you do not rely on the DOM to maintain state, instead you store it all in scope. If you want to change something, you modify the scope and let the rendering/event delegation/etc take care of itself through the framework.

This is a really rough example, and I have not tested it in a browser, but it's fairly typical of angular.

The HTML:

<div ng-controller="ExamplePagingController">
    <div class="previous" ng-click="previousPage()" ng-class="{ disabled: currentPage == 0 }"></div>
    <ul ng-repeat="(idx, page) in pagedItems" ng-show="idx == currentPage">
        <li ng-repeat="item in page">{{ item.someDisplayProperty }}</li>
    </ul>
    <div class="next" ng-click="nextPage()" ng-class="{ disabled: pagedItems.length == 0 || currentPage == pagedItems.length - 1 }"></div>
</div>

The angular stuff:

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

exampleModule .controller('ExamplePagingController', ['$scope', function ($scope) {
    $scope.items = someExternalVariableOrAngularServiceCall();
    $scope.currentPage = 0;
    $scope.pageSize = 5;
    $scope.pagedItems = [];

    $scope.groupToPages = function () {
        $scope.pagedItems = [];
        for (var i = 0; i < $scope.items.length; i += 1) {
            var pageIndex = Math.floor(i / $scope.pageSize);
            if (i % $scope.pageSize === 0) {
                $scope.pagedItems[pageIndex] = [$scope.items[i]];
            } else {
                $scope.pagedItems[pageIndex].push($scope.items[i]);
            }
        }
    };

    $scope.previousPage = function () {
        if ($scope.currentPage > 0) {
            $scope.currentPage -= 1;
        }
    };

    $scope.nextPage = function () {
        if ($scope.currentPage < $scope.pagedItems.length - 1) {
            $scope.currentPage += 1;
        }
    };

    $scope.groupToPages();
}]);
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks Nick. Could you give me a search term to help me learn how to do the 'click next active item in tab group' magic I'm able to do with Jquery?
Generally in angular that's not what you want to do, instead you want to edit the model (scope) and let the framework takeover updating the dom for you. Since this is doing paging, i'll give you a small example in a few moments (time to type it up).
@Stewie- I don't know yet- haven't figured it all out. I'm working on it.
@NickLarsen Many thanks- This looks impressive- more tricky than I was hoping to get into, but if I can wrap my head around it I'll be good. Trying to work through it today. Cheers!
@Hairgami_Master sounds good, just remember the biggest change in thinking you have to make when thinking about angular is that the model is the only thing you should be modifying, the rest should take care of itself.
|
0

You'll need to give more context to your DOM query since they were created dynamically. You should also be using the .on syntax in later versions of jQuery. http://api.jquery.com/on/

$(document).on('click', '.nextButton', function () {
    //your code
}); 

1 Comment

Many thanks @Jack. Folks seem to be against using any Jquery at all, a lot of code in Angular to avoid using JQuery but I'm trying to see where to draw the line right now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.