9

I was using ng-include on a few of my pages, however I had to stop using ng-include because it was breaking the angular-ui datepicker. I opened this Github bug.

I am wondering if anyone else was having issues with directives not functioning the same way when being used as part of a ng-include.

Is there a way to make the datepicker work as expected as part of a ng-include?

Here is a plunker showing how it is broken. http://plnkr.co/edit/AboEJGxAK3Uz76CfpaZ0?p=preview

Here is the html that works when on the view, but does not work when part of a ng include.

<div class="row">
  <div class="col-md-2">
    <p class="input-group">
      <input type="text" class="form-control" datepicker-popup="yyyy/MM/dd" ng-model="something.dt2" is-open="secondCal"
         min-date="minDate" name="secondCal" max-date="'2015-06-22'" datepicker-options="dateOptions"
         date-disabled="disabled(date, mode)" ng-required="true" close-text="Close"/>
        <span class="input-group-btn">
          <button type="button" class="btn btn-default" style="line-height: 1.2em" ng-click="open($event, 'secondCal')">
            <i class="ss-icon ss-calendar"></i>
          </button>
        </span>
    </p>
  </div>
</div>

Here is the JS from the controller.

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

      $scope[elementOpened] = !$scope[elementOpened];
  };

And two ways I was doing ng-include

<div ng-include src="'dist/partials/myPartial.html'"></div>
<div ng-include="'dist/partials/myPartial.html'"></div>

Update I found that this is because the ng-include directive creates a new scope for each include. This SO post creates a new directive that does the include without creating a new scope. However there seems there "should" be a way to fix it without using a different include.

Community
  • 1
  • 1
zmanc
  • 5,201
  • 12
  • 45
  • 90

2 Answers2

20

The datepicker will be unable to open as soon as the is-open is changed by the datepicker directive itself (e.g. click outside to close the datepicker).

This is a common issue regarding the "Prototypal Inheritance" characteristic of scope.

For a complete detail, you could read this: Understanding-Scopes

You could easily solve this by not storing any primitive values directly into $scope, but some object and using dot-notation like this:

<input type="text" class="form-control"
    datepicker-popup="yyyy/MM/dd" ng-model="something.dt2"
    is-open="model.secondCal"

and in your controller:

app.controller('MainCtrl', function($scope) {
  $scope.model = {};

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

    $scope.model[elementOpened] = !$scope.model[elementOpened];
  };
});

Example Plunker: http://plnkr.co/edit/dJNIwSz2Uot3McmIMhd4?p=preview

runTarm
  • 11,537
  • 1
  • 37
  • 37
  • thank you for this! I did change `$scope.model[elementOpened] = !$scope.model[elementOpened];` to `$scope.model[elementOpened] = true;` but everything works as expected. Kudos. – zmanc Aug 14 '14 at 12:41
0

I've created Plunker to debug it but it works fine with your code

http://plnkr.co/edit/nxYCiwRqdWMOkfZoRhGY?p=preview

<body ng-controller="MainCtrl">
  <div ng-include="'partial.html'"></div>
</body>

after clarification and further tests i see that calendar with ng-include lose the scope when triggering the change not by scope method, the easy workaround would be as per this plunker

http://plnkr.co/edit/nxYCiwRqdWMOkfZoRhGY?p=preview

Don't remember which one of the angular team said it but if you don't have a dot in your model you are doing it wrong.

a little explanation why it works:

if you do

$scope.valueName = value

it will assign value to the current scope immediately

but if you do

$scope.something.valueName = value

what will happen is that angular will first locate $scope.something, if it doesn't exists on current scope it will look in parent (as long as you don't work in isolated scope) then when it finds it it will assign value or return something like 'cant find valueName of undefined'

from the angularjs documentation: https://docs.angularjs.org/api/ng/directive/ngInclude

This directive creates new scope. This directive executes at priority level 400.

maurycy
  • 8,455
  • 1
  • 27
  • 44