【问题标题】:Angular Directive With Binding to Hash of Scope Objects绑定到范围对象散列的 Angular 指令
【发布时间】:2014-03-22 19:30:16
【问题描述】:

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

HTML

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

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

有没有办法在 Angular 中做到这一点?


更新

我当然没有提供足够的细节。点击提交太快了。这是我基于@Olivvv 反馈的解决方案。该建议将我引向scope.$eval 函数。

这里的目标是创建一个指令,允许我们使用带有$http get 的选择来为选择中的选项播种。一些$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 来评估该属性。稍后您将看到我如何将每个参数添加到范围,并添加一个观察者以防其中一个参数发生更改。如果选择了不同的国家,这将允许我将“状态”重置为 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();
        }
    };
}]);

模板

我们的设计约束迫使我们引入“选择占位符”。除此之外,选择是在 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>

【问题讨论】:

  • 更多关于图片其余部分的细节会有所帮助。
  • 是的,只是不完全清楚目标是什么......我想你可能想要像lookupModel[lookupParams]这样的东西,其中lookupParams绑定到一个字符串,这样你就可以获得模型的特定属性,但可以根据目前的情况,不能肯定地说。您能否介绍一下您的指令定义或展示一个 plunkr 或 jsfiddle 示例?

标签: angularjs angularjs-directive


【解决方案1】:

我在“utils”服务中使用以下函数解决了这个问题:

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}}'}"

会起作用

【讨论】:

  • 这对我有用。 $parse 是解决我的问题的关键。
猜你喜欢
  • 1970-01-01
  • 2015-05-14
  • 1970-01-01
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-14
相关资源
最近更新 更多