Tips for managing and accessing search criteria in angularjs

In my Angular application, there are times when I need to:

  • Save the form variables that have been entered for the current page. This could be search terms or any other user input.
  • Ensure that if the user navigates back in their history, the same search parameters are utilized again.

After exploring ngRoute, stateProvider, and html history, I haven't found a satisfactory solution for achieving this functionality. It seems like something that should be a common requirement, so perhaps I'm missing the proper approach.

Answer №1

From the details you've provided, I can suggest a few approaches to tackle this situation.

You could explore using LocalStorage, which is widely supported in most browsers. Alternatively, there are polyfills available if needed. This method involves storing data as name/value pairs.

For instance, consider this basic example:

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

// Save the data
localStorage.setItem('searchParams', JSON.stringify(searchParams));

// Retrieve the data
searchParams = JSON.parse(localStorage.getItem('searchParams'));

// Remove the data
localStorage.removeItem('searchParams');

Depending on your application flow, utilizing the browser history stack could be beneficial. For example, after a search for bacon, redirecting users with ?query=bacon appended to the URL can help manage history and simplify navigation using the back button. Ultimately, the best approach depends on how your app is structured. There are also other methods to achieve this based on specific requirements - such as implementing a server-side component for cross-device synchronization of data.

Answer №2

In order to address this issue within our current project, we implemented a directive that monitors the model and binds its value to a variable in a data service. Additionally, upon rendering, the directive verifies if the correct value is already stored in the data service. If it is, the model is then updated with this value.

Addressing the comments, here is an overview of my DataStorageService:

'use strict';

/**
 * Utility for managing session or local storage operations
 */
app.factory('DataStorageService', function(
        $rootScope,
        $http,
        $location) {

    /**
     * Retrieve an item from storage
     *
     * @param item - string - identifier of the item
     * @return - mixed -
     */
    var retrieve = function(item) {
        return JSON.parse(sessionStorage.getItem(item) || localStorage.getItem(item));
    };

    /**
     * Store an item in storage
     *
     * @param item - string - identifier of the item
     * @param value - mixed - value to be saved
     * @param persistent - boolean flag for session or local storage
     * @return void
     */
    var save = function(item, value, persistent) {
        var obj = {
            value: value,
            ts: new Date().getTime()
        };
        window[persistent ? 'localStorage' : 'sessionStorage'][value === null ? 'removeItem' : 'setItem'](item, JSON.stringify(obj));
    };

    /**
     * Remove an item from storage
     *
     * @param item - string - identifier of the item
     * @return void
     */
    var erase = function(item) {
        save(item, null, true);
        save(item, null);
    };

    /**
     * Clear all session and local storage
     *
     * @return void
     */
    var clearAll = function() {
        sessionStorage.clear();
        localStorage.clear();
    };

    /**
     * Check if an item has expired
     *
     * @return boolean
     */
    var checkExpiry = function(str, minutes) {
        var currentTime = new Date(),
            currentTimestamp = currentTime.getTime(),
            storedItem = retrieve(str);
        if(storedItem && typeof storedItem.ts != 'undefined' && (new Date(currentTimestamp) - new Date(storedItem.ts) < minutes * 60 * 1000)) {
            return true;
        } else {
            erase(str);
            return false;
        }
    };

    return {
        retrieve: retrieve,
        save: save,
        erase: erase,
        clearAll: clearAll,
        checkExpiry: checkExpiry
    };
}

);

Answer №3

In the past, I've successfully preserved view state by utilizing a service to store it in an object.

Instead of storing references to specific fields (such as sort columns in a table or values in certain fields) in the controller/scope, I would save them in the view state object of the service.

Upon initialization, the controller would determine if it was a new search by checking the 'source' or 'type' of page transfer through a URL parameter or state (e.g. #/search?type=new). If it was indeed a new search, the values would be reset; otherwise, the previously used values would be displayed and utilized.

Whenever the application reloaded, the data in the Service would be cleared, creating a fresh form.


The method mentioned above is straightforward because Angular takes care of the saving process for you. Services being singletons means that by directly binding to the service's fields, they will persist through route changes automatically.

In your view:

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

During controller initialization:

$scope.criteria = ViewStateService.criteria;

If you prefer to save view state only at specific points, you can set up an event handler on page change/route change events to copy the data at those junctures.

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

how to watch for a route change in angularjs

Answer №4

With various methods available, I found two to be particularly reliable. Ultimately, I opted for the first approach for my application because I needed my search parameters to carry over to other controllers.

Saving Parameters in Cookies

Utilizing $cookies in Angular.js allows for easy management of browser parameters. This serves as a dependable source for search parameters.

For instance:

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});

        // perform search operation here
        // remember to cache your search results 
        // to avoid additional network requests with 'most recent' parameters
    }

    // Save search params in cookies
    function storeSearchHistory(params) {
        var history = getSearchHistory();
        history.unshift(params); 
        if(history.length > searchCookieMaxSize) {
            history.pop();
        }
        $cookies.putObject(searchCookieKey, history);
    }

    // Retrieve 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);
            }]
        }
    })

If you do not cache these search network calls, your app will experience delays while waiting for the request to complete.

Passing Parameters through States

