简体   繁体   中英

AngularJS ng-click not calling function on scope

I have a custom directive which loads a navigation block from a webservice call. I am trying to click on one of those navigation links which I put a "ng-click" in. I am trying to click on the link which should call the function called within the ng-click. That function should execute, but it is not.

Here is my routing

var cartangularPublicShoppingApp = angular.module('cartangularPublicShoppingApp', [
  'ngRoute',
  'CategoriesController',
  'CategoryServices',
  'CategoryNavigationServices',
  'MenuModule'
]);
cartangularPublicShoppingApp.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.
            when('/cart', {
                templateUrl: 'partials/public/cart.html',
                controller: 'CartCtrl'
            }).
            when('/categories/:categoryId', {
                templateUrl: 'partials/public/categories.html',
                controller: 'CategoriesController'
            }).
            otherwise({
                redirectTo: '/categories'
            });
    }]
);

Here is the custom directive

angular.module('MenuModule', [])
.directive('myCustomer', function() {
        return {
            restrict: 'E',
            templateUrl: './partials/public/customer.html',
            controller: function($scope, $sce, CategoryNavigationService) {

                var z = CategoryNavigationService.getCategoryNavigation().success(function(data){
                    $scope.categoryNavigation = data;
                    var navHTML = createCategoryNavigationBar(data);
                    var t = $sce.trustAsHtml(navHTML);
                    $scope.panes = t;

                }).error(function(data){

                        var error = "Get confident, stupid!";
                        var t = $sce.trustAsHtml(error);
                        $scope.panes = t;
                });
                function createCategoryNavigationBar(categoryNavigation){
                     var test = "";
                    var categoryId;
                    var catNavArray = categoryNavigation.categoryNavigationArray;
                     for(categoryId in catNavArray){
                         var currentCategoryNavigation = categoryNavigation.categoryNavigationArray[categoryId];
                            var string =  '<li> <a href="javascript:void(0);" name="categoryId" ng-click="getProductsForCategory()">' + currentCategoryNavigation.categoryName + "</a>";
                            test = test + string;

                         var count = 0;
                         var countingNavArr = currentCategoryNavigation.categoryNavigationArray;
                         for(var countingObject in countingNavArr){
                             count++;
                         }
                         if(count > 0){
                             var innerCategoryId;
                             test = test + "<ul>";
                             for(innerCategoryId in currentCategoryNavigation.categoryNavigationArray){
                                 var innerCategoryNavigation = currentCategoryNavigation.categoryNavigationArray[innerCategoryId];
                                 var innerTest = createCategoryNavigationBar(innerCategoryNavigation);
                                 test = test + innerTest;
                             }
                             test = test + "</ul>";
                         }
                         test = test + "</li>";
                    }
                    test = '<ul id="menu">' + test + '</ul>';
                    return test;



                }

            }
        };
    });

Here is the controller that get's routed to my html fragment that I am showing the directive in.

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

categoriesControllers.controller('CategoriesController', ['$scope', '$routeParams' , '$location', 'CategoryService',
  function($scope, $routeParams, $location, CategoryService) {

      var categoryId = $routeParams.categoryId;
      getProductsByCategoryIdServiceCall(CategoryService, categoryId);

      $scope.getProductsForCategory = function(){
          var categoryId = 4;
          getProductsByCategoryIdServiceCall(CategoryService, categoryId);

      }
      function getProductsByCategoryIdServiceCall(CategoryService, categoryId){
          CategoryService.getProductsByCategoryId(categoryId).success(function(data){
              $scope.productsDTO = data;
              $scope.name = "David M Pugh";
          }).error(function(data){
                  $scope.name = "David Q Pugh";
                  $scope.name = data;
          });

      }

  }]);

Here is code fragment from categories.html that contains the custom directive:

   <div class="row-fluid">
        <div class="span12">
            <div class="navbar">
                <div class="navbar-inner">
                    <div class="container" style="width: auto;">
                        <div class="span5"></div>
                        <div class="span2">
                            <div id="currentCategoryDropBoxMenu">

                            </div>
                        </div>

                    </div>
                </div>
            </div>
        </div>
    </div>
    <br />
  <my-customer></my-customer>
    <br />

I have tried changing the javascript method called inside ng-click to be like: ng-click="getProductsForCategory" as well.

both results in the method getProductsForCategory not being called when the link is clicked

Does anyone have any idea what my problem is?

thanks,

David

EDITED INFO* Hey folks, thanks for looking into this problem. It is still ongoing, but I added an extra test to my html fragment for my custom directive

<div ng-bind-html="panes"></div>
<a href="javascript:void(0);" ng-click="getProductsForCategory()">testing</a>

Before the only line was the first tag which was the div. I added the 2nd line to see if it was perhaps the binding of the html directly to the div tag in the directive, or if there was a problem with the directive's configuration elsewhere.

