Parse.com query users through factory Service

Building an app using Parse.com for the backend. The user creation and querying works fine when using the simple parse.com code for the docs.
However I have been trying to put the query into a AngularJS service, so that it can be accesses and I can do a ng-repeat to display the returned results in a list.

The code I have put in place so far is this:

View:

    <div class="row">
      <div class="col col-75">
      <label class="item item-input">
        <i class="icon ion-search placeholder-icon"></i>
        <input type="text" placeholder="Search" ng-model="search.queryvalue">
      </label>
      </div>
      <div class="col">
        <button class="button button-calm" ng-click="searchnow()">Search</button>
      </div>
    </div>

    <ion-list>
      <ion-item class="item-avatar" type="item-text-wrap" ng-repeat="user in users">
          <img ng-src="{{userpic}}.png">
          <h2>{{user.id}}</h2>
          <p>{{user.get('location')}}</p>
      </ion-item>
    </ion-list>

Controller:

.controller('SearchResultsCtrl', function($scope, $state, $rootScope, parseQueryFactory) {
  $scope.search = {};
  $scope.users = {};
  $scope.searchnow = function () {
    $scope.users = parseQueryFactory.searchUsers($scope.search.queryvalue);
  };
})

Services:

.factory('parseQueryFactory', function($http) {
  
  var query = new Parse.Query(Parse.User);
  var people = {};

  return {
    searchUsers: function(searchVal){
      query.startsWith("username", searchVal);  // Search username
      query.limit(20);
      return query.find({
        success: function(people) {
          /*var objects = {};
          for (var i = 0; i < people.length; i++) { 
            var object = people[i];
            objects = objects + object;
          }
          console.log(people);
          return objects;*/
        },
        error: function(error) {
          return error;
        }
      });
  }
}
})

I have tried a few ways to make this work, but I am new to angular and not sure how to go about doing this.

The only thing that works is if i put the following code in the controller (but then I cannot use ng-repeat):

$scope.searchnow = function () {
    var queryvalue = $scope.user.queryvalue;
    userquery.startsWith("username", queryvalue);  // Search username
    userquery.limit(20);
    userquery.find({
      success: function(people) {
        for (var i = 0; i < people.length; i++) { 
          var object = people[i];
          console.log("ID: " + object.id + ', username: ' + object.get('username'));
        }
      }, error: function(error) {
        console.log("error");
      }
    });
  };

Has anyone implemented such a service for parse.com?

I have looked around and tried implementations from various people, but always the data that gets returned is not usable and it doesn’t seem to display at all.

Hey there!

Did you solve this issue? Apparently people here are quite busy solving more issues…I’m experimenting a similar problema.

Thanks!

Cheers

You can use callbacks.

try following code

//change in controller
 $scope.searchnow = function () {
     parseQueryFactory.searchUsers($scope.search.queryvalue, function(users){
         $scope.users = users;
    });
  };

// change in service
return {
    searchUsers: function(searchVal, callback){
      query.startsWith("username", searchVal);  // Search username
      query.limit(20);
      return query.find({
        success: function(people) {
          callback(people);
        },
        error: function(error) {
          alert(error);
        }
      });
  }

This is what I use for using parse.com as a backend (sorry I have just dumped my code in here but reckon you can just pull out the code you need).

controller

    .controller('NewsIndexCtrl', ['$scope', 'CommonService', 'NewsService', '$state', '$location', '$timeout', '$ionicLoading', 
    function ($scope, CommonService, NewsService, $state, $location, $timeout, $ionicLoading) {

    $scope.navTitle =  "News";
    CommonService.FooterTitle = ""
    
    function refreshNews() {

        if (!CommonService.ConnectionOnline) {
            $scope.$broadcast('scroll.refreshComplete');  // Incase we are in pull to refresh
            window.plugins.toast.show('No network connection.', 'short', 'center');
            return;
        };

        $ionicLoading.show({
          template: 'Loading...',
          noBackdrop: false
        });
        NewsService.getNewsArticles(CommonService.ShowUnpublished)
            .then(function (data) {
                NewsService.newsArticles = data;
                $scope.news = data;
                $scope.$broadcast('scroll.refreshComplete');
                $ionicLoading.hide();
            },
            function (err) {
               // HandleError(err);
               $scope.$broadcast('scroll.refreshComplete');
               $ionicLoading.hide();
            });
    }

    $scope.onSelectNewsArticle = function(newsArticle) {
        NewsService.selectedNewsArticle = newsArticle;
        //$state.go('news.detail', { NewsId: newsArticle.id });
        $location.url('/news/' + newsArticle.id);
    }

    $scope.onRefresh = function() {
        refreshNews();
        // Note: Broadcast needs to be done in refreshNews as async nature
        //$scope.$broadcast('scroll.refreshComplete');
    }

    // Init news if not loaded yet
    if (NewsService.newsArticles.length == 0) {
        refreshNews();
    } else {
        $scope.news = NewsService.newsArticles;
    }
    
}])

service:

    .factory('NewsService', function($q, LogService) {

  var ParseObject = Parse.Object.extend("News");

  var selectedNewsArticle = null;

  var newsArticles = {};

  // Properties
  Object.defineProperty(ParseObject.prototype, "Title", {
    get: function() {
      return this.get("Title");
    },
    set: function(aValue) {
      this.set("Title", aValue);
    }
  });
  Object.defineProperty(ParseObject.prototype, "Blurb", {
    get: function() {
      return this.get("Blurb");
    },
    set: function(aValue) {
      this.set("Blurb", aValue);
    }
  });
  Object.defineProperty(ParseObject.prototype, "Article", {
    get: function() {
      return this.get("Article");
    },
    set: function(aValue) {
      this.set("Article", aValue);
    }
  }); 
  Object.defineProperty(ParseObject.prototype, "PostDateTime", {
    get: function() {
      return this.get("PostDateTime");
    },
    set: function(aValue) {
      this.set("PostDateTime", aValue);
    }
  });   
  Object.defineProperty(ParseObject.prototype, "Published", {
    get: function() {
      return this.get("Published");
    },
    set: function(aValue) {
      this.set("Published", aValue);
    }
  }); 

  return {

    NewsObject: function(){
      return ParseObject;
    },

    selectedNewsArticle: function() {
      return selectedNewsArticle;
    },

    newsArticles: function() {
      return newsArticles;
    },

    getNewsArticles: function(ShowUnpublished){
      LogService.add('getNewsArticles Start');
      //Creating a deferred object
      var deferred = $q.defer();
      //Query Parse
      var query = new Parse.Query(ParseObject);
      if (!ShowUnpublished) {
        query.equalTo('Published', true)
      }
      query.descending('PostDateTime');
      query.find({
        success : function(data) {
          LogService.add('getNewsArticles Success');
          //Passing data to deferred's resolve function on successful completion
          deferred.resolve(data);
        },
        error : function(err) {
          //Return error message incase of failure
          LogService.add('getNewsArticles Failed: ' + err);
          deferred.reject(err);
         } 
      });

      //Returning the promise object
      return deferred.promise;
    },

    getNewsArticle: function(NewsId){

      if (NewsService.selectedNewsArticle != null) {
        return NewsService.selectedNewsArticle;
      }
      LogService.add('getNewsArticle Start');
      //Creating a deferred object
      var deferred = $q.defer();
      //Query Parse
      var query = new Parse.Query(ParseObject);
      query.get(NewsId, {
        success : function(data) {
          LogService.add('getNewsArticle Success');
          //Passing data to deferred's resolve function on successful completion
          deferred.resolve(data);
        },
        error : function(err) {
          LogService.add('getNewsArticle Failed: ' + err);
          //Return error message incase of failure
          deferred.reject(err);
         } 
      });

      //Returning the promise object
      return deferred.promise;
    }

  }
})

hope this helps

Darren

1 Like

@darrenahunter Sorry I could not follow your solution. There is alot going on, as your service returns various values. I’m not 100% sure how to use this. Will have to look into a bit further.

@mrameezraja I tried using your solution. However I get the following error:
TypeError: Cannot read property 'replace' of undefined

The error is coming from this line:
query.startsWith("username", searchVal);

Not sure what the exact issue is.

@iontofer This is what worked for me:

In my controller I put this code:

$scope.searchnow = function () {
    $ionicLoading.show();
    console.log("Search Now Button Pressed");
    var newqueryvalue = $scope.searchqueryvalue;
    console.log("button QueryVal: var " + newqueryvalue);
    console.log("button QueryVal: scope " + $scope.searchqueryvalue);
    
    userquery.startsWith("username", newqueryvalue);  // Search username
    userquery.notEqualTo("id", $rootScope.sessionUser.id);
    userquery.limit(20);
    userquery.find({
      success: function(result) {
        console.log("results found");
        $scope.people = result;
        $ionicLoading.hide()
      },
      error: function(error) {
        console.log("error");
      }
    });
  };

And in my template, following was the code:

<ion-list>
      <ion-item class="item item-icon-right" type="item-text-wrap" ng-href="#/search/user/{{person.id}}" ng-repeat="person in people">
          {{person.get('fullname')}}
          <span class="item-note">{{person.get('location')}}</span>
          <i class="icon ion-chevron-right"></i>
      </ion-item>
    </ion-list>

This has been the most functional solution for me since I was not being able to understand services. However, there is one strange issue.
This code works perfects on ionic serve, Android and the iOS Emulator, however, it does not work on an actual iPhone (I have tested this on iPhone 4s, 5, 5s and 6)

I have realised that the reason for this is that Parse just returns nothing. It is not returning any value at all, always an empty array. If anyone can help me with this issue that would be perfect.

Hi

just a note you will want to include the ‘$ionicLoading.hide()’ in your error handler function also

Yeah forgot to add that. Good spot, thanks.