Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngModel used in isolate directive definition

My Directive with name of datePicker Is On the Input Element, that gets gregorian date from model And converts it to persian date for the end user. with changing date from datePicker(here it is jalali(persian date picker)),it is nessaccery to be converted to gregorian and updates the model.

  1. I am not sure from binding type that i used.
  2. $watch function dont work for me ,it works when page loaded first time.
  3. what is happening for ngModel and dateDirVal attributes in isolated scope?
  4. the value of ngModelCtrl.$viewValue in gregorianToJalali function equals to NaN. Why?

my HTML :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="css/jalali/theme.css" rel="stylesheet" />
    <script src="Scripts/jalali/jalali.js"></script>
    <script src="Scripts/jalali/calendar.js"></script>
    <script src="Scripts/jalali/calendar-setup.js"></script>
    <script src="Scripts/jalali/calendar-fa.js"></script>

    <script src="Scripts/jquery-1.7.1.min.js"></script>
    <script src="Scripts/angular.min.js"></script>
    <script src="Scripts/directive.js"></script>

</head>
<body ng-app="myApp">
    <div ng-controller="myController">
        <input ng-model="dateValue1" date id="id1" />
    </div>
</body>
</html>

and My Directive :

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

app.controller('myController', function ($scope) {
    var date = new Date('2014', '06', '03');
    var newdate = new Date(date);

    newdate.setDate(newdate.getDate() + 1);
    $scope.dateValue1 = new Date(newdate);
})
.directive('date', function ($compile) {
    return {
        restrict: 'A',
        require: ['date', '^ngModel'],
        scope: {
            dateDirVal: "=ngModel"
        },
        controller: function ($scope) {

        },
        compile: function (element, attr, linker) {
            return {

                post: function postLink($scope, element, attrs, ctrls) {
                    var myCtrl = ctrls[0], ngModelCtrl = ctrls[1];

                    var inputId = element.attr('id').toString();
                    gregorianToJalali();
                    function gregorianToJalali() {
                        var val = ngModelCtrl.$viewValue;
                        if ($scope.dateDirVal) {
                            var inputValue = $scope.dateDirVal;
                            var gDate = new Date(inputValue);
                            var gY = gDate.getFullYear();
                            var gM = gDate.getMonth();
                            var gD = gDate.getDate();
                            var value = JalaliDate.gregorianToJalali(gY, gM, gD);
                            var jalali = value[0].toString() + "/" + value[1].toString() + "/" + value[2].toString();
                            $scope.dateDirVal = jalali;
                        }
                    }

                    Calendar.setup({
                        inputField: inputId,
                        ifFormat: '%Y/%m/%d',
                        dateType: 'jalali'
                    });

                    element.bind("blur", function (e) {
                        var jDate = element.val().split('/');
                        var value = JalaliDate.jalaliToGregorian(jDate[0], jDate[1], jDate[2]);
                        var gDate = new Date(value[0], value[1], value[2]);
                        ngModelCtrl.$setViewValue(gDate);
                        $scope.dateDirVal = value;
                    });

                    $scope.$watch("dateDirVal", function (newValue, OldValue, scope) {
                        if (newValue) {
                            alert(JSON.stringify(newValue));
                        }
                        //ngModelCtrl.$setViewValue(gDate);
                        //$scope.dateDirVal = value;
                    });

                }
            }
        }
    };
});
like image 849
Fatemeh Gheisari Avatar asked Nov 10 '22 07:11

Fatemeh Gheisari


1 Answers

You could use $parsers and $formatters functions pipelines to do that.

Functions on $parsers react with DOM changes and its return changes the model. So, you could use a toGregorianDate function to convert persian date and persist the gregorian.

Functions on $formatters react with model changes, so, whenever the model changes (including rendering the first time) it will be triggered and its returns are rendered into the DOM. So you could use it to call a toPersianDate function and convert the gregorian into persian date to be rendered to your user.

These functions are listeners, and there are a big caution on compile functions documented on ngModelController DOCs alerting that listenners are supposed to be used on link functions

So I recomend you change a bit your code to look more like that

.directive('date', function ($compile) {
    return {
        restrict: 'A',
        require: ['date', '^ngModel'],
        scope: {
            dateDirVal: "=ngModel"
        },
        controller: function ($scope) {

        },
        //use link instead of compiler to use DOM listeners
        link: function ($scope, element, attrs, ctrls) {
            var myCtrl = ctrls[0], ngModelCtrl = ctrls[1];

            var inputId = element.attr('id').toString();

            function gregorianToJalali(viewValue) {
                if ($scope.dateDirVal) {
                    var inputValue = $scope.dateDirVal;
                    var gDate = new Date(inputValue);
                    var gY = gDate.getFullYear();
                    var gM = gDate.getMonth();
                    var gD = gDate.getDate();
                    var value = JalaliDate.gregorianToJalali(gY, gM, gD);
                    var jalali = value[0].toString() + "/" + value[1].toString() + "/" + value[2].toString();

                    //The return of a $parsers is what is saved to the model
                    return jalali;
                }
            }

            Calendar.setup({
                inputField: inputId,
                ifFormat: '%Y/%m/%d',
                dateType: 'jalali'
            });

            function jalaliToGregorian(viewValue) {
                var jDate = viewValue.split('/');
                var value = JalaliDate.jalaliToGregorian(jDate[0], jDate[1], jDate[2]);
                var gDate = new Date(value[0], value[1], value[2]);

                //The return of a formmatter is what is rendered on the DOM
                return gDate;
            });

            //with that, jalaliToGregorian will be called every time a user fill the input
            ngModelCtrl.$parsers.unshift(jalaliToGregorian(viewValue))

            //gregorianToJalali will be called every time a model change, converting 
            // gregorian dates and presenting persian date on the view
            ngModelCtrl.$formatters.unshift(gregorianToJalali(viewValue))

        }
    };
});

I tried to not change so much your code to you figure out what happened... so I neither changed your jalaliToGregorian function, but you need to pay attention, that the $parsers function will bind to the model its return... and you are not checking if the inputed date were a persian date at all... if the function return undefined, the model will not be changed... and if return something else, that return will be binded, being a date or not (null can be binded if the inputed date were wrong)

like image 106
cefigueiredo Avatar answered Nov 15 '22 11:11

cefigueiredo