The second tag I added should be a standard ng-click operation. my 2nd a href tag does call the function getProductsForCategory(). So it does appear to be due to my binding of my html string to the div element for the directive.

The problem is that my navigation structure i am building can have infinite nested child elements (it's basically a suckerfish select box).

This means I will have to use recursion to map out every parent child navigation structure...in a directive...

You are missing a set of braces in ng-click markup

ng-click="getProductsForCategory"

Should be

ng-click="getProductsForCategory()"

I came up with a solution for my project. Here is the routing section

var cartangularPublicShoppingApp = angular.module('cartangularPublicShoppingApp', [
  'ngRoute',
  'CategoriesController',
  'CategoryServices',
  'CategoryNavigationServices',
  'MenuModule'
]);
cartangularPublicShoppingApp.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.
            when('/categories/:categoryId', {
                templateUrl: 'partials/public/categories.html',
                controller: 'CategoriesController'
            })
    }]
);

This is the main controller for the view (categories.html) that will be used to show off our custom directive. I created a test dataset called "treeFamily" that I will use to test the directive in this controller

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

categoriesControllers.controller('CategoriesController', ['$scope', '$routeParams' , '$location', 'CategoryService',
  function($scope, $routeParams, $location, CategoryService) {

      $scope.treeFamily = {
          name : "Clothes",
          categoryId : "4",
          children: [{
              name : "Clothes",
              categoryId : "3",
              children: [{
                  name : "Men's Clothes",
                  categoryId : "2",
                  children: []
              },{
                  name : "Jackets",
                  categoryId : "1",
                  children: [
                      {
                          name : "Light Jackets",
                          categoryId : "4",
                          children: [{
                              name : "Natural Material",
                              children: []
                          }
                          ]
                      },{
                          name : "Heavy Jackets",
                          categoryId : "3",
                          children: []
                      }]
              }, {
                  name: "Pants",
                  categoryId : "4",
                  children: []
              }]
          }]
      }

Here is the directive that we will use to recursively traverse our dataset.

angular.module('MenuModule', [])
.directive("tree", function(RecursionHelper) {
    return {
        restrict: "E",
        scope: {
            family: '=',
            'product': '&products'
       },

        templateUrl: './partials/public/family.html',
        compile: function(element) {
            return RecursionHelper.compile(element);
        }
    };
})

This is a compiling service that I found someone demonstrating online. I decided to use it, as it keeps our code neat and clean.

var categoryNavigationServices = angular.module('CategoryNavigationServices', []);
categoryNavigationServices.factory('RecursionHelper', ['$compile', function($compile){
    var RecursionHelper = {
        compile: function(element){
            var contents = element.contents().remove();
            var compiledContents;
            return function(scope, element){
                if(!compiledContents){
                    compiledContents = $compile(contents);
                }
                compiledContents(scope, function(clone){
                    element.append(clone);
                });
            };
        }
    };

    return RecursionHelper;
}]);

This is the html fragment for our directive. Note how we are calling the directive from within the directive.

<a href="javascript:void(0);" name="categoryId" ng-click="product(family.categoryId)">{{ family.name }}</a>
<ul>
    <li ng-repeat="child in family.children">
        <tree family="child"  products="products(child.categoryId)"></tree>
    </li>
</ul>

Here is part of my categories.html page which is the main view from my controller.

    <ul>
            <li ng-repeat="object in treeFamily.children">
                <a href="javascript:void(0);" name="categoryId" ng-click="products(object.categoryId)">{{object.name}}</a>
                <ul>
                    <li ng-repeat="child in object.children">
                        <tree family="child" products="products(child.categoryId)"></tree>

                    </li>
                </ul>
            </li>
   </ul>

The main problem I was having after i got the recursive directives working was that my ng-click that I added to the directive's html was not responding when clicked. This was because the scope on the directive was an isolated scope.

In order to access the main controller's method, you have to bind the directive's method to the controller's method. in order to do this you have to add the controller's function you want to bind to within the tag its'self. ie:

<tree family="child" products="products(child.categoryId)">

and the directive's isolated scope references this ie:

scope: {
            family: '=',
            'product': '&products'
       },

The a href inside the directive's html is as such:

<a href="javascript:void(0);" name="categoryId" ng-click="product(family.categoryId)">{{ family.name }}</a>

note that we reference the directive's function "product", and not products, which is the name of the method on the controller that we wanted access to.

The one thing that seems problematic that you didn't compile HTML in directive. This is a reason that ng-click doesn't work because angular doesn't see this change.

var string =  '<li> <a href="" name="categoryId" ng-click="getProductsForCategory()">' + currentCategoryNavigation.categoryName + "</a>";

when you call:

 var navHTML = createCategoryNavigationBar(data);

try to write something like:

var temp = createCategoryNavigationBar(data);
var navHTML = angular.element(temp)($scope));

maybe it will help,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM