Как хранить и извлекать параметры поиска в angularjs?

У меня есть приложение Angular, в котором я иногда хочу:

  • Сохраните текущие введенные переменные формы для отображаемой в данный момент страницы. Это могут быть условия поиска или другой пользовательский ввод.
  • Если пользователь возвращается в историю, убедитесь, что снова используются те же параметры поиска.

Я просмотрел историю ngRoute, stateProvider и html и не нашел хорошего способа сделать это. Это похоже на то, что должно быть довольно распространенным явлением, поэтому я просто не понял, как это сделать.


person Markus Johansson    schedule 22.01.2015    source источник
comment
Когда вы говорите параметры поиска, вы имеете в виду поисковую часть URL-адреса? Например, в URL-адресе: example.com/page?search=set+of+terms. Я говорю о части ?search=set+of+terms.   -  person David    schedule 22.01.2015
comment
используйте такой модуль, как Angular-Local-Storage (github.com/grevory/angular-local-storage) для хранения ваших переменных в локальном хранилище клиента (или сеансе, или файлах cookie). прочитайте значения обратно, если они существуют, и назначьте свои переменные. Однако есть много вещей, которые следует учитывать; в частности, когда сохранять и когда обновлять хранилище.   -  person Claies    schedule 22.01.2015
comment
Дэвид: Я пытался уточнить в тексте. Параметры поиска или переменные формы не должны заканчиваться в URL-адресе.   -  person Markus Johansson    schedule 22.01.2015
comment
Воспользуйтесь услугой. Это синглтоны, указывающие на один и тот же объект/ссылку на протяжении всего времени существования приложения AngularJS. Кроме того, вы можете сохранить эти данные с помощью файлов cookie или локального хранилища.   -  person Sergiu Paraschiv    schedule 22.01.2015
comment
Я не хочу, чтобы данные сохранялись, поэтому, если пользователь вернется на ту же страницу, не возвращаясь в историю, будут показаны старые данные. В этом случае поля формы должны быть в состоянии по умолчанию.   -  person Markus Johansson    schedule 22.01.2015
comment
Затем вы подключаетесь к API истории HTML5 и сами обрабатываете этот случай. Никак иначе на самом деле.   -  person Sergiu Paraschiv    schedule 22.01.2015
comment
Как мне подключить это и заставить его вращаться с угловым? В настоящее время я использую ngRoute для обработки разных представлений.   -  person Markus Johansson    schedule 22.01.2015
comment
возможно, это то, что вы ищете github.com/decipherinc/angular-history   -  person micha    schedule 22.01.2015


Ответы (4)


Основываясь на том, что вы описываете, я вижу несколько способов, как это можно сделать.

Существует LocalStorage, который представляет собой поддерживается в большинстве браузеров, и даже в этом случае есть полифиллы для этого. Это будет означать, что вы сохраняете с использованием пары имя/значение.

Вот краткий пример:

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. Это позволит вам легко поддерживать историю и позволит легко использовать кнопку «Назад». В конце концов, все действительно сводится к тому, как настроено ваше приложение, что является лучшим выбором. Есть и другие способы, которыми это может быть достигнуто в зависимости от требований. Например, если вам нужно синхронизировать между устройствами, необходимо реализовать серверный компонент для хранения значений и их извлечения.

person David    schedule 22.01.2015

Чтобы справиться с этим в нашем текущем проекте, мы объявили директиву, которая следит за моделью и привязывает это значение к переменной в службе данных. Кроме того, при рендеринге эта директива проверяет, установлено ли уже соответствующее значение в службе данных. Если это так, модель устанавливается на это значение.

Как просили в комментариях, мой 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
    };
}

);

person DonJuwe    schedule 22.01.2015
comment
Прохладный. Но очищаете ли вы когда-нибудь значение в службе данных? Допустим, пользователь нажимает «Добавить клиента», заполняет половину, а затем решает не продолжать и нажимает в другом месте. Если он затем вернется к той же форме, не используя навигацию по истории, как предотвратить заполнение старых значений? - person Markus Johansson; 23.01.2015
comment
Данные очищаются при перезагрузке, так как вы не записываете их в локальные сотраги, куки и т.д. Если пользователь вернётся на страницу с ранее заполненной формой, директива проверяет, есть ли у модели какие-то данные в сервисе и устанавливает значение модели. - person DonJuwe; 23.01.2015
comment
Понятно, так что отмененное создание клиента будет задерживаться в приложении до перезагрузки? В моем случае я бы предпочел, чтобы эти данные присутствовали только в навигации по истории. Есть идеи, как это можно реализовать? - person Markus Johansson; 23.01.2015
comment
Что ж, данные хранятся в сервисе только для всего сайта. Если вы хотите сохранить его в действиях браузера, таких как кнопка обновления или возврата в историю, я предлагаю написать службу, которая записывает его в локальное хранилище браузера. Дайте мне знать, если вам нужен код для хорошего localStorageService. - person DonJuwe; 23.01.2015
comment
Похоже, это может быть действительно полезно. Если вы хотите поделиться им, мне интересно. - person Markus Johansson; 23.01.2015

В прошлом я сохранял состояние просмотра, имея службу, которая хранила его в объекте.

Любая ссылка на поле, которое я хотел сохранить (например, столбец сортировки таблицы или значение определенного поля), будет сохранена в объекте состояния представления службы, а не в контроллере/области.

Контроллер будет проверять «источник» или «тип» передачи страницы при ее инициализации путем поиска определенного параметра или состояния 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.
});

как отслеживать изменение маршрута в angularjs

person JGefroh    schedule 22.01.2015
comment
Звучит интересно. Этот ответ соответствует тому, что я ищу. Я думаю о том, как узнать, КОГДА что-то хранить. Если пользователь ввел много значений, а затем щелкнул ссылку в приложении, я хочу, чтобы эти значения были сохранены. В таком случае я как-нибудь зацеплюсь за навигацию. - person Markus Johansson; 23.01.2015
comment
Я отредактировал ответ с дополнительной информацией. Если вы привязываетесь непосредственно к службе, вам не нужно делать ничего особенного, чтобы знать, когда сохранять — вы будете сохранять непосредственно в службу, а не в область. - person JGefroh; 23.01.2015

Существует несколько методов, и два из них показались вполне надежными. В итоге я выбрал первый подход для своего приложения, так как мои параметры поиска должны были распространяться на другие контроллеры.

Сохранение их в файлах cookie

Angular.js предлагает $cookies, что позволяет получать/устанавливать параметры на браузер. Я использую это как настоящий источник параметров поиска.

Например:

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 при перемещении между состояниями.

person tsuz    schedule 23.12.2016