无法将日期选择器结果从ng自定义指令绑定到html输入字段

时间:2017-05-24 03:19:01

标签: javascript angularjs dom angularjs-directive

我是js和Angular.js的完全初学者。我需要一些帮助将返回结果从Angular自定义指令中的日期选择器返回到HTML输入字段中的ng-model。在这里 -

我的HTML表单使用ng-controller从后端数据库中检索数据以填充元素,其中包括日期字段。可以使用附加的日期选择器更新此日期字段。鉴于Jquery日期选择器不适用于FireFox和Safari浏览器中的angular.js,我编写了一个实现日期选择器的自定义ng指令。但是,我在从custom指令返回结果以替换HTML中的原始日期字段时遇到问题。

在我的HTML中,日期输入字段为ng-model="myCtrl.deadline",而我的自定义指令为"scope.deadline = date;" - 没有"myCtrl"前缀。如果我设置ng-model="deadline",那么日期字段将不会被从后端拉出的初始数据填充。如果我设置ng-model={{deadline}},当我从日期选择器中选择一个新日期时,我会在浏览器中收到angular.min.js错误。

自定义指令中的日期选择器工作正常,我可以在HTML日期字段中选择一个新日期,但新日期不绑定到HTML字段。因此,没有办法区分。具有先前值的新值以检测更改并触发将新日期值更新到后端。

以下是我的代码的样子:

代码

<html ng-app="myApp" ng-controller="MyCtrl as myCtrl">
<head>
      <script src="js/angular.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-messages.js"></script>

    <title>Edit your data</title>
</head>
<body>
<div class="container">
...
       <div  class="row">
          <div class="col-sm-4 col-md-4"><strong>Deadline:</strong></div>
          <div class="col-sm-8 col-md-8">
          <input type="text" 
            class="form-control" 
            id="theDate"
            ng-model="myCtrl.deadline" 
            ng-blur="myCtrl.update('deadline')"
            ng-change="myCtrl.update('deadline')"
            required jq-date-picker><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></div>
       </div>
<div>
...
</body>
<script type="text/javascript">
    var app = angular.module('myApp', ['ngMessages']);
    app.controller(
            'MyCtrl',
            ['$http','$location','$timeout', function($http, $location, $timeout) {
                        var self = this;
                        self.Id="";
                        ...                     
                        self.deadline = "";
                        self.prevDeadline = "";

            // function begin
            //handles updates on the page
            self.update = function(varname){
                      var changed = false;
                     // the 2 statements show self.deadline not get updated
                     // with the new date value from the custom directive
                     // can't diff. with prevDeadline to detect a change  
                      console.log("prev.DeadLine: " + self.prevDeadline);
                      console.log("new.deadLine: " + self.deadline);
                     ...
            }

            //retrieve data initially
            self.getData = function(Id){
                            $http.get('/rest/v3/getData/',{params:{betId: betId}}).then(
                                    function(response){
                                            var data = response.data;
                                            ....
                                            self.deadline = data.deadline;
                                            self.prevDeadline = self.deadline;
                                            ...
                            );
                        }

                    } ]);

    app.directive('jqDatePicker', function (){
          return {
              restrict: 'A',
              require: 'ngModel',
              link: function (scope, element, attrs, ngModelCtrl) {
                  element.datepicker({
                      dateFormat: 'D, d MM yy',
                      onSelect: function (date) {
                          scope.deadline = date;
                          scope.$apply();
                      }
                  });
              }
          };
      });

</script>
</html>

很抱歉这篇长篇文章。我是一个新手,发现使用角度UI Bootstrap方法来解决这个问题对我目前的理解有点过分了。谢谢你的帮助。

跟进问题:如果我在演示代码https://angular-ui.github.io/ui-date/中使用角度datepicker方法,则指令代码如下所示

      angular.module('MyApp', ['ui.date'])
      .controller('MyCtrl', function($scope) {
          $scope.aDate = '2015-10-31';
          $scope.dateOptions = {
             dateFormat: 'dd.mm.yy',
          }
      })

我现有的控制器代码如下所示

    var app = angular.module('myApp', ['ngMessages']);
    app.controller(
        'MyCtrl',
        ['$http','$location','$timeout', function($http, $location, $timeout) {
            var self = this;
            self.Id="";
            ... 
            self.deadline = "";
            self.prevDeadline = "";
            ... 
    } ]);

如何将两个代码段合并在一起?会这样吗?

    var app = angular.module('myApp', ['ui.date', 'ngMessages']);
    app.controller(
        'MyCtrl',
        ['$http','$location','$timeout', '$scope', function($http, $location, $timeout, $scope) {
        var self = this;
        self.Id="";
        ... 
        self.deadline = "";
        self.prevDeadline = "";
        ...
        $scope.aDate = '2015-10-31';
        $scope.dateOptions = {
        dateFormat: 'dd.mm.yy', 
        ... 
    } ]); 

作为初学者,我发现Angular.org文档和教程对我来说并不容易理解。到目前为止,我依靠在网上查找代码示例来编码我需要的代码。我想正确学习角度自定义指令,这样我就可以编写不同的要求,而不是在我找不到要复制和粘贴的代码示例时被卡住。非常感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

你只需要:

ngModelCtrl.$setViewValue(date);

在:

app.directive('jqDatePicker', function() {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, element, attrs, ngModelCtrl) {
        $(element).datepicker({
          dateFormat: 'D, d MM yy',
          onSelect: function(date) {
            ngModelCtrl.$setViewValue(date); // <--
          }
        });
      }
    };
  });
  

