angular-ui: datepicker seems to hang angularjs when showing button

I have this piece of html code in my application (the ng-app and ng-controller values are defined before):

<div>
    <label for="projectSearchDateFrom"><%= Res("Projects.Search.From")%></label>
    <input id="projectSearchDateFrom" type="text" ng-model="startDate" ui-date="dateOptions"/>
    <img ng-show="hasStartDate()" ng-click="clearStartDate()" src="/_Layouts/ClientPortal/Images/layout/TA/delete-small.png" alt="<%= Res("ToolbarDialog.Clear")%> <%= Res("Projects.Search.From")%>" title="<%= Res("ToolbarDialog.Clear")%>" />
</div>

My AngularJS controller looks like this:

function ProjectSearchCtrl($scope) {
    $scope.startDate = '';

    $scope.hasStartDate = function () {
        return $scope.startDate != '';
    };

    $scope.clearStartDate = function () {
        $scope.startDate = '';
    };

    $scope.dateOptions = {
        dateFormat: "yy-mm-dd",
        showOn: "focus"
    };
}

This works perfectly: I have a datepicker set up correctly thanks to AngularUI, the AngularJS binding works...

But if I change the showOn value to "button" or "both" (the two possible options which will actually show the datepicker button), everything after the input (containing the ui-date attribute) stops working: ng-show, ng-click... The controller doesn't even get called.

Versions (all is up-to-date):

  • jQuery 1.7.2
  • angularJS 1.0.0
  • angularUI 0.1.0
  • Chrome 20

Please take a look at this line in the Select2 directive. This is a note to ANYONE writing a directive / implementing a plugin in AngularJS (not just AngularUI):

Any plugin that injects a new DOM element immediately after the linked element runs the risk of disrupting the compiler. The reason is because the way AngularJS works, it caches the index of each DOM element at compile time, and then makes a second pass upon linking. When you inject new DOM, you offset the index of all siblings immediately after the directive.

For this reason, I've been forced to wrap both TinyMCE and Select2 in a setTimeout so that the DOM is injected after the linking is done. Note that I don't bother using $timeout because I really don't need/want $apply() to fire just to turn on the plugin, as there are already callbacks in place that do this when the plugin changes the data.

I'll look into making sure this is uniform across AngularUI. Unfortunately, there appears to be no elegant solution to this problem in AngularJS at this time, however it's a problem I've been thinking about for some time and am constantly looking for a better solution towards.

Read this Google Groups post for more information about compiling vs linking: https://groups.google.com/forum/?fromgroups#!searchin/angular/compile$20link/angular/RuWn5W3Q5I0/KJhcQJ_RNsIJ

You can also open a bug ticket on the AngularUI project in the future.

As suggested by Pete BD in his comment on the question, there is some kind of bug/unwanted behaviour in the way that jQueryUI and angularJS interact. A workaround is to wrap the input control in a div.

<div class="date">
    <label for="projectSearchDateFrom"><%= Res("Projects.Search.From")%></label>
    <div>
        <input id="projectSearchDateFrom" type="text" ng-model="startDate" ui-date="dateOptions"/>                                  
    </div>
    <img class="clear" ng-show="hasStartDate()" ng-click="clearStartDate()" src="/_Layouts/ClientPortal/Images/layout/TA/delete-small.png" alt="<%= Res("ToolbarDialog.Clear")%> <%= Res("Projects.Search.From")%>" title="<%= Res("ToolbarDialog.Clear")%>" />
</div>

Now I can use showOn "both" or "button".

This is fixed in the latest release!