2

I am creating a simple CRUD using AngularJS and facing a minor issue. While editing a form I am getting json string returned by server in model and I have created my custom directive to format that date. It formats the date but scope is not applied and when I submit the form I get the old json date in alert.

MY Js goes like this:

 var myApp = angular.module('myApp', ['toaster']).controller('MyController',function($scope){
$scope.old = {    ship_date : '/Date(1359743400000)/'    };

$scope.UpdateShipment = function ()     {
    alert($scope.old.ship_date);
}
}).directive('formatDate', function () {

return {
    require: 'ngModel',
    scope : {'ngModel' : '='},
    link: function (scope, element, attr, ngModelController) {

        ngModelController.$formatters.unshift(function (valueFromModel) {

            if (angular.isUndefined(valueFromModel)) {
                return valueFromModel;
            }

            var date = new Date(parseInt(valueFromModel.substr(6)));
            console.log(valueFromModel);
            return date.toLocaleDateString();
        });
    }
};
});

View:

 <div ng-app="myApp">
  <div ng-controller="MyController">
    <input type="text" ng-model="old.ship_date" />   <form ng-submit="UpdateShipment()">
     <input type="text"  format-Date ng-model="old.ship_date" />
     <input type="submit" id="submit" value="Save" />
   </form>
 </div>
</div>

PLEASE HELP , MANY THANKS.

Jitender Sharma
  • 119
  • 3
  • 13

6 Answers6

4

I had similiar issues, but i handled it in $http interceptor. You can transform the date strings into javascript objects. No need for custom directive. I think it is a lot cleaner approach.

Here is example implementation: http://aboutcode.net/2013/07/27/json-date-parsing-angularjs.html

  app.config(["$httpProvider", function ($httpProvider) {
     $httpProvider.defaults.transformResponse.push(function(responseData){
        convertDateStringsToDates(responseData);
        return responseData;
    });
}]);
stride
  • 1,931
  • 1
  • 17
  • 20
1

All previous Answers about you needing to call $scope.apply() are correct, but as you have seen it can throw an error when another digest/apply is already in progress so to call it safely use this

if(!$scope.$$phase){$scope.$apply();}

this will only call it if it is not in progress and hopefully might fix your issue.

Jared Reeves
  • 1,390
  • 2
  • 15
  • 29
0

Use $scope.$apply() when your operating a function outside the angular way.

Try after the ngModelController({...}) function add $scope.$apply();

user2720708
  • 455
  • 2
  • 8
  • 19
0

You need to use $scope.$apply. Refer this post about modify scope inside directive.

Community
  • 1
  • 1
Saravana Kumar
  • 816
  • 1
  • 12
  • 28
  • I read the post but that scenario is different. I want to do this when model is rendered unlike their case where they are binding scope to event – Jitender Sharma Dec 06 '13 at 12:19
0

just remove the scope-defintion from your directive

enter code here

http://jsfiddle.net/2vxCA/

kfis
  • 4,739
  • 22
  • 19
0

To build off of the answer from 'stride', you can also implement this using an interceptor. There's a few critical change you need to make when implementing it as an interceptor.

First, your .config section would look like this:

.config([
  $httpProvider", function($httpProvider) {
  $httpProvider.interceptors.push("httpInterceptorTransformResponseService");
  }
])

With that in place, you would build a factory service to intercept and transform the data similar to the example from http://aboutcode.net/2013/07/27/json-date-parsing-angularjs.html. The regex is somewhat arbitrary and depending on the data you're actually retrieving via your requests, you may want/need to change it.

(function () {
    "use strict";
    angular.module("yourAppNameHere")
    .factory("httpInterceptorTransformResponseService",
        [
            function () {
                // Purpose: This interceptor is intended to convert Json strings that match the ISO8601 date format  into DateTime objects.
                // This is necessary in many cases because there is not an object type embedded into serialized Json that represents a DateTime object.

                // There are numerous variations of this regex. Choose the one that works best for you, based on what data you expect
                var regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})\.(\d{1,})(Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;

                function convertDateStringsToDates(input) {
                    // Ignore things that aren't objects.
                    if (typeof input !== "object")
                        return;

                    for (var key in input) {
                        if (!input.hasOwnProperty(key))
                            continue;

                        var value = input[key];
                        var match;
                        // Check for string properties which look like dates.
                        if (typeof value === "string" && (match = value.match(regexIso8601))) {
                            var milliseconds = Date.parse(match[0])
                                if (!isNaN(milliseconds)) {
                                    input[key] = new Date(milliseconds);
                                }
                        } else if (typeof value === "object") {
                            // Recurse into object
                            convertDateStringsToDates(value);
                        }
                    }
                }

                // declare the service
                var transformResponseService = {
                    response: function (response) {
                        // convert all parsable date strings returned from the data into Date objects
                        convertDateStringsToDates(response.data);
                        return response;
                    }
                };

                return transformResponseService;
            }
        ]);
})();

CRITICAL PART: Notice near the end where the service is declared and the response for the transform is declared. The version above for the interceptor is called as follows:

convertDateStringsToDates(response.data);

and NOT

convertDateStringsToDates(response);

If you send response instead of response.data to the function when using an interceptor, what happens is that it will parse EVERYTHING that comes back from the entire http request. This means that in addition to the data it retrieves, it will also apply this to things like the http configuration, headers, etc.

I ran into an issue where it was running the regex against the config section of the http request. Because it's a recursive service and objects are treated like references, it entered an infinite loop and would overflow the stack. It's highly likely that you will only want to apply this to the data that's returned, not the configuration, headers, etc.

Mike Taber
  • 833
  • 6
  • 21