1

I'm using angularjs 1.4.4

I'm trying to update the $locale dynamically and it is updating. When a filter gets run it uses the correct updated $locale to evaluate itself. Unfortunately old filters don't re-run themselves.

var englishMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var frenchMonths = ["janvier", "f\u00e9vrier", "mars", "avril", "mai", "juin", "juillet", "ao\u00fbt", "septembre", "octobre", "novembre", "d\u00e9cembre"];

$scope.array = [];
$scope.currentDate = 'english';

$scope.addDate = function(){
  $scope.array.push(new Date());  
};
$scope.switchDate = function(){
    var monthArray = englishMonths
    if($scope.currentDate === 'english'){
       monthArray = frenchMonths;
        $scope.currentDate = 'french';
    }
    else{
     $scope.currentDate = 'english';   
    }
    $locale.DATETIME_FORMATS.MONTH.length = 0;
    for(var x = 0; x < monthArray.length; x++){
        $locale.DATETIME_FORMATS.MONTH.push(monthArray[x] + ($scope.currentDate === 'french' ? "FRENCH" : ''));
    }
};

And in the dom:

<button data-ng-click="addDate()">Add Date</button>     
<button data-ng-click="switchDate()">Toggle Language, current: {{ currentDate }}</button>   
<hr></hr>
<div data-ng-repeat="date in array">
    {{ date | date:'longDate' }}
</div>

If you add a date to the array it will evaluate at the current language. If you change the language the old dates won't re-evaluate.

You can see this in the fiddle I've made: http://jsfiddle.net/wf8ojqjg/

So I need a way for the $locale to update, which really boils down to forcing all filters to recalculate.

Mathew Berg
  • 28,625
  • 11
  • 69
  • 90
  • What about a solution like [this](http://jsfiddle.net/davidepastore/wf8ojqjg/1/)? – Davide Pastore Sep 09 '15 at 13:02
  • I have arrays all over my application so this will not work. – Mathew Berg Sep 09 '15 at 13:56
  • Do they share the same structure? You could be interested to use [services](https://docs.angularjs.org/guide/services). – Davide Pastore Sep 09 '15 at 14:00
  • No, I have {{ variable | date:'longDate' }} all over my code. In different scopes. Services will not fix this unless I put every date through a converter first which is not ideal, it should be handled automatically. – Mathew Berg Sep 09 '15 at 14:08

3 Answers3

0

So it looks like this may not be possible directly with the $locale service. Take a look at this SO link for someone basically wanting to do the exact same thing:

Angularjs and $locale

Community
  • 1
  • 1
smb
  • 539
  • 2
  • 13
  • 33
0

Interesting question!

As others mentioned, filters won't get updated by the digest loop due the instances of the objects they're "observing" do not change so they won't get re-applied.

One workaround for this "issue" is to regenerate the array of dates in your example with "new" dates, therefore the filters will be triggered.

Take a look to this updated JSFiddle: http://jsfiddle.net/wf8ojqjg/3/

angular
    .module('app', [])
    .controller('ParentCtrl', ParentCtrl)

function ParentCtrl($scope, $locale) {

    var englishMonths = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
    var frenchMonths =  ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
        'octobre', 'novembre', 'décembre'];

    $scope.arrays = {
        dates: []
    };
    $scope.currentDate = 'english';

    $scope.addDate = function(){
      $scope.arrays.dates.push(new Date());
    };

    $scope.switchDate = function(){
        var monthArray = englishMonths
        if($scope.currentDate === 'english') {
            monthArray = frenchMonths;
            $scope.currentDate = 'french';
        } else {
            $scope.currentDate = 'english';   
        }
        $locale.DATETIME_FORMATS.MONTH = monthArray;
        $scope.arrays.dates = renewInstancesOfArrayOfDates($scope.arrays.dates);
    };

    var renewInstancesOfArrayOfDates = function(array) {
        var temp = [];

        angular.forEach(array, function(t) {
            temp.push(new Date(t));
        });

        return temp;
    };
}

I don't this can be considered a proper nor elegant solution because there's no point in regenerating arrays and consuming more and more memory.

Use it with responsibility.

0

So based on some research it looks like the only way to do this is to overwrite the original datefilter like so:

.config(function ($provide) {
    $provide.decorator('dateFilter', function ($delegate) {
        $delegate.$stateful = true;
        return $delegate;
    });
})

This is undocumented and only exists in newer versions of angular. You can see the fix is working on the fiddle here: http://jsfiddle.net/y8bobe6g/

Mathew Berg
  • 28,625
  • 11
  • 69
  • 90