【问题标题】:How to store and retrieve search parameters in angularjs?如何在angularjs中存储和检索搜索参数?
【发布时间】:2015-01-22 15:02:50
【问题描述】:

我有一个 Angular 应用程序,有时我想:

  • 为当前显示的页面存储当前输入的表单变量。这可以是搜索词或其他用户输入。
  • 如果用户返回历史记录,请确保再次使用相同的搜索参数

我查看了 ngRoute、stateProvider 和 html 历史记录,但没有找到一个好方法。它看起来应该是相当普遍的东西,所以我想我只是不明白如何去做。

【问题讨论】:

  • 当您说搜索参数时,您指的是 URL 的搜索部分吗?例如,在网址中:example.com/page?search=set+of+terms 我说的是?search=set+of+terms 部分。
  • 使用 Angular-Local-Storage (github.com/grevory/angular-local-storage) 之类的模块将变量存储到客户端的本地存储(或会话或 cookie)。如果它们存在,则将它们读回并分配您的变量。然而,有很多事情需要考虑;尤其是何时保存以及何时更新存储。
  • 大卫:我试图在文中澄清。搜索参数或表单变量不必以 url 结尾。
  • 使用服务。这些是单例,在 AngularJS 应用程序的整个生命周期中都指向同一个对象/引用。此外,您可以使用 cookie 或本地存储来保存这些数据。
  • 我不希望数据被持久化,这样如果用户返回同一页面而不返回历史记录,则会显示旧数据。在这种情况下,表单字段应该处于默认状态。

标签: javascript angularjs angular-ui-router browser-history html5-history


【解决方案1】:

根据您的描述,我看到了一些可以做到这一点的方法。

在大多数浏览器中都有LocalStorage,即supported,即使如此,也有polyfills。这意味着您使用名称/值对进行存储。

这是一个简单的例子:

var searchParameters = {
  filters: [
    'recent'
  ],
  searchString: 'bacon'
}

// Store the value(s)
localStorage.setItem('searchParameters', JSON.stringify(searchParameters));

// Retrieve the value(s)
searchParameters = JSON.parse(localStorage.getItem('searchParameters'));

// Delete the value(s)
localStorage.removeItem('searchParameters');

根据您的流程,您可以使用浏览器历史堆栈。因此,如果有人搜索bacon,那么您可以将他们发送到附加了?query=bacon 的页面。这将允许您轻松维护历史记录并允许轻松使用后退按钮。归根结底,这一切都归结为您的应用程序是如何设置的,什么是最佳选择。根据要求,还有其他方法可以实现这一点。例如,如果您需要跨设备同步,则需要实现服务器端组件来存储和检索值。

