Loop exiting after first iteration is driving me nuts.

72 views
Skip to first unread message

Daniel Turner

unread,
Sep 28, 2014, 7:44:08 AM9/28/14
to ang...@googlegroups.com
I know this is just a small error somewhere, but I can't spot it. I've been playing around with the code at this fiddle, http://jsfiddle.net/SAWsA/11/, trying to learn angular. The code worked quite well, after a few fixes were made to it. I then added in a get, to pull the data from a json file, and the search function no longer works. The loop under the search exits, after the first iteration, and I just can't figure out why. I've been pulling my hair out over this for a couple of hours now, and I can't find any relevant information via the internet. Here is the code, I feel, is causing the problem. 

    var searchMatch = function (list, item) {
        if (!item) {
            return true;
        }
        return list.toLowerCase().indexOf(item.toLowerCase()) !== -1;
    };

    // init the filtered items
    $scope.search = function () {
        $scope.filteredItems = $filter('filter')($scope.itemList, function (item) {

            console.log(item);
            for(var prop in item){ //***Here is the escaping loop.

                if (item.hasOwnProperty(prop)) {
                    console.log(prop + " -> " + item[prop]);
                    if( searchMatch(item[prop], $scope.query) ){

                        return true;

                    }

                }

            }

            return false;

        });

Any help would be greatly appreciated. If you need more information to help me solve this problem, just let me know. This is really starting to get me.

Sander Elias

unread,
Sep 29, 2014, 6:08:15 AM9/29/14
to ang...@googlegroups.com

Hi Daniel,

My guess, without seeing the rest of your code is that you don’t need to do a return true.
but you need to add the matched item to an result array.

Regards
Sander

Daniel Turner

unread,
Sep 29, 2014, 9:48:34 AM9/29/14
to ang...@googlegroups.com
Thanks for the reply Sander. I'm gonna give that a shot and see what happens. I'll let you know, for sure.
Message has been deleted

Daniel Turner

unread,
Sep 29, 2014, 2:13:06 PM9/29/14
to ang...@googlegroups.com

Ok... still tearing my hair out on this. Here is my entire controller code. If anyone could help me figure out how this search is dying, that'd be great.


'use strict';

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

//Get JSON
costControllers.factory('itemJSON', function($http){

    return function(){

        return $http.get('json/items.json').then(function(response) {

            var promisedData = response.data;
            return promisedData;

        })

    };

});

costControllers.controller('MainCostCtrl', ['$scope', '$http', '$filter', 'itemJSON', function($scope,  $http, $filter, itemJSON){

    $scope.title = "Test v.054";

    var sortingOrder = 'id';

    //Set initial values
    $scope.sortingOrder = sortingOrder;
    $scope.reverse = false;
    $scope.filteredItems = [];
    $scope.groupedItems = [];
    $scope.itemsPerPage = 10;
    $scope.pagedItems = [];
    $scope.currentPage = 0;
    $scope.itemList = [];
    $scope.query = "";
    $scope.addedItems = [];
    $scope.selectPerPage = 10;

    //Get Brand JSON and pass data
    itemJSON().then(function(data){

        $scope.itemList = data;
        $scope.search();

    });

    var searchMatch = function (list, item) {
        if (!item) {
            return true;
        }
        return list.toLowerCase().indexOf(item.toLowerCase()) !== -1;
    };

    // init the filtered items
    $scope.search = function () {
        $scope.filteredItems = $filter('filter')($scope.itemList, function (item) {

            var result = [];

            for(var prop in item){

                if (item.hasOwnProperty(prop)) {
                    //console.log(prop + " -> " + item[prop]);

                    if(item[prop] === item['id']) continue;

                    if( searchMatch(item[prop], $scope.query) ){

                        result.push(item[prop]);

                    }

                }

            }

            console.log(result);
            return result;

            //original search loop for the query
            /*for(var prop in item){

                if (item.hasOwnProperty(prop)) {
                    console.log(prop + " -> " + item[prop]);

                    if(item[prop] === item['id']) continue;

                    if( searchMatch(item[prop], $scope.query) ){

                        return true;

                    }

                }

            }

            return false;*/

        });

        console.log($scope.filteredItems);

        // take care of the sorting order
        if ($scope.sortingOrder !== '') {
            $scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
        }

        $scope.currentPage = 0;
        // now group by pages
        $scope.groupToPages();
    };

    // calculate page in place
    $scope.groupToPages = function () {
        $scope.pagedItems = [];

        for (var i = 0; i < $scope.filteredItems.length; i += 1) {
            if (i % $scope.itemsPerPage === 0) {
                $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
            } else {
                $scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
            }
        }
    };

    $scope.range = function (start, end) {
        var ret = [];
        if (!end) {
            end = start;
            start = 0;
        }
        for (var i = start; i < end; i += 1) {
            ret.push(i);
        }
        return ret;
    };

    $scope.prevPage = function () {
        if ($scope.currentPage > 0) {
            $scope.currentPage -= 1;
        }
    };

    $scope.nextPage = function () {
        if ($scope.currentPage < $scope.pagedItems.length - 1) {
            $scope.currentPage += 1;
        }
    };

    $scope.setPage = function () {
        $scope.currentPage = this.n;
    };

    // change sorting order
    $scope.sort_by = function(newSortingOrder) {
        if ($scope.sortingOrder == newSortingOrder)
            $scope.reverse = !$scope.reverse;

        $scope.sortingOrder = newSortingOrder;

        $scope.search();

        // icon setup
        $('th.costHead').each(function(){
            // icon reset
            $(this).removeClass().addClass('sorting');
        });
        if ($scope.reverse)
            $('th.'+ newSortingOrder).removeClass().addClass('sorting_asc');
        else
            $('th.'+ newSortingOrder).removeClass().addClass('sorting_desc');
    };

    //selects item from table and sends to array
    $scope.itemSelect = function(item) {

        var added = $scope.addedItems.some(function(match){
            return match.id === item.id;
        });

        if (!added){
            $scope.addedItems.push(item);
        }
        console.log( $scope.addedItems );

    };

    //removes item from added items array
    $scope.removeItemSelect = function (item) {

        var index = $scope.addedItems.indexOf(item);

        $scope.addedItems.splice(index, 1);

    };

    // set the number of items per page
    $scope.$watch('selectPerPage', function(){

        $scope.itemsPerPage = $scope.selectPerPage;
        $scope.groupToPages();

    });

    //Table Sizing


    //Inject controller
    costControllers.$inject = ['$scope', '$filter'];

}]);


And here is the relevant html

</select>
                            <input type="text" ng-model="query" ng-change="search()" style="float: right" class="" placeholder="Search...">
                        </div>
                        <!-- /.panel-heading -->
                        <div class="panel-body">
                            <tr class="paging_total_row">
                                <div class="total_con">{{filteredItems.length}} total items</div>
                                <div class="dataTables_paginate paging_simple_numbers">
                                    <ul class="pagination">
                                        <li class="paginate_button previous disabled" ng-class="{disabled: currentPage == 0}">
                                            <a href ng-click="prevPage()">« Prev</a>
                                        </li>
                                        <li class="paginate_button"
                                            ng-repeat="n in range(pagedItems.length)"
                                            ng-class="{active: n == currentPage}"
                                            ng-click="setPage()">
                                            <a href ng-bind="n + 1">1</a>
                                        </li>
                                        <li class="paginate_button next" ng-class="{disabled: currentPage == pagedItems.length - 1}">
                                            <a href ng-click="nextPage()">Next »</a>
                                        </li>
                                    </ul>
                                </div>
                            </tr>
                            <div class="table-responsive">
                                <table class="table table-striped table-bordered table-hover" id="itemTables">
                                    <thead>
                                    <tr role="row">
                                        <th class="sorting costHead" ng-click="sort_by('brand')">Brand</th>
                                        <th class="sorting costHead" ng-click="sort_by('name')">Item</th>
                                        <th class="sorting costHead" ng-click="sort_by('description')">Description</th>
                                        <th class="sorting costHead" ng-click="sort_by('part_number')">Part Number</th>
                                        <th class="sorting costHead" ng-click="sort_by('supplier')">Supplier</th>
                                        <th class="sorting costHead" ng-click="sort_by('cost')">Cost</th>
                                    </tr>
                                    </thead>

                                    <tbody>
                                        <tr role="row" ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse" ng-click="itemSelect(item)">
                                            <td class="table_li">{{item.brand}}</td>
                                            <td class="table_li">{{item.name}}</td>
                                            <td class="table_li">{{item.description}}</td>
                                            <td class="table_li">{{item.part_number}}</td>
                                            <td class="table_li">{{item.supplier}}</td>
                                            <td class="table_li">{{item.cost | currency:"$"}}</td>
                                        </tr>
                                    </tbody>

Majid Burney

unread,
Oct 3, 2014, 2:39:34 PM10/3/14
to ang...@googlegroups.com
I put your code into a plunker: http://plnkr.co/edit/HpQgPE7zCW5q7N7fvpTL?p=preview

For future reference, this is a very nice thing to do and will get more people to help you. If someone can easily hop in and see your code working (or not working) and tinker with it, they’ll be much likelier to respond. A lot of code on a page isn’t much good to anyone.

I had to take a stab at what your JSON data looked like based on the table, but it’s pretty straight forward stuff. If my guess was correct, then I know what your problem is. If that “cost” property is a float and not a string, the toLowerCase call in searchMatch will throw an error. If that’s the issue, you should be seeing an error along the lines of "TypeError: undefined is not a function at searchMatch” in your console.

On the other hand, if I make the costs strings and revert the filtering to how you originally had it, searching works fine. But it would be better to leave the costs as floats and fix your searchMatch function… if that is indeed the issue.

Also, FYI, when Sander suggested changing the filtering to add to an array, I think he meant to do so instead of using $filter(‘filter’). The way you were originally using filter, by returning true or false, was correct, but $filter doesn’t buy you anything here over pushing matches directly onto the $filteredItems array.
Reply all
Reply to author
Forward
0 new messages