Watch/Update AngularJS 中的一组输入的正确方法

Proper way to Watch/Update a group of inputs in AngularJS

在使用 JQuery 多年后,我目前正在学习 AngularJS。现在,我正在考虑实现智能表 (http://lorenzofox3.github.io/smart-table-website/),并希望能够自动将搜索查询保存到 cookie 中,以便我可以在用户 return 时重新加载它们。理想情况下,我希望有一种通用的方法来执行此操作,以便我可以通过使用单个指令或 DI 来重新使用代码。

在JQuery的世界里,我会这样做:

HTML:由 st-search 定义的单个搜索条目,但我们可以有 n-这些都具有唯一 ID 的数量。

<tr>
    <th><input st-search="id" class="form-control" placeholder="Search by ID" type="number"/></th>
</tr>

"onChange" Javascript:监听所有字段更新,这样我就可以调用我的存储服务(可能是 cookie),而不是发出警报为此 table.

保存更新的搜索参数
$('input[st-search]').on('change', function(event){
    var target = $(event.target);
    alert(target.attr('st-search')+'='+target.val());
});

初始化Javascript:这将获取 cookieData 并将其应用于所有匹配的搜索字段。

$.each(cookieData, function(index, row) {
    $('input[st-search="'+row.stSearch+'"]').val(row.value);
});

现在,我对 Angular 的方法是什么感到困惑。我正在尝试按照建议尝试在 Angular 中执行 "everything" 而没有 JQuery ("Thinking in AngularJS" if I have a jQuery background?),但我不确定如何最好地解决这个问题。您可以使用 $scope.$watch 来根据 CSS 选择器一般地监视很多元素吗(我只能找到针对特定模型执行此操作的示例)?最好在每个输入或父 元素上使用装饰器来完成吗?我真的不知道从这里去哪里!

好吧,这不是一个很好的解决方案,但它确实通过将 Angular 与 jQuery 组合来满足我的需要!我决定在包含搜索字段的 tr 标签上使用 attribute/directive (st-search-cookie)。例如:

<tr st-search-cookie>
    <th><input st-search="id" class="form-control" placeholder="Search by ID" type="number"/></th>
</tr>

您可以选择在指令中定义 cookie-namecollection-name。否则,它使用所有可用搜索字段的 md5 散列作为集合名称。这个想法是你有一个单一的 cookie,它可以有许多不同的 table 的集合,而不是有很多 cookie(即每个 table 都有一个)。

无论如何,这会自动找到默认的 st-search 输入框 (input[st-search]) 以及任何带有*predicate' 属性 (input[predicate]),在制作自定义搜索指令时常用。

希望其他人会发现它有用,或者更好地改进它!

(function(angular) {
    angular.module("stSearchCookie", ['ngCookies', 'angular-md5']).directive('stSearchCookie', function ($cookies, md5, $log) {
        return {
            restrict: 'A',
            scope: {
                'cookieName': '@',
                'collectionName': '@'
            },
            transclude: false,
            link: {
                post: function (scope, elem, attrs, controller) {
                    // Set Defaults for scope
                    if (angular.isUndefined(scope.cookieName)) {
                        scope.cookieName = 'stSearchParams';
                        $log.log('cookie-name not defined so defaulting to "' + scope.cookieName + '"');
                    }
                    if (angular.isUndefined(scope.collectionName)) {
                        var fields = 'fieldNames=';
                        $.each(elem.find('input[st-search]'), function(i, e) {
                            fields = fields + $(e).attr('st-search') + ';';
                        });
                        $.each(elem.find('input[predicate]'), function (i, e) {
                            fields = fields + $(e).attr('predicate') + ';';
                        });
                        scope.collectionName = md5.createHash(fields);
                        $log.log('collection-name not defined so defaulting to "' + scope.collectionName + '"');
                    }

                    // Set defaults in cookie
                    var defaults = {};
                    $.each(elem.find('input[st-search]'), function(i, e) {
                        defaults[$(e).attr('st-search')] = '';
                    });
                    $.each(elem.find('input[predicate]'), function (i, e) {
                        defaults[$(e).attr('predicate')] = '';
                    });
                    var cookieData = $cookies.getObject(scope.cookieName);
                    if (angular.isObject(cookieData)) {
                        if (cookieData.hasOwnProperty(scope.collectionName))
                            cookieData[scope.collectionName] = angular.extend(defaults, cookieData[scope.collectionName]);
                        else
                            cookieData[scope.collectionName] = defaults;
                    } else {
                        cookieData = {};
                        cookieData[scope.collectionName] = defaults;
                    }
                    $cookies.putObject(scope.cookieName, cookieData);

                    // Populate from cookie
                    $.each(Object.keys(cookieData[scope.collectionName]), function (index, key) {
                        $('input[st-search="' + key + '"]').val(cookieData[scope.collectionName][key]).trigger('change').trigger('blur');
                    });
                    $.each(Object.keys(cookieData[scope.collectionName]), function (index, key) {
                        $('input[predicate="' + key + '"]').val(cookieData[scope.collectionName][key]).trigger('change').trigger('blur');
                    });

                    // Add events to update cookie on changes
                    elem.find('input[st-search]').on('change blur', function(event) {
                        var target = $(event.target);
                        var cookieData = $cookies.getObject(scope.cookieName);
                        cookieData[scope.collectionName][target.attr('st-search')] = target.val();
                        $cookies.putObject(scope.cookieName, cookieData);
                    });
                    elem.find('input[predicate]').on('change blur', function (event) {
                        var target = $(event.target);
                        var cookieData = $cookies.getObject(scope.cookieName);
                        cookieData[scope.collectionName][target.attr('predicate')] = target.val();
                        $cookies.putObject(scope.cookieName, cookieData);
                    });
                }
            }
        };
    });
})(angular);