简体   繁体   English

如何将数据从指令模板传递给控制器​​?

[英]How to Pass data from directive template to controller?

I am building some kind of date-picker, which is actually 2 date pickers. 我正在构建某种日期选择器,实际上是2个日期选择器。 one for start date and the other for end date.Every datepicker element generate a template of 2 input tags(). 一个用于开始日期,另一个用于结束日期。每个datepicker元素生成一个包含2个输入标记的模板()。 I want to pass data from input's value attribute to the controller. 我想将数据从input的value属性传递给控制器​​。 I have tried to define fields in the inner scope which are 2-way data binding(dateOne and dateTwo) but apparently no effect and no real data is pass between the 2 fields. 我试图在内部范围中定义字段,这些字段是双向数据绑定(dateOne和dateTwo)但显然没有效果,并且在两个字段之间没有传递实际数据。 My other approach is using ng-model, but I have little exprience with this feature and I don't know the rules for that. 我的另一种方法是使用ng-model,但我对这个功能没什么好处,我不知道这个规则。 Here is my code 这是我的代码

angular.module('directives', [])
    .directive('datepicker', ['$timeout',function ($timeout) {
        // Runs during compile
        return {
            scope: {
                id: '@',
                "class": '@',
                dateOne: '=',
                dateTwo: '='
            },
                restrict: 'E', // E = Element, A = Attribute, C = Class, M = Comment
                template: '<div id="{{id}}" class="{{class}}">'+
                        '<div class="date-wrapper">'+
                            '<label for="datepicker-start">From:</label>'+
                            '<div class="fieldWrapper">'+
                                '<input id="datepicker-start" type="date" placeholder="Select date" value={{dateOne}} />'+
                                '<a class="calendar"></a>'+
                            '</div>'+
                        '</div>'+
                        '<div class="date-wrapper">' +
                            '<label for="datepicker-end">To:</label>' +
                            '<div class="fieldWrapper">' +
                                '<input id="datepicker-end" type="date" placeholder="Select date" value={{dateTwo}}/>' +
                                '<a class="calendar"></a>' +
                            '</div>' +
                        '</div>'+
                        '</div>'
                        ,
                replace: true,
            link: function($scope, iElm, iAttrs, controller) {
                console.log('directive link function');
                console.log('directive iAttrs', iAttrs);
                $(".date-wrapper").each(function (index) {
                    console.log('directive index', index);
                    $input = $(this).find('input');
                    $btn = $(this).find('.calendar');

                    console.log('input', $input[0]);
                    console.log('btn', $btn[0]);

                    $input.attr('type', 'text');
                    var pickerStart = new Pikaday({
                        field: $input[0],
                        trigger: $btn[0],
                        container: $(this)[0],
                        format: 'DD/MM/YYYY',
                        firstDay: 1
                    });
                    $btn.show();
                });

            }
        };
}]);

------------------------Updated Code ----------------------------------- ------------------------更新代码------------------------ -----------

