1

jQuery datepicker not working inside a AngularJS ng-repeat block.

Not sure if anything wrong in code generation inside ng-repeat block. The same logic works outside ng-repeat.

Working code

        <div class="form-group">
            <label class="control-label col-md-4">TEST DATE</label>
            <div class="input-group col-md-2">
                <input type="text" id="testDate" name="testDate" readonly="readonly" class="form-control">
            </div>
        </div>

Not working code

        <div ng-repeat="reportType in reportTypes">

            <div class="form-group">
                <label class="control-label col-md-4">{{reportType.reportTypeLabel}}</label>
                <div class="input-group col-md-2">
                    <input type="text" id="{{reportType.reportTypeCodeId}}Date" readonly="readonly"
                        class="form-control">
                </div>
            </div>
        </div>

Javascript

// Date picker dd/mm/yyyy
$(function() {
    $("input[id*='date']").datepicker({
        dateFormat : "dd/mm/yy"
    });
});
$(function() {
    $("input[id*='Date']").datepicker({
        dateFormat : "dd/mm/yy"
    });
});
2
  • 1
    This is just wrong way to mix angular and jquery. ng-repeat may add or remove elements, when your jquery code runs only once. Wrap all jquery to directives or just do not use it at all - use angular datepicker instead. Commented Oct 28, 2015 at 16:29
  • Create a date-picker directive. Use jQueryLite with datepicker for the element, make sure you cleanup on $scope destroy to avoid memory leaks. Commented Oct 28, 2015 at 16:33

2 Answers 2

2

Use this directive to initialize the datepicker after ng-repeat ends:

angular.module('mymodule').directive('ngOnFinishRender', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit(attr.broadcastEventName ? attr.broadcastEventName : 'ngRepeatFinished');
                });
            }
        }
    };
});

In your controller:

$scope.$on('ngRepeatFinished', function(){        
    $("input[id*='date']").datepicker({
        dateFormat : "dd/mm/yy"
    });        
});

In your view, add the directive ng-on-finish-render to element with ng-repeat:

<div ng-repeat="reportType in reportTypes" ng-on-finish-render>

        <div class="form-group">
            <label class="control-label col-md-4">{{reportType.reportTypeLabel}}</label>
            <div class="input-group col-md-2">
                <input type="text" id="{{reportType.reportTypeCodeId}}Date" readonly="readonly"
                    class="form-control">
            </div>
        </div>
    </div>

You can add broadcast-event-name="myNgRepeatFinished" parameter if you have more than one ng-repeat in your scope and they have different purposes

$scope.$on('myNgRepeatFinished', function(){        
    $("input[id*='date']").datepicker({
        dateFormat : "dd/mm/yy"
    });        
}); 
Sign up to request clarification or add additional context in comments.

Comments

0

You have to create a custom directive for the datepicker.

The View

<div ng-app="myApp" ng-controller="myController">
<div ng-repeat="report in repArray">
    <div class="form-group">
        <label>{{report.values.name}}</label>
        <input type="text" datepicker ng-model="datevalue" />
    </div>
</div>

The Directive

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

myApp.controller('myController', ['$scope', function ($scope) {
    $scope.report = [
        { 'name': 'rep1' },
        { 'name': 'rep2' },
        { 'name': 'rep3' }
    ]

    $scope.repArray = Object.keys($scope.report)
        .map(function (value, index) {
            return { values: $scope.report[value] }
        }
    );
} ]);


myApp.directive("datepicker", function () {

    function link(scope, element, attrs, controller) {
        element.datepicker({
            dateFormat: "dd/mm/yy"
        });
    }

    return {
        require: 'ngModel',
        link: link
    };
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.