Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular-UI multiple datepickers insider form controller

I am creating a form with multiple angular-ui datepickers and some input data. For the datepickers I have created a controller and a parent form controller like the sample given below. The form controller has the model which includes the datepicker dates.

JS:

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

app.controller('dateCntrl', function($scope,$timeout){
    $scope.open = function() {
        $timeout(function() {
            $scope.opened = true;
        });
    };
});

app.controller('formCntrl', function($scope, $http){
    $scope.model = {name:'', startDate:'', endDate:''};
});

HTML:

<form ng-controller="formCntrl">
    <input type="text" id="name" placeholder="Name" ng-model="model.name" />
    <div ng-controller="dateCntrl">
        <input datepicker-popup="dd-MMMM-yyyy"  ng-model="model.startDate" id="startDate" type="text" />
        <button class="btn" ng-click="open()"><i class="icon-calendar"></i></button>
    </div>
    <div ng-controller="dateCntrl">
        <input datepicker-popup="dd-MMMM-yyyy" ng-model="model.endDate" id="endDate" type="text" />
        <button class="btn" ng-click="open()"><i class="icon-calendar"></i></button>
    </div>
</form>
  • Am I going the right way in having a separate controller for the datepicker. This will act as a common controller for all the date inputs
  • If yes, is it possible to have a generic way of binding the data in the datepicker controller back to the model dates(model.startDate,model.endDate in this case) in the parent controller.
  • Is there a alternative way to go about this.

Thanks and regards.

like image 518
guru Avatar asked Dec 07 '22 06:12

guru


2 Answers

Should have read more about the scope inheritance

The parent scope values can be accessed using $parent

<form ng-controller="formCntrl">
    <input type="text" id="name" placeholder="Name" ng-model="model.name" />
    <div ng-controller="dateCntrl">
        <input datepicker-popup="dd-MMMM-yyyy"  ng-model="$parent.model.startDate" id="startDate" type="text" />
        <button class="btn" ng-click="open()"><i class="icon-calendar"></i></button>
    </div>
    <div ng-controller="dateCntrl">
        <input datepicker-popup="dd-MMMM-yyyy" ng-model="$parent.model.endDate" id="endDate" type="text" />
        <button class="btn" ng-click="open()"><i class="icon-calendar"></i></button>
    </div>
</form>
like image 160
guru Avatar answered Dec 23 '22 15:12

guru


I took all the code from the verbose example here: http://angular-ui.github.io/bootstrap/#/datepicker & wrapped it into my own directive. This way I can just drop unlimited datepickers into my page, and specify the model for each one to bind to. I do not have to manage passing repetitive settings, or setting up unique variables for tracking the "open" status anymore, I just put 1 line of code:

<div my-date-picker my-date-picker-model="myDate1"></div>
<div my-date-picker my-date-picker-model="myDate2"></div>
<div my-date-picker my-date-picker-model="myDate3"></div>

The user can then toggle each date picker open/closed, and the values will be updated into myDate1, myDate2, & myDate3 appropriately. The open/closed status is now encapsulated within the directive, and out of mind.

To implement the directive, I copied the 'JS' tab's code into it's controller, and I copied the 'Markup' tab's code into it's template. At the end I added 1 bit of code to update the value to the parent scope:

$scope.$watch('dt', function(newVal, oldVal) {
    $scope.myDatePickerModel = newVal;
});

At the start of the controller, I changed $scope.today to initialize the value from the parent scope, instead of using the system clock:

$scope.init = function() {
    $scope.dt = $scope.hxDatePickerModel;
};
$scope.init();

The directive uses an isolate scope, and 2-way binding on the attribute which defines the parent scope's model:

scope: {
    myDatePickerModel: '='
}

Here's the full code of the directive:

app.directive('myDatePicker', function() {

    function link(scope, element, attrs) {
    }

    function controller($scope) {
       $scope.init = function() {
        $scope.dt = $scope.myDatePickerModel;
    };
    $scope.init();

        $scope.clear = function () {
            $scope.dt = null;
        };

        // Disable weekend selection
        $scope.disabled = function(date, mode) {
            return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
        };

        $scope.toggleMin = function() {
            $scope.minDate = $scope.minDate ? null : new Date();
        };
        $scope.toggleMin();

        $scope.open = function($event) {
            $event.preventDefault();
            $event.stopPropagation();

            $scope.opened = true;
        };

        $scope.dateOptions = {
            formatYear: 'yy',
            startingDay: 1
        };

        $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
        $scope.format = $scope.formats[0];

    $scope.$watch('dt', function(newVal, oldVal) {
        $scope.myDatePickerModel = newVal;
    });

    }

    return {
        restrict: 'A',
        templateUrl: 'datepicker.html',
        link: link,
        controller: controller,
        scope: {
            myDatePickerModel: '='
        }
    }
});

And here is the full code of datepicker.html, the template for this directive:

<p class="input-group">
    <input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
      <span class="input-group-btn">
        <button type="button" class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
      </span>
</p>
like image 43
Josh Ribakoff Avatar answered Dec 23 '22 14:12

Josh Ribakoff