angular.module('directives', [])
    .directive('datepicker', ['$timeout',function ($timeout) {
        // Runs during compile
        return {
            scope: {
                id: '@',
                "class": '@',
                dateOne: '=',
                dateTwo: '='
            },
                restrict: 'E', // E = Element, A = Attribute, C = Class, M = Comment
                template: '<div id="{{id}}" class="{{class}}">'+
                        '<div class="date-wrapper">'+
                            '<label for="datepicker-start">From:</label>'+
                            '<div class="fieldWrapper">'+
                                '<input id="datepicker-start" type="date"  placeholder="Select date" ng-model=dateOne />' +
                                '<a class="calendar"></a>'+
                            '</div>'+
                        '</div>'+
                        '<div class="date-wrapper">' +
                            '<label for="datepicker-end">To:</label>' +
                            '<div class="fieldWrapper">' +
                                '<input id="datepicker-end" type="date" placeholder="Select date" ng-model=dateTwo />' +
                                '<a class="calendar"></a>' +
                            '</div>' +
                        '</div>'+
                        '</div>'
                        ,
                replace: true,
            link: function($scope, iElm, iAttrs, controller) {
                console.log('directive iAttrs', iAttrs);
                $(".date-wrapper").each(function (index) {
                    console.log('directive index', index);
                    $input = $(this).find('input');
                    $btn = $(this).find('.calendar');

                    console.log('input', $input[0]);
                    console.log('btn', $btn[0]);

                    $input.attr('type', 'text');
                    var pickerStart = new Pikaday({
                        field: $input[0],
                        trigger: $btn[0],
                        container: $(this)[0],
                        format: 'DD/MM/YYYY',
                        firstDay: 1
                    });
                    $btn.show();
                });

                $scope.$watch(iAttrs.dateOne, function (newValue, oldValue) {
                    console.log('newValue', newValue);
                    console.log('oldValue', oldValue);
                }, true);

            }
        };

Actually you are almost there, I've done something very similar to what you have described and here was my approach to solve it (I used the UI-Bootstrap Date picker in my case). 实际上你几乎就在那里,我做了一些非常类似于你所描述的东西,这是我解决它的方法(在我的例子中我使用了UI-Bootstrap Date选择器)。

The way you would send data from your directive to your controller is by using callbacks, rather than simple watches. 从指令向控制器发送数据的方式是使用回调,而不是简单的监视。 If you would have used = you would have to set watches in your controller (and directive) to watch for value changes, it's bad practice overall and extra code. 如果你曾经使用过=你必须在你的控制器(和指令)中设置监视来监视值的变化,这是不好的做法,总体和额外的代码。

So basically what you need to do is 基本上你需要做的是

  1. In you directive definition object bind a callback method/function using the & sign like so 在你的指令定义对象中使用&符号绑定一个回调方法/函数

     scope: { onSelect: "&" // onSelect is our callback function in the ctrl } 
  2. You then supply the callback attribute a function bound to the controller's $scope, but you pass it a function reference (not a function call as you would in something like ng-changed). 然后,为回调属性提供一个绑定到控制器$ scope的函数,但是你传递一个函数引用(而不是像ng-changed那样的函数调用)。 like so 像这样

    <my-directive on-selected="onSelected"></my-directive>

  3. Then you define what onSelected should do, lets say I want to print the selected date 然后你定义onSelected应该做什么,假设我想打印选定的日期

     // inside controller $scope.onSelected = function(time) { console.log("Time selected: ", time); } 

Note that we pass the time argument from the directive to the controller like so, scope.onSelect() is actually a curried function, meaning it will return a function once called (that is, if you provided it with a function, you could test it using angular.isFunction ), so you should call the curried function and provide it your argument, scope.onSelect()(time) . 请注意,我们将指令中的time参数传递给控制器​​,因此, scope.onSelect()实际上是一个scope.onSelect()函数,这意味着它将在调用后返回一个函数(也就是说,如果你提供了一个函数,你可以测试它使用angular.isFunction ),所以你应该调用angular.isFunction函数并提供你的参数scope.onSelect()(time)

scope.selectDate = function(time) {
    if (angular.isFunction(scope.onSelect())) {
        // we use isFunction to test if the callback function actually
        // points to a valid function object
        scope.onSelect()(time); // we pass out new selected date time
      }
  }

Here is a plunk that shows what I mean. 这是一个显示我的意思的插件

  1. Replace value in the template with ng-model=dateOne and the same with dateTwo. 用ng-model = dateOne替换模板中的值,用dateTwo替换相同的值。

  2. I suggest to use a dedicated controller for this directive and not doing the logic inside the link function. 我建议使用专用控制器来执行此指令,而不是在链接函数中使用逻辑。

app.directive('someDirective', function () { return { restrict: 'A', controller: 'SomeController', controllerAs: 'ctrl', template: '{{ctrl.foo}}' }; }); app.directive('someDirective',function(){return {restrict:'A',controller:'SomeController',controllerAs:'ctrl',template:'{{ctrl.foo}}'};});

Read more here http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html 在这里阅读更多http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM