Yokesh T
Yokesh T

Reputation: 121

ui-grid Edit Feature not working properly

I am using ui-grid. I enabled edit feature using ui-grid-edit. The problem is datepicker. I want the datepicker to work in all browsers but it is not possible by enabling the type : "date" because it will give the same datepicker supported by HTML5. So i thought of enabling bootstrap datepicker for angular using custom template by adding editableCellTemplate

columnDefs : {
    field:'accbirthdate',displayName :"Birth Date",enableCellEditOnFocus:true,editableCellTemplate: '<input type="text" ng-input="COL_FIELD" ng-model="COL_FIELD" datepicker-popup="dd-MM-yyyy" datepicker-append-to-body="true"/>'}
}

but it is not working at all. I found that even ng-click in the input text also is not working.So anyone please help on how to enable bootstarp date-picker in angular ui-grid

Upvotes: 0

Views: 3787

Answers (3)

pto3
pto3

Reputation: 521

I also got this problem with datepicker and decidet to add a default jquery-ui one. Actually, you can add anyone.

The code below requires some explanation.

First, you template should looks like that:

editableCellTemplate: '<input datepicker ng-model="MODEL_COL_FIELD" readonly>'

It must contain a ng-model attribute with a value MODEL_COL_FIELD. This value means that your input will be bind with a cell's model. I.e. the cell after stopping an edit mode the cell (it's usually a <div> element) will get the value from our input. The MODEL_COL_FIELD value is replaced by ui-grid engine with real name of model. In our case this is row.entity['startDate']. You can see this when you read a property $attrs.ngModel. The

eval('$scope.' + $attrs.ngModel + ' = "' + value + '";');

line appears like that because we can't know a name of model. This name is designated with ui-grid engine automatically. Instead of eval you can create a function allowing to access a value of $scope parsing $attrs.ngModel value.

Second, when you create some directive, all DOM modifications should be replaced in the compile section.

Third, if you create your own directive for edit-mode in ui-grid, you must fire BEGIN_CELL_EDIT, CANCEL_CELL_EDIT and END_CELL_EDIT events manually (see http://ui-grid.info/docs/#/tutorial/201_editable). In our code we do this in onClose property of datepicker. We don't use onSelect because we can loose a focus on our input and the datepicker will be closed, but the input will be still opened. To stop an edit mode we must fire the END_CELL_EDIT event:

$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);

The JS code:

var app = angular.module('app', ['ui.grid', 'ui.grid.edit']);

app.controller('MainController', function($scope) {
    $scope.gridOptions = {
        columnDefs: [{
            name: 'startDate',
            editableCellTemplate: '<input datepicker ng-model="MODEL_COL_FIELD" readonly>',
            enableCellEdit: true,
            width: 150
        }],
        data: [{
            startDate: ''
        }]
    };
});

app.directive('datepicker', ['uiGridEditConstants', function(uiGridEditConstants) {
    return {
        restrict: 'A',
        require: 'ngModel',
        compile: function() {
            return {
                pre: function($scope, $elm, $attrs) {},
                post: function($scope, $elm, $attrs) {
                    function setValueToScope(value) {
                        eval('$scope.' + $attrs.ngModel + ' = "' + value + '";');
                        $scope.$apply();
                    }
                    $elm = $($elm);
                    $elm.datepicker({
                        dateFormat: 'mm/dd/yy',
                        onSelect: function(date) {
                            setValueToScope(date);
                        },
                        onClose: function() {
                            $scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
                        }
                    });
                    $elm[0].focus();
                }
            };
        }
    };
}]);

The full code and how it is work you can see here: http://plnkr.co/edit/NfMuGpNDqIjvoAGJ2R1B

Upvotes: 0

Yokesh T
Yokesh T

Reputation: 121

Yes as i think it is because the HTML code is not compiled when we are using it directly on editableCellTemplate. For more info on how Angular Template Compiling Works refer here Angular Template Compiling

Here's what i do to resolve this issue. I replaced my column defs editableCellTemplate to the following

columnDefs : {
    field:'accbirthdate',displayName :"Birth Date",enableCellEditOnFocus: true,editableCellTemplate: '<input type="text" class="form-control" datepicker-popup="dd/MM/yyyy" ng-class="\'colt\' + col.index" ng-model="row.entity[col.field]" datepicker-append-to-body="true" is-open="istableDate" close-text="Close" table-date/>'}
}

as like gridEditor i created my own directive in my directive.js i have created the directive

