【问题标题】:AngularJS ng-click not calling function on scopeAngularJS ng-click不在范围内调用函数
【发布时间】:2013-11-16 18:04:58
【问题描述】:

我有一个自定义指令,它从 web 服务调用加载导航块。 我正在尝试单击其中一个“ng-click”导航链接。 我正在尝试单击应该调用在 ng-click 中调用的函数的链接。该函数应该执行,但不是。

这是我的路线

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'
            });
    }]
);

这是自定义指令

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;



                }

            }
        };
    });

这是路由到我在其中显示指令的 html 片段的控制器。

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;
          });

      }

  }]);

以下是 categories.html 中包含自定义指令的代码片段:

   <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 />

我尝试将 ng-click 内部调用的 javascript 方法更改为: ng-click="getProductsForCategory" 也是如此。

这两种结果都会导致在单击链接时不会调用 getProductsForCategory 方法

有人知道我的问题是什么吗?

谢谢,

大卫

编辑信息* 嘿伙计们,感谢您研究这个问题。它仍在进行中,但我为我的自定义指令添加了一个额外的测试到我的 html 片段

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

之前唯一的一行是第一个标签,即 div。 我添加了第 2 行,看看是否可能是 html 直接绑定到指令中的 div 标签,或者其他地方的指令配置有问题。

我添加的第二个标签应该是标准的 ng-click 操作。我的第二个 href 标签 调用函数 getProductsForCategory()。 所以这似乎是由于我将我的 html 字符串绑定到指令的 div 元素。

问题是我正在构建的导航结构可以有无限的嵌套子元素(它基本上是一个吸盘选择框)。

这意味着我将不得不使用递归来映射每个父子导航 结构...在指令中...

【问题讨论】:

  • 您在控制台日志中看到了什么?有什么好用的吗?

标签: javascript angularjs


【解决方案1】:

ng-click 标记中缺少一组大括号

ng-click="getProductsForCategory"

应该是

ng-click="getProductsForCategory()"

【讨论】:

  • 正如@Maxim 指出的那样,需要 $compile .....但是,将 json 解析为 html ala jQuery 样式的概念没有意义。为什么不将数据传递给控制器​​范围并让 Angular 使用 ng-repeat 管理 DOM?控制器不应该用于 DOM 操作
  • 你好 Charlietfl。我不只是将数据传递到控制器范围并让 Angular 使用 ng-repeat 管理 DOM 的原因是数据是一组父子类别链接,其中可以有无限数量的嵌套类别。 ng-repeat 可以在一个列表上重复,但是包含 N 个嵌套层的列表怎么样,并且它们必须采用正确的 html 顺序才能使 Suckerfish Dropbox 工作。在 Angular 之前,我只是在服务器端使用递归 php 并返回一串预先格式化的 html。我不知道如何使用返回的 json 以及指令和 angular
  • 可以测试孩子并在孩子存在时使用递归模板...只是快速搜索,这篇文章看起来很适合解释sporto.github.io/blog/2013/06/24/…
【解决方案2】:

我为我的项目想出了一个解决方案。 这是路由部分

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'
            })
    }]
);

这是视图 (categories.html) 的主控制器,用于展示我们的自定义指令。我创建了一个名为“treeFamily”的测试数据集,我将用它来测试这个控制器中的指令

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: []
              }]
          }]
      }

这是我们将用于递归遍历数据集的指令。

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);
        }
    };
})

这是我发现有人在网上演示的编译服务。 我决定使用它,因为它可以让我们的代码保持整洁。

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;
}]);

这是我们指令的 html 片段。注意我们是如何从指令中调用指令的。

<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>

这是我的 categories.html 页面的一部分,它是我的控制器的主视图。

    <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>

在递归指令正常工作后,我遇到的主要问题是我添加到指令的 html 中的 ng-click 在单击时没有响应。 这是因为指令的作用域是一个孤立作用域。

为了访问主控制器的方法,您必须将指令的方法绑定到控制器的方法。 为了做到这一点,您必须在标签自身中添加要绑定的控制器功能。 即:

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

并且指令的隔离作用域引用了这个 即:

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

指令的html中的a href是这样的:

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

请注意,我们引用了指令的函数“product”,而不是 products,它是我们想要访问的控制器上的方法的名称。

【讨论】:

    【解决方案3】:

    似乎有问题的一件事是您没有在指令中编译 HTML。这是ng-click 不起作用的原因,因为 angular 没有看到这种变化。

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

    当你打电话时:

     var navHTML = createCategoryNavigationBar(data);
    

    试着写这样的东西:

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

    也许会有所帮助,

    【讨论】:

    • 由于我的第二次测试在指令的 html 片段中使用 ng-click 创建了一个 href,我得出的结论是我直接将 html 字符串附加到 html 片段。我仍然对如何使用指令进行递归数据处理一无所知(解决需要递归的问题)。
    猜你喜欢
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多