Filtering data from an Ajax request in Angular using a filter function with JSON

Hi everyone,

I recently started learning AngularJS and created a basic item list with search functionality and pagination. Everything was working smoothly, so I decided to move my list outside the controller and store it as a JSON file.

Here's what I did:

HTML

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" > <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Test angular</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script type="text/javascript" src="js/angular.min.js"></script>
        <script type="text/javascript" src="js/controllers.js"></script>
        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
    </head>
    <body >

      <section class="app" ng-app="myApp" data-scope="$scope = myApp" > 

         <div ng-controller="myCtrl" data-scope="$scope = myApp.myCtrl">
            <input type="text" ng-model="search" data-scope="$scope = myApp.myCtrl.items(repeater scope)">
            Search = {{ search }}
            <div class="item" ng-repeat="item in newItems | filter:search | startFrom:currentPage*pageSize | limitTo:pageSize">
              {{ item.name }}
            </div>
             <button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">
              Previous
          </button>
          {{currentPage+1}}/{{numberOfPages()}}
          <button ng-disabled="currentPage >= items.length/pageSize - 1" ng-click="currentPage=currentPage+1">
              Next
          </button>
          </div>

      </section>



    </body>
</html>

Note: The data-scope attributes are used for scope visibility.

controllers.js

var myApp = angular.module('myApp', []); 

myApp.filter('startFrom', function() {
    return function(input, start) {
        start = +start; 
        return input.slice(start);
    }
});

myApp.controller('myCtrl', function($scope, $interval, $filter, $http){
    $scope.currentPage = 0;
    $scope.pageSize = 10;
    $scope.numberOfPages=function(){
        return Math.ceil($scope.items.length/$scope.pageSize);                
    }
    $scope.$watch('search', function () {
        $scope.currentPage = 0;
        $scope.newItems = $filter('filter')($scope.items, $scope.search);
        $scope.numberOfPages=function(){
            return Math.ceil($scope.items.length/$scope.pageSize);             
        }
    });   
    $scope.newItems = $scope.items;
    $http.get('js/items.json') 
       .then(function(res){
          $scope.items = res.data;          
        });


});

The JSON loads successfully, but there seems to be an error regarding the use of the startFrom filter:

TypeError: Cannot call method 'slice' of undefined

My assumption is that the filter is trying to slice something that isn't defined yet, possibly due to the ordering of operations.

UPDATE :

After initializing $scope.items = []; as suggested by VtoCorleone, the previous errors were resolved. However, a new issue emerged where the first page of the list doesn't display any items, although pagination works as expected.

My proposed solution involves setting two properties for items (items, newItems). items contains the original JSON data, while newItems stores filtered results. By using items, all items can be retained and restored if necessary.

Upon inspecting with Angular inspector, on page load, items is populated with the JSON data, whereas newItems remains empty. This leads to the items not displaying properly despite being available in the JSON. Why is this happening?

Answer №1

If you're wondering why the page isn't showing up:

The issue here is that your $watch is only on 'search'. So, when items are updated after an ajax callback, your numberOfPages remains at 0. It's only when you start searching that the watch function kicks in and updates numberOfPages.

To solve this, make sure to include the updating of pages within your ajax callback function.

$http.get('js/items.json') // retrieve json file
   .then(function(res){
      $scope.items = res.data; // assign data to items
      $scope.numberOfPages=function(){
        return Math.ceil($scope.items.length/$scope.pageSize);             
   }             
});

Answer №2

Success!!

myApp.controller('myCtrl', function($http, $scope, $interval, $filter){



    $scope.items = [];
     $http.get('js/items.json')
       .then(function(res){
          $scope.items = angular.fromJson(res.data);   
          $scope.newItems = angular.fromJson(res.data); // I set $scope.newItems directly in the Ajax response.
        });
    //$scope.newItems = $scope.items; // this doesn't work, don't know why.
    $scope.currentPage = 0;
    $scope.pageSize = 10;
    $scope.numberOfPages=function(){
        return Math.ceil($scope.newItems.length/$scope.pageSize);                
    }
    $scope.$watch('search', function () {
        $scope.currentPage = 0;
        $scope.newItems = $filter('filter')($scope.items, $scope.search);
        $scope.numberOfPages=function(){
            return Math.ceil($scope.newItems.length/$scope.pageSize);             
        }
    });  
    $scope.$watch('pageSize', function () {
        $scope.currentPage = 0;
        $scope.numberOfPages=function(){
            return Math.ceil($scope.newItems.length/$scope.pageSize);             
        }
    });       

});

Finally, I successfully set $scope.newItems directly in the Ajax response. Upon page load, newItems is already populated with all the elements. Then I updated numberOfPages(); to reflect the number of pages based on the newItems.

$scope.newItems = $scope.items;

If anyone knows why this line is not functioning as expected (newItems is empty on page load), please enlighten me :)

Answer №3

Encountered the same issue,

To resolve it, simply include this line in your filter: "input = input || '';"

.filter('startFrom', function() {
    return function(input, start) {
        input = input || '';
        start = parseInt(start,10);
        return input.slice(start);
    }
});

When the page loads, the filter is triggered but the value may not be loaded yet, causing "input" to be undefined at that point.

++

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

jQuery's .html() function does not accept the encoded entity "&amp;"

