Передать функцию из модели в директиву в 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
>                 });
>             }
>         },
> 
>     };
> 
> });


person Bhuvnesh    schedule 03.01.2015    source источник
comment
После многих поисков, наконец, обнаружил проблему с помощью docs.angularjs.org/api/ng/ директива/ngModel   -  person Bhuvnesh    schedule 03.01.2015


Ответы (4)


Я предполагаю, что в вашем коде директивы вы выполняете функцию непосредственно во время связывания, и из-за этого она не может выполняться в событии gridComplete.

Попробуйте изменить gridComplete: scope.gridData.gridComplete() в коде директивы на gridComplete: scope.gridData.gridComplete.

Таким образом, он может выполняться в событии gridComplete.

person Shripal Soni    schedule 03.01.2015
comment
Как объяснил user860478, вы не должны выполнять какие-либо манипуляции с DOM в контроллере, и вы можете передать шаблон кнопки в качестве атрибута для ваша директива. И установите этот шаблон в обработчик gridComplete. Но если вы хотите сделать это в контроллере, будет полезно, если вы сможете поместить пример кода в plunker или любой другой сайт для совместной работы над кодом. - person Shripal Soni; 03.01.2015
comment
Потому что мы просто передаем функцию из модели в директиву, потому что наша директива имеет компонент, и мы повторно используем этот компонент много раз. И не манипулируя DOM в модели, просто передайте одну функцию в директиву в качестве параметра. И, наконец, DOM манипулирует внутренней директивой. Я думаю, это делает сцену? - person Bhuvnesh; 03.01.2015

Вот рабочий пример, который должен дать вам то, что вам нужно:

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

Вы можете привязывать функции так же, как привязываете данные из внешних -> внутренних областей. Здесь gridComplete связывается из внешней области (области действия контроллера) во внутреннюю область с использованием двусторонней привязки. Он вызывается в функции ссылки сразу после компиляции, но может быть вызван в любое время.

// 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();
      }
    }
  })
person Peter Ashwell    schedule 03.01.2015

После изучения многих официальных источников 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
                });
            }
        } },

    };

});
person Bhuvnesh    schedule 03.01.2015

Вы не должны выполнять какие-либо манипуляции с 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');

        ...
    }

Кнопки редактирования также не должны размещаться внутри контроллера. Вы должны переместить их внутрь шаблона или добавить в функцию ссылки.

В целом использование jqGrid с Angular — плохая идея. Есть несколько сеток на основе Angular, которые можно сопоставить с вашим приложением гораздо чище, например: http://ui-grid.info/

Если вы решили оставить всю эту логику представления внутри вашего контроллера, то вам следует исправить эту строку:

gridComplete: scope.gridData.gridComplete(),

Вы вызываете функцию во время назначения и, следовательно, назначаете РЕЗУЛЬТАТ функции, а не саму функцию. Так должно быть:

gridComplete: scope.gridData.gridComplete,
person Victor Marchuk    schedule 03.01.2015