AngularJS指令的动态选项

时间:2015-04-02 20:53:35

标签: javascript angularjs

我正在尝试将动态变量传递给显示时间选择器的指令(pickadate.js:http://amsul.ca/pickadate.js/time/)。但是,我正在努力研究如何将选项纳入指令。我在互联网上搜索,但看到了很多方法,并且很困惑如何最好地构建它,因为它不起作用。这是我目前的代码:

指令:

// Pick a date directive used as pick-a-time on HTML element
appDirectives.directive('pickATime', function() {
    return {
        // Restrict it to be an attribute in this case
        restrict: 'A',
        // responsible for registering DOM listeners as well as updating the DOM
        link: function(scope, element, attrs) {
            element.pickatime(scope.$eval(attrs.pickATime));
        },
        scope: {
            timeOptions: '=options'
        },
        templateUrl: '../Templates/timeoptions.html'
    };
});

指令模板:

Min: {{timeOptions.startTime}} Max: {{customerInfo.endTime}}

HTML:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time options="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

传递动态值的控制器(存储在REST中)

// Query settings for variables to be used later in function
appSettings.query(function(settings) {
    // Data is within an object of "value", so this pushes the server side array into a variable
    var setting = settings.value;

    // Foreach result, where setting is equal to active get the apporpriate variables
    angular.forEach(setting, function(settingvalue, settingkey) {
        if (settingvalue.Title == 'Active') {

            // Get work and non work durations as variables
            workDuration = settingvalue.Work_x0020_Day_x0020_Hours_x0020;
            nonWorkDuration = settingvalue.Non_x0020_Work_x0020_Day_x0020_H;

            // Get $scope variables to control time picker range
            var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
            var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
            var startTime = '[' + startHour + ',' + startMinute + ']';
            var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
            var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];    
            var endTime = '[' + endHour + ',' + endMinute + ']';
            $scope.timeRange = {min: startTime, max: endTime};                  
        }
    })
});

输入的非动态方法(有效)如下:

<input type="text" placeholder="End Time" id="timeend" pick-a-time="{min: [0,0], max: [23,30]}" data-ng-model="itemtimeend"class="form-control" autocomplete="off">

更新:与Dave合作,我已调整为以下内容。它正确记录timeRange,但为指令

中的timeOptions提供了未定义的内容

timeRange日志:

 time start is [8,30]time end is [17,0]

timeOption log:

 time options log undefined

指令(在日志记录中未定义timeOptions):

appDirectives.directive('pickATime', function() {
return {
    // Restrict it to be an attribute in this case
    restrict: 'A',
    // responsible for registering DOM listeners as well as updating the DOM
    link: function(scope, element, attrs) {
        element.pickatime(scope.pickATime);
        console.log("time options log" + scope.timeOptions);
    },
    scope: {
        timeOptions: '='

    },
    templateUrl: '../Templates/timeoptions.html'
};

});

模板:

min: {{timeOptions.min}}, max: {{timeOptions.max}}

控制器(正确注销):

// Get $scope variables to control time picker range
var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
var startTime = '[' + startHour + ',' + startMinute + ']';
var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];
var endTime = '[' + endHour + ',' + endMinute + ']';
$scope.timeRange = {
    min: startTime,
    max: endTime
};

HTML:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time timeOptions="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

更新 - Picker Working ...但现在表单没有提交时间数据按照此帖子:TimePicker directive won't submit time (undefined) **

非常感谢@ dave-alperovich和@ joe-enzminger的不懈帮助和出色的答案。

控制器:

// Get $scope variables to control time picker range
var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];
$scope.timeRange = {
min: [startHour,startMinute],
max: [endHour,endMinute]
};

指令:

appDirectives.directive('pickATime', function() {
return {
    // Restrict it to be an attribute in this case
    restrict: 'A',
    // responsible for registering DOM listeners as well as updating the DOM
    link: function(scope, element, attrs) {
        element.pickatime(scope.options());
    },
    scope: {
        options: '&pickATime'
    },
};
});

用法:

<input ng-if="timeRange" type="text" placeholder="Start Time" id="timestart" pick-a-time="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

2 个答案:

答案 0 :(得分:3)

将数据从父作用域传递到指令有许多不同的方法。您已经(正确地)选择了孤立范围提供的选择类别,如

所示
scope: {
}

指令的参数。这意味着您的指令范围不会原型继承父作用域。

您的第一个示例不起作用的原因是行:

element.pickatime(scope.$eval(attrs.pickATime));

最终将undefined传递给element.pickatime()方法。

这是因为这行代码的作用是尝试根据指令的范围来评估DOM中的pick-a-time html属性值中包含的表达式(这是一个字符串)。第一个示例中,pick-a-time属性的值为空字符串。

当您使用“非动态”版本时,pick-a-time属性的值现在是字符串

"{min: [0,0], max: [23,30]}"

哪个是有效的角度表达式,$ eval将返回一个对象,其最小和最大属性分别设置为[0,0]和[23,30],因此您的指令有效。

在这两种情况下,您的指令都会完全忽略使用options属性传递给指令的值。

一个简单的解决方法是修改您的指令以使用通过options属性传入的信息。编写指令的方式,此对象将与$ scope.timeOptions值双向绑定(稍后将详细介绍)。实质上,对$ scope.timeOptions的任何更改都将显示在父作用域的timeRange属性中,反之亦然。

对指令的更改将是:

element.pickatime(scope.timeOptions);

额外信用:

在上一个示例中,您声明指令中未定义timeOptions。这是因为html需要是:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time time-options="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

唯一的变化是timeOptions - &gt;时间的选项

这是角度按惯例处理属性到范围属性映射的方式。

额外额外信用:

您的示例不需要双向绑定(我认为您不想更改指令中的选项)。您可以使用&amp ;;避免创建两个$ watch。而不是=。这将是我的指令的最终版本:

appDirectives.directive('pickATime', function() {
    return {
        // Restrict it to be an attribute in this case
        restrict: 'A',
        // responsible for registering DOM listeners as well as updating the DOM
        link: function(scope, element, attrs) {
            element.pickatime(scope.options());
        },
        scope: {
            options: '&pickATime'
        },
        templateUrl: '../Templates/timeoptions.html'
    };
});

用法:

点符号问题的更新:

在您的控制器中,您需要对itemtimestart使用点表示法:

.controller('xxx', function($scope){
    $scope.parameters = {
    }
}

<input ng-if="timeRange" type="text" placeholder="Start Time" id="timestart" pick-a-time="timeRange" data-ng-model="parameters.itemtimestart" class="form-control" autocomplete="off">

$scope.paramters.itemtimestart should now be the correct time.

您还可以使用“controller as”语法来简化此操作。

Here is a Plunk

答案 1 :(得分:0)

如果选项已经存在(在timeRange中)且不会随时间变化,则无需执行任何操作:它应位于scope.timeOptions(链接和控制器中)。

但是,如果选项可以随时更改,并且您希望在合并时刷新,则需要注意其更改:

scope.$watch('timeOptions', function(newOptions) {
  // do something with the newOptions
});