Attach click event for the weekday labels in Angul

2019-08-09 23:32发布

问题:

I'm using Angular UI Bootstrap datepicker with the gm.datepickerMultiSelect extension and I'd like to make weekdays labels clickable, so that I could select all days in the month (like all Wednesdays). I can get/calculate all days of the same weekday and add them to the selected days scope, but as I'm rather new to AngularJS & Bootstrap UI, I can't find the right way to trigger that click event for the labels.

回答1:

Angular UI Bootstrap lets you override their directive's templates. You can create your own template by putting it inside a <script> tag with type text/ng-template.

So we copy the contents of Angular UI's template/datepicker/day.html and we alter it a little bit to call a new function selectWeekday on our weekday's ng-click :

<script type="text/ng-template" id="template/datepicker/day.html">
  <table role="grid" aria-labelledby="{{::uniqueId}}-title" aria-activedescendant="{{activeDateId}}">
    <thead>
      <tr>
        <th>
          <button type="button" class="btn btn-default btn-sm pull-left" ng-click="move(-1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-left"></i></button>
        </th>
        <th colspan="{{::5 + showWeeks}}">
          <button id="{{::uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button" class="btn btn-default btn-sm" ng-click="toggleMode()" ng-disabled="datepickerMode === maxMode" tabindex="-1" style="width:100%;"><strong>{{title}}</strong></button>
        </th>
        <th>
          <button type="button" class="btn btn-default btn-sm pull-right" ng-click="move(1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-right"></i></button>
        </th>
      </tr>
      <tr>
        <th ng-if="showWeeks" class="text-center"></th>
        <!-- Added ng-click and style -->
        <th ng-click="selectWeekday(label)" style="cursor:pointer;" ng-repeat="label in ::labels track by $index" class="text-center"><small aria-label="{{::label.full}}">{{::label.abbr}}</small></th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="row in rows track by $index">
        <td ng-if="showWeeks" class="text-center h6"><em>{{ weekNumbers[$index] }}</em></td>
        <td ng-repeat="dt in row track by dt.date" class="text-center" role="gridcell" id="{{::dt.uid}}" ng-class="::dt.customClass">
          <button type="button" style="min-width:100%;" class="btn btn-default btn-sm" ng-class="{'btn-info': dt.selected, active: isActive(dt)}" ng-click="select(dt.date)" ng-disabled="dt.disabled" tabindex="-1"><span ng-class="::{'text-muted': dt.secondary, 'text-info': dt.current}">{{::dt.label}}</span></button>
        </td>
      </tr>
    </tbody>
  </table>
</script>

Note: This script tag must be within your ng-app or else it will be ignored and won't overwrite the original template.

Now we need to modify the datepicker directive with AngularJS decorators to add the selectWeekday function:

angular.module('myApp', [
  'ui.bootstrap',
  'gm.datepickerMultiSelect'
  ])
  .config(function($provide) {
    $provide.decorator('datepickerDirective', function($delegate) {
      var directive = $delegate[0];
      //get a copy of the directive's original compile function
      var directiveCompile = directive.compile;

      //overwrite the original compile function
      directive.compile = function(tElement, tAttrs) {
        // call the directive's compile with apply to send the original 'this' and arguments to it
        var link = directiveCompile.apply(this, arguments);

        //here's where the magic starts
        return function(scope, element, attrs, ctrls) {
          //call the original link
          link.apply(this, arguments);

          scope.selectWeekday = function(label) {
            scope.$emit('datepicker.selectWeekday', label);
          };

        };
      };

      return $delegate;
    });
  })

And from the controller listen to datepicker.selectWeekday:

.controller('DateController', function($scope) {

  $scope.$on('datepicker.selectWeekday', function(event, newVal) {
    $scope.selectedWeekday = newVal;
  });

});

From here you can add the logic to select the days based on the known selected weekday!

Here's a working plunkr: http://plnkr.co/edit/Ef4gd7SUYMcG05PuvqFh?p=preview