在替换模板之前,请先阅读AngularJS中的原始标记

时间:2013-08-28 19:36:34

标签: angularjs angularjs-directive

我正在创建一个花哨的滑块,允许用户选择范围内的值,我正在尝试将其构建为AngularJS指令。范围中的每个步骤都有一个简短的文本描述,显示在该位置。例如:

 Temperature
                  Warm
[------------------^------]
 |     |     |     |     |
 Cold                  Hot

我想在页面上使用这个初始标记,因为它是语义的并且优雅地降级:

<div class="prompt scale">
    <label for="mySelect">Temperature</label>
    <select name="mySelect">
        <option value="1">Cold</option>
        <option value="2">Cool</option>
        <option value="3">Neutral</option>
        <option value="4">Warm</option>
        <option value="5">Hot</option>
    </select>
</div>

然后我会用花式滑块的标记完全替换它。但是,这样做需要Angular能够读取原始标记,以便提取渲染花式滑块所需的数据(每个选项的值和标签)。但是,我找不到任何可以引用原始元素及其子元素的地方。声明该指令时,compile()和link()函数都引用模板元素,而不是原始元素。如何阅读原始标记,包括访问其后代?

1 个答案:

答案 0 :(得分:2)

如果您打算在指令配置对象上使用模板属性,我猜您将失去查看原始属性的能力。

我认为要有效地做你正在做的事情,你需要使用我不熟悉的编译指令功能。我没有用它来告诉你这个:

http://jsfiddle.net/2TPWA/

基本上为每个重要数据创建指令。让他们共享一个控制器来注册所有这些数据。通过这种方式,父指令可以使其子节点不一定是指定的深度。隐藏(或删除,如果您愿意)原始标记,然后根据合并信息创建窗口小部件。

在你的情况下,我会像你在这里看到的那样连接所有内容的指令和另一个指针,它本身就是小部件,可以用可能的属性或配置对象创建,就像另一个回答者建议的那样。 / p>

<div>
<div sliding-scale class="prompt scale">
<label sliding-scale-title for="mySelect">Temperature</label>
<select name="mySelect">
    <option sliding-scale-option value="1">Cold</option>
    <option sliding-scale-option value="2">Cool</option>
    <option sliding-scale-option value="3">Neutral</option>
    <option sliding-scale-option value="4">Warm</option>
    <option sliding-scale-option value="5">Hot</option>
</select>
</div>
</div>



var myApp = angular.module('myApp', []);

myApp.directive('slidingScaleTitle', function () {
    return {
        require: '^slidingScale',
        link: function (scope, element, attrs, controller) {
            controller.setTitle(element.text());
        }
    };
});

myApp.directive('slidingScaleOption', function () {
    return {
        require: '^slidingScale',
        link: function (scope, element, attrs, controller) {
            controller.addOption({ 
                value: attrs.value,
                text: element.text()
            });
        }
    };
});

myApp.directive('slidingScale', function ($compile) {
    var template = '<div><b>{{ title }}</b><ul><li ng-repeat="o in options"><b>{{ o.value }}:</b> {{ o.text }} </li></ul>';

    return {
        // You should make this its own controller if you want this unit-tested.
        // I'm inlining it as an example.
        controller: function ($scope) {
            var title;
            var options = [];

            this.setTitle = function (value) {
                title = value;
            };
            this.getTitle = function () {
                return title;
            };
            this.getOptions = function () {
                return options;
            }
            this.addOption = function (value) {
                options.push(value);
            };
        },
        link: function (scope, element, attrs, controller) {

            scope.$watch(controller.getTitle, function (value) {
                scope.title = value;
            });

            scope.$watch(controller.getOptions, function (value) {
                scope.options = value;
            });

            element.children().css('display', 'none');
            fancySliderElement = angular.element(template);
            element.append(fancySliderElement);
            $compile(fancySliderElement)(scope);
        }
    }
});