<强> ngModel.NgModelController:

     

NgModelController为ngModel指令提供API。该   controller包含数据绑定,验证和CSS的服务   更新,值格式化和解析。故意没有   包含处理DOM呈现或侦听DOM的任何逻辑   事件。这种与DOM相关的逻辑应该由其他指令提供   它利用NgModelController进行数据绑定来控制   元件。

     

$setViewValue(value, trigger):

     

更新视图值。

     

当控件想要更改视图时,应调用此方法   值;通常,这是在DOM事件处理程序中完成的。对于   例如,input指令在输入值时调用它   更改并选择在选择选项时调用它。

这样的事情:

(function() {
  var app = angular.module('myApp', ['ngMessages']);
  app.controller('MyCtrl', ['$http', '$location', '$timeout', function($http, $location, $timeout) {
    var self = this;
    self.Id = "";
    self.deadline = "";
    self.prevDeadline = "";

    //retrieve data initially
    self.getData = function(Id) {
      $http.get('/rest/v3/getData/', {
        params: {
          betId: betId
        }
      }).then(function(response) {
        var data = response.data;

        self.deadline = data.deadline;
        self.prevDeadline = self.deadline;
      }, function(response) {
        console.log(response);
      });
    };
  }]);

  app.directive('jqDatePicker', function() {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, element, attrs, ngModelCtrl) {
        $(element).datepicker({
          dateFormat: 'D, d MM yy',
          onSelect: function(date) {
            ngModelCtrl.$setViewValue(date);
          }
        });
      }
    };
  });
})();
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-messages.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<div data-ng-app="myApp">
  <div data-ng-controller="MyCtrl as myCtrl">

    <div class="container">
      <div class="row">
        <div class="col-sm-4 col-md-4"><strong>Deadline:</strong></div>
        <div class="col-sm-8 col-md-8">
          <input type="text" class="form-control" id="theDate" ng-model="myCtrl.deadline" required jq-date-picker><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></div>
      </div>
      <div>
        Selected Date: {{myCtrl.deadline}}
      </div>
    </div>
  </div>
</div>

使用https://angular-ui.github.io/ui-date/assets/date.js

  1. 您需要添加此JavaScript外部文件: (https://angular-ui.github.io/ui-date/assets/date.js)在您的信息页中。
  2. 在textBox日期字段中添加ui-date="dateOptions"
  3. 在模块中注入'ui.date'依赖项。
  4. 在控制器中添加'$scope'
  5. 这样的事情:

    (function() {
      var app = angular.module('myApp', ['ngMessages', 'ui.date']);
      app.controller('MyCtrl', ['$scope', '$http', '$location', '$timeout', function($scope, $http, $location, $timeout) {
        var self = this;
        self.Id = "";
        self.deadline = "06.10.2015";
        self.prevDeadline = "";
    
    
        $scope.dateOptions = {
          dateFormat: 'dd.mm.yy',
        };
    
        //retrieve data initially
        self.getData = function(Id) {
          $http.get('/rest/v3/getData/', {
            params: {
              betId: betId
            }
          }).then(function(response) {
            var data = response.data;
    
            self.deadline = data.deadline;
            self.prevDeadline = self.deadline;
          }, function(response) {
            console.log(response);
          });
        };
      }]);
    })();
    <link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-messages.js"></script>
    <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script src="https://angular-ui.github.io/ui-date/assets/date.js"></script>
    
    <div data-ng-app="myApp">
      <div data-ng-controller="MyCtrl as myCtrl">
    
        <div class="container">
          <div class="row">
            <div class="col-sm-4 col-md-4"><strong>Deadline:</strong></div>
            <div class="col-sm-8 col-md-8">
              <input type="text" class="form-control" id="theDate" ng-model="myCtrl.deadline" required ui-date="dateOptions"><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span></div>
          </div>
          <div>
            Selected Date: {{myCtrl.deadline}}
          </div>
        </div>
      </div>
    </div>

    希望这有帮助。