By creating a parent controller that retains $stateParams, child controllers can inherit these parameters without overrides when navigating back and forth or within child states. However, when moving between states with specific parameters, ensure to explicitly define the parent's $stateParams.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Maximizing the potential of JavaScript by utilizing effective tags

Looking to enhance my JavaScript code by adding a maximum tags option limited to 6 with no duplicates. Check out the current snippet below: <div id="tags"> <span>php</span> <span>c++< ...

Customizing AngularJS Delimiters

Is it possible to use a custom delimiter in Angular JS, such as changing from {{ var }} to [[ var ]]? Could someone provide a detailed example on how to successfully implement this customization with Angular? ...

Opt for utilizing a global npm package over repeatedly installing it

Is there a way to utilize the globally installed package without needing to reinstall it every time we run npm i? Here's the scenario I have: I've set up a docker image with a specific package already installed (installation command in the Docker ...

How to Ensure an Element Appears Above Another Despite Z-Index Troubles?

After conducting approximately 2 hours of research on this topic, I was unable to find clear answers or solutions. Hence, I have decided to address the issue here. The problem I'm facing is as follows: Due to the nature of HTML/CSS, it seems impossi ...

Encountering difficulties in accessing files displayed by serve-index in Express

My Node.js server using Express seems to be working fine for displaying directory contents, but I'm running into an issue when trying to access individual files. After clicking on a file listed in the directory, I keep getting an error message that sa ...

Managing multiple strings within an array of strings using JavaScript

Array data is structured with account names on the left and subscriptions on the right side. 7ef:" 3sdc 12exf" 12ef:" 8ecg" 10ef:" 3ecf 3egf 3elm 3ecf 3egf 3elm " This means that the index 7ef has 2 strings of data separated by a space, while 10ef has 6 ...

jquery is failing to load content dynamically

Hi there! I've been working on dynamically loading content, but when clicking on the menu, only the loader appears. I seem to be missing something in the code or doing something wrong. Could you please take a look and let me know? Here's my HTML ...

Why don't inline style changes implemented by JavaScript function properly on mobile browsers like Chrome, Dolphin, and Android?

View the jsFiddle here Issue on PC/Windows browser: When performing action, h1 header "gif" disappears and video starts playing. Problem on mobile devices: The gif does not disappear as expected but the video still plays indicating that JavaScript is fun ...

Having trouble with testing an Angular directive?

This is a snippet from my directive spec file for Angular 6. import { Component, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, ComponentFixture, async } from '@angular/core/testing'; import { By } from ' ...

The private route fails to redirect once the condition has been met

I am facing an issue with my PrivateRoute not redirecting after the condition is satisfied. In my scenario, when an admin clicks on login, it should check whether a token is present in localStorage. If there is no token, it should redirect to the login pag ...

Running the JavaScript code on a webpage using Selenium WebDriver

I am currently in the process of creating an automated test for a website, and I am encountering some difficulty trying to execute a specific function within the site's code. Upon inspecting the developer tools, I have identified the function I need ...

Using regular expressions to match routes in JSON

Let's say I have the following JSON object: var urls = { "GET/users/:id":1, "POST/users":0 } If I have a string like "GET/users/10", how can I use it as a key to retrieve the corresponding value from the urls JSON? In this case, "GET/users/10" s ...

exploring methods to prevent flash of unstyled content (fouc)

Looking for a way to control CSS with a cookie: Want the user's style choice to stick until they change it or the cookie expires Avoid any default styling issues when the user returns Avoid using jquery, libraries, or frameworks Need compatibility w ...

Jquery Delay feature failing to perform as desired

Afternoon all! Having a bit of trouble with a dialog box that I'm trying to close after a 5-second delay. Been tinkering with some code, but for some reason, the dialog box just closes right away without any delay. Here's the snippet I've ...

Utilize Protractor and Jasmine tags to execute a series of test suites

I'm looking for a way to utilize tagging options similar to those in cucumberJS with protractor, but using Jasmine. Is there a method to tag different scenarios like @smoke, @regression, etc. and then specify in the console to run based on those tags? ...

There is no 'Access-Control-Allow-Origin' header on the resource you requested, so access from 'localhost ' is not permitted

I'm trying to retrieve JSON data by passing a URL, but I keep encountering an error that states: Failed to load https://sample-dec42.firebaseapp.com/one.json: Response to preflight request doesn't pass access control check: No 'Access-Contr ...

Can a Node.js application be configured to accept user input from an external text editor?

Currently working on a Node.js application where I need to integrate an external text editor such as VSCode. The goal is to prompt the user to input text and save it, then have the app retrieve the saved data from the text editor as stdin. Essentially, it& ...

Setting a default field value in Mongoose when updating multiple documents at once

Issue: Encountering problem with aggregation in a non-existent field. I am working with the Follow Schema which has the following fields: _user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true } ...

How to ensure input fields are validated with a combination of Angular and jQuery frameworks?

Currently, I am utilizing angular.js and jQuery to validate user inputs within a form that is dynamically generated using ng-repeat. The setup involves an array of strings (barcodes) that are looped through and displayed alongside an input field for user i ...

Tips for showcasing mobile view content on a full web screen

Link to the Reference Page:- https://i.sstatic.net/fmahp.png This query has been raised by a developer before, but the provided solution did not work for me. Link to the original question:- How to Change Desktop View, Tablet View, and Mobile View Inside ...