角度指令绑定到范围对象的哈希值

时间:2014-03-22 19:30:17

标签: angularjs angularjs-directive

我正在尝试创建一个允许我绑定到其他范围属性的哈希的指令。

HTML

<div lookup lookup-model="data.countryId"></div>
<div lookup lookup-model="data.stateId" lookup-params="{countryId: data.countryId}"></div>

我希望能够每次更新lookup-params中的值以使用data.stateId模型刷新查找。我试图保持这种通用性,因为我可能会有各种不同的查找参数。

有没有办法在Angular中执行此操作?


更新

我当然没有提供足够的细节。点击过早提交。这是我的解决方案,基于@Olivvv的反馈。该建议引导我进入scope.$eval功能。

这里的目标是创建一个指令,允许我们使用带有$http的select来选择select中的选项。一些$http请求将需要一个参数,因为它们是对另一个值的依赖。例如,只有在提供国家/地区值时才能提供一组状态。

以下是我汇总的代码。我确信它可以改进,但它现在正在做的伎俩。请注意,我正在使用Lodash实现一些实用功能。您还将看到范围对象“lookupModelObject”。这纯粹是为了满足造型选择的设计需求。如果您只对lookupParams感兴趣,可能会被忽略。

HTML代码段

<div select-lookup lookup-value="block.data.countryId" lookup-type="countries" lookup-placeholder="Select a Country"></div>
<div select-lookup lookup-value="block.data.stateId" lookup-type="states" lookup-params="{countryId: block.data.countryId}" lookup-placeholder="Select a State"></div>

指令

要指出的重要部分是我如何评估attrs.lookupParams。如果属性存在,我使用scope.$eval来评估属性。稍后您将看到我如何将每个参数添加到范围中,并在其中一个参数更改时添加了一个观察程序。如果选择了其他国家/地区,这将允许我将“state”重置为null。

angular.module("foo").directive('selectLookup', ['$http', '$q', function($http, $q) {

    return {
        restrict: 'A',
        replace: true,
        templateUrl: 'common/lookups/partials/selectLookupPartial.html',
        scope: {
            id: "@",
            lookupValue: "=",
            lookupParams: "="
        },
        link: function(scope, element, attrs) {
            // Initialize the options.
            scope.options = [];

            var optionsLoaded = false;

            var resetLookupModel = function() {
                scope.lookupModelObject = {
                    id: null,
                    text: attrs.lookupPlaceholder
                };
            };

            // Evaluate and obtain the lookup parameters for this lookup.
            var lookupParams = {};
            if (attrs.lookupParams) {
                lookupParams = scope.$eval(attrs.lookupParams);
            }

            var updateLookupModelObject = function(value) {

                // This function is only relevant if the options have been loaded.
                if (optionsLoaded) {
                    if (value === undefined || value === null) {
                        resetLookupModel();
                    }
                    else {
                        var item = _.findWhere(scope.options, {id: value});

                        if (item) {
                            scope.lookupModelObject = item;
                        }
                        else {
                            resetLookupModel();
                        }
                    }
                }

            };

            var fetchValues = _.throttle(function() {

                var deferred = $q.defer(),
                    fetchUrl = "/api/lookup/" + attrs.lookupType,
                    keys = _.keys(lookupParams);

                _.each(keys, function(key, index) {
                    if (index === 0) {
                        fetchUrl += "?";
                    }
                    else {
                        fetchUrl += "&";
                    }

                    fetchUrl += key + "=" + lookupParams[key];
                });

                // Empty the options.
                scope.options.splice(0, scope.options.length);

                $http.get(fetchUrl).then(function(response) {
                    scope.options = response.data;
                    optionsLoaded = true;
                    updateLookupModelObject(scope.lookupValue);
                    deferred.resolve(scope.options);
                });

                return deferred.promise;

            }, 150);

            // Setup the watchers
            // If there are lookup params add them to scope so we can watch them.
            var keys = _.keys(lookupParams);

            _.each(keys, function(key) {
                scope[key] = lookupParams[key];

                // Setup watchers for each param.
                scope.$watch(key, function() {
                    fetchValues();
                });
            });

            scope.$watch('lookupParams', function(newValue, oldValue) {
                if (!_.isEqual(newValue, oldValue)) {
                    lookupParams = newValue;
                    fetchValues().then(resetLookupModel);
                }
            });

            scope.$watch('lookupValue', updateLookupModelObject);

            scope.$watch('lookupModelObject', function(newValue, oldValue) {
                if (!_.isEqual(newValue, oldValue)) {
                    scope.lookupValue = newValue.id;
                }
            });

            fetchValues();
        }
    };
}]);

模板

我们有一个设计约束,迫使我们引入一个“选择占位符”。除此之外,select是在Angular中设置选择的“典型”方式。

<div class="container select-container">
    <div class="select-placeholder">
        <span class="select-placeholder-text">{{ lookupModelObject.text }}</span>
        <select class="select-input" data-ng-model="lookupModelObject" id="{{ id }}" data-ng-options="option as option.text for option in options"></select>
    </div>
</div>

1 个答案:

答案 0 :(得分:0)

我在&#34; utils&#34;中使用以下函数解决了它。服务:

function  utils    ($parse) {
    this.$params = function(attrs, attrName, allowedParams){
        var out = {},
        parsed = $parse(attrs[attrName])();
        if (typeof parsed === 'object'){
            angular.forEach(parsed, function(val, key){
                if (allowedParams.indexOf(key) !== -1){
                    this[key] = val;
                } else {
                    //do some logging. i.e ('parameter not recognized :', key, ' list of the allowed params:', allowedParams)
                }
            }, out);
        }else{
            out[allowedParams[0]] = attrs[attrName];
        }
        return out;
    };
}

在模板中使用它:

lookup-params="{countryId: '{{data.countryId}}'}"

并在你的指令中:

var lookupParams = utils.$params(attrs, 'lookup-params', ['countryId','anotherParams', 'etcetera']);

第一个允许的参数可以直接作为字符串而不是对象传递:

lookup-params="{'{{data.countryId}}'}"

将起作用