app.directive('tableDate',function($filter){
   function parseDateString(dateString) {
      if (typeof(dateString) === 'undefined' || dateString === '') {
        return null;
      }
      var parts = dateString.split('/');
      if (parts.length !== 3) {
        return null;
      }
      var year = parseInt(parts[2], 10);
      var month = parseInt(parts[1], 10);
      var day = parseInt(parts[0], 10);

      if (month < 1 || year < 1 || day < 1) {
        return null;
      }
      return new Date(year, (month - 1), day);
    }
    function pad(s) { return (s < 10) ? '0' + s : s; }
    return {
        priority: -100, // run after default uiGridEditor directive
        require: '?ngModel',
        link: function (scope, element, attrs, ngModel) {
          scope.istableDate = false;

          scope.$on( 'uiGridEventBeginCellEdit', function () { 
            scope.istableDate = true;
          });

          element.on("click",function(){
            scope.istableDate = true;
          });

          element.bind( 'blur', function () { 
            if(!scope.istableDate){
              scope.$emit( 'uiGridEventEndCellEdit' ); 
            }else{
              scope.istableDate =  false;
            }
          }); //when leaving the input element, emit the 'end cell edit' event

          if (ngModel) {
            ngModel.$formatters.push(function (modelValue) {
              var modelValue= new Date(modelValue);
              ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
              return $filter('date')(modelValue, 'dd/MM/yyyy');
            });

            ngModel.$parsers.push(function (viewValue) {
              if (viewValue ) {
                var dateString =  [pad(viewValue.getDate()), pad(viewValue.getMonth()+1), viewValue.getFullYear()].join('/')
                var dateValue = parseDateString(dateString);
                ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
                return dateValue;
              }
              else {
                ngModel.$setValidity(null, true);
                return null;
              }
            });
          }
        }
      };
});

My Date format is dd/MM/yyyy, choose yours once we emit the event it will mentioned as changed. Now i have my bootstrap date-picker working for my ui-grid on all browsers.

If you have any doubt on this feel free to ask me. i Spend One day on this and I would like to share my experience to others.

Oops not in IE6 :)

Upvotes: 1

Ramesh Rajendran
Ramesh Rajendran

Reputation: 38703

I got this same issue before one moth ago. but i can't find out the solution. So i change my mind to custom grid.

I have using table, tr,td tags

see this is my html code

 <table ng-show="TimeSheetList.length!==0" class="table">
            <tr>
                <th style="background-color: #BBE1EF">Start Date</th>
                <th style="background-color: #BBE1EF">Start Time</th>
                <th style="background-color: #BBE1EF">End Time</th>
                <th style="background-color: #BBE1EF">Total Hours</th>
                <th style="background-color: #BBE1EF">Description</th>
                <th style="background-color: #BBE1EF">Remarks</th>
            </tr>
            <tr ng-repeat="timesheetlist in TimeSheetList">
                <td ng-dblclick="ChangeVal(this,'StartDate')"><span ng-hide="timesheetlist.IsEditStartDate">{{timesheetlist.StartDate}}</span>
                    <input style="width: 150px" type="text" class="form-control" date-time required="true" view="hours" partial="true" ng-blur="UpdateTimeSheet(this.timesheetlist)" id="StartDate{{$index}}" ng-show="timesheetlist.IsEditStartDate" ng-model="timesheetlist.StartDate" />
                </td>
                <td><span ng-dblclick="ChangeVal(this,'StartTime')" ng-hide="timesheetlist.IsEditStartTime">{{timesheetlist.StartTime}}</span>
                    <timepicker hour-step="1" minute-step="1" show-meridian="true" ng-change="UpdateTimeSheet(this.timesheetlist)" ng-blur="UpdateTimeSheet(this.timesheetlist)" id="StartTime{{$index}}" ng-show="timesheetlist.IsEditStartTime" ng-model="timesheetlist.StartTime"></timepicker>

                </td>
                <td><span ng-dblclick="ChangeVal(this,'EndTime')" ng-hide="timesheetlist.IsEditEndTime">{{timesheetlist.EndTime}}</span>
                    <timepicker hour-step="1" minute-step="1" show-meridian="true" ng-change="UpdateTimeSheet(this.timesheetlist)" ng-blur="UpdateTimeSheet(this.timesheetlist)" id="EndTime{{$index}}" ng-show="timesheetlist.IsEditEndTime" ng-model="timesheetlist.EndTime"></timepicker>
                </td>
                <td>
                    <input type="text" readonly="true" class="form-control" ng-model="timesheetlist.TotalHours" style="width: 200px" autofocus="">
                </td>
                <td><span ng-dblclick="ChangeVal(this,'Description')" ng-hide="timesheetlist.IsEditDescription">{{timesheetlist.Description}}</span>
                    <input style="width: 200px" type="text" class="form-control" ng-blur="UpdateTimeSheet(this.timesheetlist)" ng-show="timesheetlist.IsEditDescription" ng-model="timesheetlist.Description" /></td>
                <td><span ng-dblclick="ChangeVal(this,'Remarks')" ng-hide="timesheetlist.IsEditRemarks">{{timesheetlist.Remarks}}</span>
                    <input style="width: 200px" type="text" class="form-control" ng-blur="UpdateTimeSheet(this.timesheetlist)" ng-show="timesheetlist.IsEditRemarks" ng-model="timesheetlist.Remarks" /></td>
            </tr>
        </table>

this is my controller code

 function loadTimeSheets(date) {
            $http({
                method: 'GET',
                url: rootUrl + '/api/TimeSheet/LoadTimeSheet?date=' + date,
                headers: {
                    'Content-Type': "application/json; charset=utf-8"
                }
            }).success(function (response) {
                $scope.TimeSheetList = response;
                if ($scope.TimeSheetList.length == 0) {
                    alert('You did not add your works in this date');
                }
            }).error(function (response, errorCode) {
                if (errorCode == 444) {
                    //toastr.error('Your email address is does not verrified ', 'Error');
                }
            })
        }

I hope you can customize my grid with what you want.

If you don't like that, then you can go to with ng-Grid

Upvotes: 0

Related Questions