1

I have have an input field which is attached an Angular UI datepicker. Below that, I added 2 buttons to change date, "day by day".

Here is the input part (just after in my page):

<p class="input-group">
    <span class="input-group-addon hidden-xs">From</span>
    <input type="text" class="form-control text-center" datepicker-popup="{{format}}" ng-model="parent.dtFrom"   ng-change="refresh(0)" show-button-bar="false" is-open="opened1" max-date="maxDate" datepicker-options="dateOptions" ng-required="true" close-text="Close" readonly />
    <span class="input-group-btn">
        <button type="button" class="btn btn-default" ng-click="open($event, 'opened1')"><i class="glyphicon glyphicon-calendar"></i></button>
    </span>
</p>

And here are my button to change it:

 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 btn-group" role="group" >
   <div class="text-center" >
     <button type="button" class="btn btn-default btn-outline glyphicon glyphicon-chevron-left text-center previousdate" ng-click="addDayFrom(-1)"></button>
     <button type="button" class="btn btn-default btn-outline glyphicon glyphicon-home text-center todaydate"  ng-click="DateFromToday()"></button>
     <button type="button" class="btn btn-default btn-outline glyphicon glyphicon-chevron-right text-center nextdate" ng-click="addDayFrom(1)" ng-show="parent.dtFrom < todate" ></button>
   </div>
 </div>

Here is how I init my dtFrom at the begin of my controller:

$scope.parent={
    dtFrom : new Date(),
    dtTo : new Date()
};

And this is my function for change dtFrom:

$scope.addDayFrom=function(day){
    $scope.parent.dtFrom.setDate($scope.parent.dtFrom.getDate() +  parseInt(day));
    console.log($scope.parent.dtFrom);
};

It change value in $scope.parent.dtFrom but model isn't updated into input.

Example: Today we are 12/05/2015.

If I click one time on previous button, $scope.parent.dtFrom will be 11/05/2015.

And that's what is displayed all but the input.

I suppose that's a scope issue, but can't figure out where it is. Have you any clue to fix this ?

Edit: Picture here : http://hpics.li/4e0fab6

falsarella
  • 12,217
  • 9
  • 69
  • 115
Pierolain
  • 189
  • 1
  • 3
  • 18

2 Answers2

1

Change your code from:

$scope.addDayFrom=function(day){
    $scope.parent.dtFrom.setDate($scope.parent.dtFrom.getDate() +  parseInt(day));
    console.log($scope.parent.dtFrom);
};

To this:

$scope.addDayFrom=function(day){
    $scope.parent.dtFrom = ($scope.parent.dtFrom.getDate() +  parseInt(day));
    console.log($scope.parent.dtFrom);
};

Looking at the Angular UI datepicker documentation, you can see that you don't need to access parent. I thought you were trying to access the parent scope, but actually you were accessing the parent attribute that you have set here:

$scope.parent={
    dtFrom : new Date(),
    dtTo : new Date()
};

Angular UI datepicker is watching by reference, as we can see in their source code, what makes perfect sense, since that's the most efficient watching strategy. To understand more about that, read Scope $watch Depths on Angular core documentation:

Scope $watch Depths

Dirty checking can be done with three strategies: By reference, by collection contents, and by value. The strategies differ in the kinds of changes they detect, and in their performance characteristics.

  • Watching by reference (scope.$watch (watchExpression, listener)) detects a change when the whole value returned by the watch expression switches to a new value. If the value is an array or an object, changes inside it are not detected. This is the most efficient strategy.
  • Watching collection contents (scope.$watchCollection (watchExpression, listener)) detects changes that occur inside an array or an object: When items are added, removed, or reordered. The detection is shallow - it does not reach into nested collections. Watching collection contents is more expensive than watching by reference, because copies of the collection contents need to be maintained. However, the strategy attempts to minimize the amount of copying required.
  • Watching by value (scope.$watch (watchExpression, listener, true)) detects any change in an arbitrarily nested data structure. It is the most powerful change detection strategy, but also the most expensive. A full traversal of the nested data structure is needed on each digest, and a full copy of it needs to be held in memory.

    enter image description here

That's why it wasn't detecting $scope.parent.dtFrom.setDate(newDate) usage, and the model wasn't being updated. So, just change that piece of code to $scope.parent.dtFrom = newDate, and it should work (as it has already worked with your global variable approach).

falsarella
  • 12,217
  • 9
  • 69
  • 115
0

It's a bit of hack but, it works ... so I share it with you

When i start my app i create a local date variable that i change when i click on my button. when it's done, i do that :

$scope.parent.dtFrom = new Date(localDateVariable);

Not the best solution, but a solution.

falsarella
  • 12,217
  • 9
  • 69
  • 115
Pierolain
  • 189
  • 1
  • 3
  • 18
  • Maybe `$scope.parent.dtFrom.setDate($scope.parent.dtFrom.getDate() + parseInt(day));` isn't correct. How do you set `locaDateVariable`? – falsarella May 12 '15 at 18:27
  • When app start, I init `$scope.parent.dtFrom` and my `localDateVariable` as date object. Then, on click event on previous day button, i fire a function which remove one day to `localDateVariable` with `localDateVariable.setDate(localDateVariable.getDate() + parseInt(day));`, Then i just assign it to `$scope.parent.dtFrom = new Date(localDateVariable);` For keeping updated my local variable, when i catch change event from datepicker on my input, I do that : `localDateVariable = $scope.parent.dtFrom;` – Pierolain May 13 '15 at 07:47