1

I created one directive in Angularjs now binding model data into directive , problem is that I have I am using JqGrid and I want call one function when JqGrid's gridcomplete event will call.

Everything working fine when we direct use function code into directive, But when trying to call it from model then its not able to call.

Pasting code and highlighting problem into snap also.


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

Bhuvnesh
  • 71
  • 2
  • 7
  • After many search finally findout problem with the help of https://docs.angularjs.org/api/ng/directive/ngModel – Bhuvnesh Jan 03 '15 at 09:54

4 Answers4

1

Here is a working example that should give you what you need:

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

You can bind functions the same way you bind data from outer -> inner scopes. Here, gridComplete is bound from the outer scope (controller scope) into the inner scope using a two-way binding. It gets called in the link function, immediately after compiling, but it could be called any time.

// 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();
      }
    }
  })
Peter Ashwell
  • 4,292
  • 2
  • 18
  • 22
1

I guess, in your directive code you are executing the function directly at time of linking and due to that it is not able to execute on gridComplete event.

Try to change gridComplete: scope.gridData.gridComplete() in your directive code with gridComplete: scope.gridData.gridComplete.

So it can execute on gridComplete event.

Shripal Soni
  • 2,448
  • 17
  • 15
  • As explained by [user860478](http://stackoverflow.com/a/27752773/3292746), you should not do any DOM manipulation into the controller and you can pass the button template as an attribute to your directive. And set that template into gridComplete handler. But if you want to do it in controller, it will be helpful if you can put sample code in plunker or any other code collaboration site. – Shripal Soni Jan 03 '15 at 10:02
  • Because we just passing function from model to directive , because our directive have component and we are re-using this component many times. And not manipulating DOM into model , its just pass one function into directive as a parameter. And DOM finally manipulating inside directive. I think it make scene ? – Bhuvnesh Jan 03 '15 at 10:05
1

After explore many angularjs official findout the solution


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

Now my code looks like added "event_gridComplete" function inside block and then called from directive.

Working !

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

    };

});
Bhuvnesh
  • 71
  • 2
  • 7
0

You shouldn't do any DOM manipulations inside of your controller to begin with. These lines:

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

can be executed inside of a directive (your current one or a different one for this specific use case) by using element parameter. Another way to put it inside of your directive is to make it an optional attribute, i.e.:

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


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

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

        ...
    }

The edit buttons shouldn't be done inside of a controller as well. You should move them inside of a template or add them in a link function.

Using jqGrid with Angular is a bad idea overall. There are some Angular based grids that can be mapped with your application in a much cleaner way, for example: http://ui-grid.info/

If you decide to keep all this presentation logic inside of your controller, then you should fix this line:

gridComplete: scope.gridData.gridComplete(),

You are calling the function during the assignment and therefore assigning the function's RESULT, not the function itself. It should be:

gridComplete: scope.gridData.gridComplete,
Victor Marchuk
  • 13,045
  • 12
  • 43
  • 67