Whenever I attempt to include a string containing "& (amp)" within the .html() function, it results in an unrecognized expression error. Can you advise me on how to convert the &amp; string or suggest the best method for inserting the desired strin ...

Creating an HTML element within a three.js globe

I have a globe created using three.js Reference: I am trying to display an HTML div at a specific latitude/longitude on the globe. Can someone guide me on how to position the div at a particular lat/long? What I've attempted: I'm currently stu ...

Require the field if the country selected is the United States

I am working on implementing form validation for the STATES dropdown, but I want it to only be required if the selected country is USA or CANADA. Currently, my validation works regardless of the country selection. It forces the user to select a state even ...

I'm looking to include a field card into the to-do table I built using .Net, but I'm not sure where I made a mistake

HTML Challenge I have set a goal to dynamically add a DOM element using JavaScript when the "Add HTML Element" button is clicked. The process involves clicking the button, which opens a modal for inputting necessary information. After fil ...

PHP: Exploring the Art of Extracting Variables from JSON Strings

It seems like I may have overlooked something obvious, what would be the most effective method to extract parameters in this specific format... '{"phonenumber":"123456", "mobile":"589521215", "website":"www.xfty.co.uk" }' in order to separate ...

What is the best way to extract information from a JSON file and display it on a webpage using

I am new to this and I have a question for everyone Here's an example of the JSON response from my URL: The JSON data returned is as follows: { "Data":{ "id": 1312, "Name": "Steem Dollars", "Symbol": "SBD", "website_slug": "steem-dollars", "Level": ...

Interactive sidebar component with navigation and animated section markers

For weeks, I've been attempting to create a navigation sidebar similar to the ones shown in these images: Even though getbootstrap.com/components offers appealing navigation sidebars, I have not found a built-in component in their library. This has m ...

Retrieving data from intricate JSON structures

Currently, I am engaged in web scraping to extract the "id" of all locations from a complex json content. Click here for the JSON link I attempted using the dict.items method, but it only extracted 2 values at the start of the dictionary followed by a li ...

Performance of obtaining image data

Is anyone else experiencing a significant lag when trying to retrieve the state of a single pixel on the canvas? Take a look at my JS code below: var state = ctx.getImageData(x,y,1,1).data; state = 'rgba(' + state[0] + ',' + state[1] ...

While tidying up the code in my home.vue file for my Vue.js project, I am constantly encountering these pesky errors

Compilation failed. ./src/views/Home.vue Error in Module (from ./node_modules/eslint-loader/index.js): C:\Users\OSOKA\Desktop\VUE\vue-shop\src\views\Home.vue 2:21 warning Remove ⏎···⏎·· ...

Is there a way to use a single function to fill and calculate multiple input fields with PHP, Javascript, and

I've encountered an issue while trying to populate a form using Javascript/ajax/php. The problem is that my function only fills in one of the required forms and then stops, even though I have received the second response from the server. Here's ...

AngularJS Alert: [$injector:unpr] Provider Not Recognized

After setting up the URL routes for the sportsStore app from an AngularJS book to learn, I'm encountering the following errors: Error: [$injector:unpr] Unknown provider: $templateRequestProvider <- $templateRequest <- $route <- ngViewDirect ...

Issue with Orgchart JS: The requested resource does not have the 'Access-Control-Allow-Origin' header present

Currently, I am developing a program to create organization charts using orgchart.js and simple PHP. This project does not involve any frameworks, but unfortunately, I encountered the following error: CORS policy is blocking access to XMLHttpRequest at & ...

Is there a way to perform nested association counting in Sequelize?

Exploring ways to tally product reviews within nested associations using a specific query. const user = await User.findOne({ where: { id: req.query.user }, attributes: ["id", "name"], include: [ { model: Category, as: "interest ...

Enhancing User Interface with AngularJS and NodeJS: Dynamically updating and animating the

I am currently coding in angularjs/nodejs To pull data from my database, I have utilized the powerful $http service. And for displaying this data on the view, I have incorporated the ngRepeat directive. However, I am facing a challenge. Whenever I add ...

Adding additional validations to your Marketo form is a great way to ensure the accuracy

I'm having trouble adding a new validation rule to the Marketo form since I'm not well-versed in JS and jQuery. I need this rule to display an error message if the form is submitted with any field left empty. Additionally, I want to validate the ...

Guide to dynamically displaying location data using JSON string on Google Maps in ASP.NET

A script is being used to display locations on a Google map: <script type="text/javascript"> $(document).ready(function () { var markersdetails = { "Iran": { "title": "Iran", "lat": "32.000000", ...

Unable to modify div style using a JS function

I am attempting to show different divs based on the button clicked, with all starting with a display style of "none" except for one default div called "atualizacoes". After clicking a button, all divs should be set to display="none", and then the specific ...

Tips for allowing specific tags using Google's Caja HTML Sanitizer in a node.js environment

I'm currently utilizing the npm module Caja-HTML-Sanitizer with node.js. Although I am able to sanitize the HTML input using the sanitizer() function, I am unsure of how to implement a whitelist in order to restrict only certain tags (e.g. p br stron ...

Struggles with converting Atom to JSONP

Currently, I am working on a news feed that is hosted on a separate server where the static PDF documents referenced in the feed are stored. I am exploring the possibility of implementing client-side feed parsing since I am uncertain about the capabilitie ...