【讨论】:

    【解决方案2】:

    为了在我们当前的项目中处理这个问题,我们声明了一个指令来监视模型并将这个值绑定到数据服务中的一个变量。此外,在渲染时,该指令会检查数据服务中是否已经设置了适当的值。如果是这样,则模型正在设置为此值。

    根据 cmets 的要求,我的 StorageService:

    'use strict';
    
    /**
     * storage wrapper for session- or local-storage operations
     */
    app.factory('StorageService', function(
            $rootScope,
            $http,
            $location) {
    
        /**
         * get an item
         *
         * @param item - string - the item identifier
         * @return - mixed -
         */
        var get = function(item) {
            return JSON.parse(sessionStorage.getItem(item) ||localStorage.getItem(item));
        };
    
        /**
         * set an item
         *
         * @param item - string - the item identifier
         * @param value - mixed - the value to set
         * @param usePersistentStorage - boolean - the flag for session- or local-storage
         * @return void
         */
        var set = function(item, value, usePersistentStorage) {
            var obj = {
                value: value,
                ts: new Date().getTime()
            };
            window[usePersistentStorage ? 'localStorage' : 'sessionStorage'][value === null ? 'removeItem' : 'setItem'](item, JSON.stringify(obj));
        };
    
        /**
         * remove an item
         *
         * @param item - string - the item identifier
         * @return void
         */
        var remove = function(item) {
            set(item, null, true);
            set(item, null);
        };
    
        /**
         * clear the whole session- and local-storage
         *
         * @return void
         */
        var clear = function() {
            sessionStorage.clear();
            localStorage.clear();
        };
    
        /**
         * check if item has expired
         *
         * @return boolean
         */
        var checkExpiration = function(str, minutes) {
            var now = new Date(),
                nowts = now.getTime(),
                item = get(str);
            if(item && typeof item.ts != 'undefined' && (new Date(nowts) - new Date(item.ts) < minutes * 60 * 1000)) {
                return true;
            } else {
                remove(str);
                return false;
            }
        };
    
        return {
            get: get,
            set: set,
            remove: remove,
            clear: clear,
            checkExpiration: checkExpiration
        };
    }
    

    );

    【讨论】:

    • 酷。但是您是否清楚数据服务的价值?假设用户点击“添加客户”,填写了一半,然后决定不继续并点击其他地方。如果他然后回到同一个表单,而不使用历史导航,你如何防止旧值被填写?
    • 数据在重新加载时被清除,因为您没有将它们写入本地存储、cookie 等...模型在服务中有一些数据,并设置模型值。
    • 我明白了,所以取消的客户创建会在应用程序中徘徊,直到重新加载?就我而言,我认为如果该数据仅存在于历史导航中,我会更喜欢。有什么想法可以实现吗?
    • 好吧,数据仅在站点范围内保存在服务中。如果您想将其保留在刷新或历史记录返回按钮等浏览器操作上,我建议编写一个服务,将其写入浏览器本地存储。如果您需要一个不错的 localStorageService 的代码,请告诉我。
    • 听起来真的很有帮助。如果你愿意分享,我很感兴趣。
    【解决方案3】:

    我过去曾通过将视图状态保存在对象中的服务来保存它。

    对我想要维护的字段的任何引用(例如表的排序列或特定字段的值)都将保存在服务的视图状态对象中,而不是控制器/范围中。

    控制器会在初始化时通过查找特定的 url 参数或状态(例如 #/search?type=new)来检查页面传输的“来源”或“类型”。如果它被认为是新的搜索,它将重置这些值。否则它将显示并使用以前使用的值。

    应用程序重新加载会清除服务中的数据,从而提供全新的形式。


    我上面描述的方法很简单,因为 Angular 会为您处理保存。服务是单例的,因此通过直接绑定到服务的字段,它会自动在路由更改后继续存在。

    在你看来:

    <input ng-model="criteria.firstName">    
    

    在你的控制器初始化中:

    $scope.criteria = ViewStateService.criteria;
    

    如果您希望仅在特定点保存视图状态,您可以在页面更改/路由更改事件上设置事件处理程序并在该点复制数据。

    $scope.$on('$locationChangeStart', function(next, current) {
        //code to copy/save fields you want to the Service.
    });
    

    how to watch for a route change in angularjs

    【讨论】:

    • 听起来很有趣。这个答案符合我正在寻找的内容。我在想的是如何知道何时存储东西。如果用户输入了很多值,然后单击应用程序中的链接,我希望保留这些值。在那种情况下,我以某种方式连接到导航。
    • 我已经用更多信息编辑了答案。如果您直接绑定到服务,则无需执行任何特定操作即可知道何时保存 - 您将直接保存到服务而不是范围。
    【解决方案4】:

    有几种方法,其中两种似乎相当可靠。我最终为我的应用选择了第一种方法,因为我的搜索参数需要传播到其他控制器。

    将它们存储在 cookie 中

    Angular.js 提供$cookies 允许在浏览器上获取/设置参数。我将其用作搜索参数的 true 来源。

    例如:

    search.service.js

    angular
        .module('app')
        .service('SearchService', SearchService);
    
    
        SearchService.$inject = [
            '$cookies'
        ];
    
        function SearchService(
            $cookies
        ) {
    
        var searchCookieKey = 'searchHistoryCookieKey';
        var searchCookieMaxSize = 10;
    
        return {
            search: search,
            getSearchHistory: getSearchHistory
        };
    
        function search(arg1, arg2) {
            storeSearchHistory({arg1: arg1, arg2: arg2});
    
            // do your search here
            // also, you should cache your search so 
            // when you use the 'most recent' params
            // then it won't create another network request 
        }
    
        // Store search params in cookies
        function storeSearchHistory(params) {
            var history = getSearchHistory();
            history.unshift(params); // first one is most recent
            if(history.length > searchCookieMaxSize) {
                history.pop();
            }
            $cookies.putObject(searchCookieKey, history);
        }
    
        // Get recent history from cookies
        function getSearchHistory() {
            return $cookies.getObject(searchCookieKey) || [];
        }
    
    }
    

    app.states.js

       .state('search', {
            url: "/search",
            templateUrl: "/dashboard/search/templates/index.html",
            controller: 'SearchController',
            resolve: {
                searchResults: ['SearchService', '$stateParams', function(SearchService, $stateParams) {
                    if(!$stateParams.arg1 || !$stateParams.arg2) {
                        var history = SearchService.getSearchHistory();
                        var mostRecent = history.length ? history[0] : null;
                        if(mostRecent) {
                            return SearchService.search(mostRecent.arg1, mostRecent.arg2);
                        }
                    }
                    return SearchService.search($stateParams.arg1, $stateParams.arg2);
                }]
            }
        })
    

    如果您没有缓存这些搜索网络调用,那么您的应用将需要等待请求返回,从而降低您的应用速度。

    在各州传递它们

    您可以创建一个包含$stateParams 的父控制器,您的子控制器将继承这些参数。后退/前进或在子状态之间访问时不会覆盖参数。但是,当您使用特定参数移动状态时,它们会被覆盖。因此,您只需要在状态之间移动时明确指定这些父级的$stateParams

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-25
      • 2020-07-23
      • 2010-10-31
      相关资源
      最近更新 更多