将函数从模型传递到 AngularJs 中的指令

Pass function from model into directive in AngularJs

我在 Angularjs 中创建了一个指令,现在将模型数据绑定到指令中,问题是我正在使用 JqGrid,我想在调用 JqGrid 的 gridcomplete 事件时调用一个函数。

当我们直接使用函数代码到指令中时一切正常,但是当试图从中调用它时 模型然后它无法调用。

也将代码和突出显示问题粘贴到 snap 中。


> var app = angular.module('BOneApp', []);
> 
> app.directive('jqGrid', function ($compile) {
> 
>     var jqGridCounter = 0;
> 
>     return {
>         replace: true,
>         restrict: 'E',
>         scope: {
>             gridData: '='
>         },
>         template: '<div>' +
>             '<table></table>' +
>             '<div class="jqgrid-pagination"></div>' +
>             '</div>',
>         controller: function ($scope, $element) {
>             $scope.editRow = function (row) {
>                $element.find('table').editRow(row);
>             };
>             $scope.saveRow = function (row) {
>                 $element.find('table').saveRow(row);
>             };
>             $scope.restoreRow = function (row) {
>                 $element.find('table').restoreRow(row);
>             };
>         },
>         link: function (scope, element) {
>             var gridNumber = jqGridCounter++;
>             var wrapperId = 'jqgrid-' + gridNumber;
>             element.attr('id', wrapperId);
> 
>             var tableId = 'jqgrid-table-' + gridNumber;
>             var table = element.find('table');
>             table.attr('id', tableId);
> 
>             var pagerId = 'jqgrid-pager-' + gridNumber;
>             element.find('.jqgrid-pagination').attr('id', pagerId);
> 
>             table.jqGrid({
>                 id:scope.gridData.id,
>                 url: scope.gridData.url,
>                 datatype: "json",
>                 height: 'auto',
>                 colNames: scope.gridData.colNames || [],
>                 colModel: scope.gridData.colModel || [],
>                 rowNum: 10,
>                 rowList: [10, 20, 30],
>                 pager: '#' + pagerId,
>                 sortname: 'id',
>                 toolbarfilter: true,
>                 viewrecords: true,
>                 sortorder: "asc",
>                  
>                 gridComplete: scope.gridData.gridComplete(),
>                 //editurl: scope.gridData.editurl,
>                 caption: scope.gridData.caption,
>                 multiselect: scope.gridData.multiselect,
>                 autowidth: true
> 
>             });
>             table.jqGrid('navGrid', '#' + pagerId, {
>                 edit: true,
>                 add: true,
>                 del: true
>             });
>             table.jqGrid('inlineNav', '#' + pagerId);
> 
> 
>             element.find(".ui-jqgrid").removeClass("ui-widget ui-widget-content");
>             element.find(".ui-jqgrid-view").children().removeClass("ui-widget-header
> ui-state-default");
>             element.find(".ui-jqgrid-labels, .ui-search-toolbar").children().removeClass("ui-state-default
> ui-th-column ui-th-ltr");
>             element.find(".ui-jqgrid-pager").removeClass("ui-state-default");
>             element.find(".ui-jqgrid").removeClass("ui-widget-content");
> 
>             // add classes
>             element.find(".ui-jqgrid-htable").addClass("table table-bordered table-hover");
>             element.find(".ui-jqgrid-btable").addClass("table table-bordered table-striped");
> 
>             element.find(".ui-pg-div").removeClass().addClass("btn btn-sm btn-primary");
>             element.find(".ui-icon.ui-icon-plus").removeClass().addClass("fa
> fa-plus");
>             element.find(".ui-icon.ui-icon-pencil").removeClass().addClass("fa
> fa-pencil");
>             element.find(".ui-icon.ui-icon-trash").removeClass().addClass("fa
> fa-trash-o");
>             element.find(".ui-icon.ui-icon-search").removeClass().addClass("fa
> fa-search");
>             element.find(".ui-icon.ui-icon-refresh").removeClass().addClass("fa
> fa-refresh");
>             element.find(".ui-icon.ui-icon-disk").removeClass().addClass("fa
> fa-save").parent(".btn-primary").removeClass("btn-primary").addClass("btn-success");
>             element.find(".ui-icon.ui-icon-cancel").removeClass().addClass("fa
> fa-times").parent(".btn-primary").removeClass("btn-primary").addClass("btn-danger");
> 
>             element.find(".ui-icon.ui-icon-seek-prev").wrap("<div class='btn btn-sm btn-default'></div>");
>             element.find(".ui-icon.ui-icon-seek-prev").removeClass().addClass("fa
> fa-backward");
> 
>             element.find(".ui-icon.ui-icon-seek-first").wrap("<div class='btn btn-sm btn-default'></div>");
>             element.find(".ui-icon.ui-icon-seek-first").removeClass().addClass("fa
> fa-fast-backward");
> 
>             element.find(".ui-icon.ui-icon-seek-next").wrap("<div class='btn btn-sm btn-default'></div>");
>             element.find(".ui-icon.ui-icon-seek-next").removeClass().addClass("fa
> fa-forward");
> 
>             element.find(".ui-icon.ui-icon-seek-end").wrap("<div class='btn btn-sm btn-default'></div>");
>             element.find(".ui-icon.ui-icon-seek-end").removeClass().addClass("fa
> fa-fast-forward");
> 
>             $(window).on('resize.jqGrid', function () {
>                 table.jqGrid('setGridWidth', $("#content").width());
>             });
> 
>             $compile(element.contents())(scope);
>         }
>     } });
> 
> 
> app.controller('CostCenter', function ($scope) {
> 
>     $scope.gridData = {
>         url: baseURL + "/CompanyAdmin/GetCostCenterForCompanyAdmin",
>         //editurl: "/Tables/Edit",
>         caption: "Cost Centers",
>         colNames: ['Actions', 'ID', 'Parent Code', 'Parent Name', 'Code', 'Name', 'Address', 'Contact Number', 'Website'],
>         colModel: [
>             { name: 'act', index: 'act', sortable: false },
>             { name: 'ID', index: 'ID', key: true, hidden: true },
>             { name: 'ParentCode', index: 'ParentCode', editable: true },
>             { name: 'ParentName', index: 'ParentName', editable: true },
>             { name: 'Code', index: 'Code', editable: true },
>             { name: 'Name', index: 'Name', editable: true },
>             { name: 'Address', index: 'Address', editable: true/*, searchoptions: { sopt: ['eq', 'ne', 'cn'] }*/ },
>             { name: 'ContactNumber', index: 'ContactNumber', editable: true },
>             { name: 'Website', index: 'Website', editable: true/*, edittype: 'select', editoptions: { value:
> sa_EditOpt(arr_AccountNumbers, 'Id', 'ACNumber') } */ }
>         ],
>         multiselect: false,
>         gridComplete: function () { **/* Need to call this function into run time in directive */**
> 
>             var gridid = $("#jqgrid-table-0");
>             var ids = gridid.jqGrid('getDataIDs');
>             for (var i = 0; i < ids.length; i++) {
>                 var cl = ids[i];
>                 be = "<a class='btn btn-xs btn-default' data-original-title='Edit Row'
> href=\"/CompanyAdmin/UpdateBusinessEntity/" + cl + "\"><i class='fa
> fa-pencil'></i></a>";
>                 ac = "<a class='btn btn-xs btn-default' data-original-title='Edit Row' href=\"/CompanyAdmin/Create?ParentID="
> + cl + "\"><i class='fa fa-sitemap'></i></a>";
>                 jQuery(gridid).jqGrid('setRowData', ids[i], {
>                     act: be + ac
>                 });
>             }
>         },
> 
>     };
> 
> });

这是一个可以满足您需要的工作示例:

http://plnkr.co/edit/bN5KOtehElJqNP3C7CkD?p=preview

您可以像从外部 -> 内部范围绑定数据一样绑定函数。在这里,gridComplete 使用双向绑定从外部范围(控制器范围)绑定到内部范围。它在编译后立即在 link 函数中调用,但它可以随时调用。

// Code goes here
angular.module('MyApp', [])
  .controller('MainCtrl', ['$scope',
    function($scope) {
      $scope.gridData = {
        gridComplete: function() {
          console.log("someFn was executed!")
        }
      }
    }
  ])
  .directive('directiveWithFn', function() {
    return {
      restrict: 'A',
      $scope: {
        'gridData': '='
      },
      link: function(scope, elem) {
        // Call the function after compile
        scope.gridData.gridComplete();
      }
    }
  })

我想,在您的指令代码中,您在链接时直接执行函数,因此它无法在 gridComplete 事件上执行。

努力改变 gridComplete: scope.gridData.gridComplete() 在你的指令代码中 gridComplete: scope.gridData.gridComplete

因此它可以在 gridComplete 事件上执行。

一开始您不应该在控制器内部进行任何 DOM 操作。这些行:

    var gridid = $("#jqgrid-table-0");
    var ids = gridid.jqGrid('getDataIDs');

可以通过使用 element 参数在指令(您当前的指令或针对此特定用例的不同指令)内部执行。将它放在指令中的另一种方法是使其成为可选属性,即:

    scope: {
       gridData: '=',
       editButtons: '@'
    },


    link: function (scope, element) {
        ...

        if(scope.editButtons){
            var ids = element.jqGrid('getDataIDs');

        ...
    }

编辑按钮也不应在控制器内部完成。您应该将它们移动到模板中或将它们添加到 link 函数中。

将 jqGrid 与 Angular 一起使用总体上是个坏主意。有一些基于 Angular 的网格可以以更清晰的方式映射到您的应用程序,例如:http://ui-grid.info/

如果您决定将所有这些表示逻辑保留在您的控制器中,那么您应该修正这一行:

gridComplete: scope.gridData.gridComplete(),

您在赋值期间调用函数,因此赋值函数的结果,而不是函数本身。应该是:

gridComplete: scope.gridData.gridComplete,

经过多次探索angularjs官方找到解决方案


angular.module('getterSetterExample', [])
.controller('ExampleController', ['$scope', function($scope) {
  var _name = 'Brian';
  $scope.user = {
    name: function(newName) {
      if (angular.isDefined(newName)) {
        _name = newName;
      }
      return _name;
    }
  };
}]);

现在我的代码看起来像是在块中添加了 "event_gridComplete" 函数,然后从指令中调用。

正在工作!

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

app.directive('jqGrid', function ($compile) {

    var jqGridCounter = 0;
    return {
        replace: true,
        restrict: 'E',
        scope: {
            gridData: '='
        },
        template: '<div>' +
            '<table></table>' +
            '<div class="jqgrid-pagination"></div>' +
            '</div>',
        controller: function ($scope, $element) {
            $scope.editRow = function (row) {
               $element.find('table').editRow(row);
            };
            $scope.saveRow = function (row) {
                $element.find('table').saveRow(row);
            };
            $scope.restoreRow = function (row) {
                $element.find('table').restoreRow(row);
            };
        },
        link: function (scope, element) {
            var gridNumber = jqGridCounter++;
            var wrapperId = 'jqgrid-' + gridNumber;
            element.attr('id', wrapperId);

            var tableId = 'jqgrid-table-' + gridNumber;
            var table = element.find('table');
            table.attr('id', tableId);

            var pagerId = 'jqgrid-pager-' + gridNumber;
            element.find('.jqgrid-pagination').attr('id', pagerId);

            table.jqGrid({
                id:scope.gridData.id,
                url: scope.gridData.url,
                datatype: "json",
                height: 'auto',
                colNames: scope.gridData.colNames || [],
                colModel: scope.gridData.colModel || [],
                rowNum: 10,
                rowList: [10, 20, 30],
                pager: '#' + pagerId,
                sortname: 'id',
                toolbarfilter: true,
                viewrecords: true,
                sortorder: "asc",

                gridComplete: scope.gridData.gridComplete.event_gridComplete,
                //editurl: scope.gridData.editurl,
                caption: scope.gridData.caption,
                multiselect: scope.gridData.multiselect,
                autowidth: true

            });
            table.jqGrid('navGrid', '#' + pagerId, {
                edit: true,
                add: true,
                del: true
            });
            table.jqGrid('inlineNav', '#' + pagerId);


            element.find(".ui-jqgrid").removeClass("ui-widget ui-widget-content");
            element.find(".ui-jqgrid-view").children().removeClass("ui-widget-header ui-state-default");
            element.find(".ui-jqgrid-labels, .ui-search-toolbar").children().removeClass("ui-state-default ui-th-column ui-th-ltr");
            element.find(".ui-jqgrid-pager").removeClass("ui-state-default");
            element.find(".ui-jqgrid").removeClass("ui-widget-content");

            // add classes
            element.find(".ui-jqgrid-htable").addClass("table table-bordered table-hover");
            element.find(".ui-jqgrid-btable").addClass("table table-bordered table-striped");

            element.find(".ui-pg-div").removeClass().addClass("btn btn-sm btn-primary");
            element.find(".ui-icon.ui-icon-plus").removeClass().addClass("fa fa-plus");
            element.find(".ui-icon.ui-icon-pencil").removeClass().addClass("fa fa-pencil");
            element.find(".ui-icon.ui-icon-trash").removeClass().addClass("fa fa-trash-o");
            element.find(".ui-icon.ui-icon-search").removeClass().addClass("fa fa-search");
            element.find(".ui-icon.ui-icon-refresh").removeClass().addClass("fa fa-refresh");
            element.find(".ui-icon.ui-icon-disk").removeClass().addClass("fa fa-save").parent(".btn-primary").removeClass("btn-primary").addClass("btn-success");
            element.find(".ui-icon.ui-icon-cancel").removeClass().addClass("fa fa-times").parent(".btn-primary").removeClass("btn-primary").addClass("btn-danger");

            element.find(".ui-icon.ui-icon-seek-prev").wrap("<div class='btn btn-sm btn-default'></div>");
            element.find(".ui-icon.ui-icon-seek-prev").removeClass().addClass("fa fa-backward");

            element.find(".ui-icon.ui-icon-seek-first").wrap("<div class='btn btn-sm btn-default'></div>");
            element.find(".ui-icon.ui-icon-seek-first").removeClass().addClass("fa fa-fast-backward");

            element.find(".ui-icon.ui-icon-seek-next").wrap("<div class='btn btn-sm btn-default'></div>");
            element.find(".ui-icon.ui-icon-seek-next").removeClass().addClass("fa fa-forward");

            element.find(".ui-icon.ui-icon-seek-end").wrap("<div class='btn btn-sm btn-default'></div>");
            element.find(".ui-icon.ui-icon-seek-end").removeClass().addClass("fa fa-fast-forward");

            $(window).on('resize.jqGrid', function () {
                table.jqGrid('setGridWidth', $("#content").width());
            });

            $compile(element.contents())(scope);
        }
    }
});


app.controller('CostCenter', function ($scope) {


    $scope.gridData = {
        url: baseURL + "/CompanyAdmin/GetCostCenterForCompanyAdmin",
        //editurl: "/Tables/Edit",
        caption: "Cost Centers",
        colNames: ['Actions', 'ID', 'Parent Code', 'Parent Name', 'Code', 'Name', 'Address', 'Contact Number', 'Website'],
        colModel: [
            { name: 'act', index: 'act', sortable: false },
            { name: 'ID', index: 'ID', key: true, hidden: true },
            { name: 'ParentCode', index: 'ParentCode', editable: true },
            { name: 'ParentName', index: 'ParentName', editable: true },
            { name: 'Code', index: 'Code', editable: true },
            { name: 'Name', index: 'Name', editable: true },
            { name: 'Address', index: 'Address', editable: true/*, searchoptions: { sopt: ['eq', 'ne', 'cn'] }*/ },
            { name: 'ContactNumber', index: 'ContactNumber', editable: true },
            { name: 'Website', index: 'Website', editable: true/*, edittype: 'select', editoptions: { value: sa_EditOpt(arr_AccountNumbers, 'Id', 'ACNumber') } */ }
        ],
        multiselect: false,
        gridComplete: {
            event_gridComplete: function () {

                var gridid = $("#jqgrid-table-0");

                var ids = gridid.jqGrid('getDataIDs');

            for (var i = 0; i < ids.length; i++) {
                var cl = ids[i];
                be = "<a class='btn btn-xs btn-default' data-original-title='Edit Row' href=\"/CompanyAdmin/UpdateBusinessEntity/" + cl + "\"><i class='fa fa-pencil'></i></a>";
                ac = "<a class='btn btn-xs btn-default' data-original-title='Edit Row' href=\"/CompanyAdmin/Create?ParentID=" + cl + "\"><i class='fa fa-sitemap'></i></a>";
                jQuery(gridid).jqGrid('setRowData', ids[i], {
                    act: be + ac
                });
            }
        } },

    };

});