can't access the data from service in controller - angularjs

I am trying to add angular-typeahead to my app for search suggestion taking help from this Plunkr.
This is the code of app.js file:
var myApp = angular.module('myApp', ['ngRoute','siyfion.sfTypeahead']);
myApp.factory('websitesSvc',function($http, $log, $q) {
return {
getwebsites: function(){
//Create a promise using promise library
var deferred = $q.defer();
$http({method: 'GET', url: '/api/websites/'}).
success(function(data, status, headers,config){
deferred.resolve(data);
}).
error(function(data, status, headers,config){
deferred.reject(status);
});
return deferred.promise;
}
};
});
myApp.controller('MyCtrl', ['$scope','websitesSvc',
function($scope,websitesSvc) {
$scope.searchString=null;
websitesSvc.getwebsites().then(function(websites){
$scope.websites = websites;
console.log($scope.websites); //It works here
});
//Output undefined
//THIS IS NOT WORKING
console.log($scope.websites);
var websites = new Bloodhound({
datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.domain_name); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
//want to pass the websites array list from service to local
local:websites, //THIS IS NOT WORKING
});
// initialize the bloodhound suggestion engine
websites.initialize();
$scope.numbersDataset = {
displayKey: 'domain_name',
source: websites.ttAdapter()
};
// Typeahead options object
$scope.exampleOptions = {
highlight: true
};
}
]);
The thing is the I am not able to pass the value of $scope.websites to the typeahead.How to make get the value of websites from services so that I can pass the resultant array to the typeahead?
After editing the code as suggested by red 6 hours ago Kalhano Toress Pamuditha, I am able to access the data.But now I am getting this

websitesSvc.getwebsites().then(function(websites){
$scope.websites = websites;
console.log($scope.websites); //It works here
});
//Output undefined
//THIS IS NOT WORKING
console.log($scope.websites); this will execute before websitesSvc.getwebsites() completes,
javascript code is not hold until sync calls to be complete it will execute the rest of the code, that is the case where u get the undefined.
you will get the data after websitesSvc.getwebsites() promise. so if u need to execute something after this data received, you can execute a function inside then like below
websitesSvc.getwebsites().then(function(websites){
$scope.websites = websites;
console.log($scope.websites); //It works here
$scope.methodAfterComplete();
});
$scope.methodAfterComplete = function() {
// this will call after completing the websitesSvc.getwebsites()
}
so you can place your code inside methodAfterComplete method which require $scope.websites data. for example ;
$scope.methodAfterComplete = function() {
var websites = new Bloodhound({
datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.domain_name); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
local:websites,
});
// initialize the bloodhound suggestion engine
websites.initialize();
$scope.numbersDataset = {
displayKey: 'domain_name',
source: websites.ttAdapter()
};
// Typeahead options object
$scope.exampleOptions = {
highlight: true
};
}

Related

TypeError: dataFile.saveDataFile is not a function in angularjs service

I'm getting the error TypeError: dataFile.saveDataFile is not a function when trying to call the function saveDataFile from my dataFile service (funnily enough).
The dataFile service code is below, it's a little more odd because the loadDataFile function gets called and works no problem.
angular.module('crmApp').
factory('data', function($http, $filter, $q){
var data = {};
data.data;
// Get the data from the DB
data.getData = function () {
var d = $q.defer();
if (data.data) {
console.log("There's already data");
d.resolve(data.data);
// console.log(data.data);
// return data.data;
}
else {
console.log("there's no data, asking for it");
return $http({
method: 'GET',
url: '/getAllData'})
.then(function(response) {
data.data = response.data;
d.resolve(data.data);
// return data.data;
},
function myError(response) {
console.log(response);
return 1;
});
}
return d.promise;
}
The place I'm calling it from - controller.addTasks is here:
'use strict';
angular.
module('addTask')
.controller("addTask", ["$scope", "dataFile",
function($scope, dataFile) {
$scope.addTask = function(dataFile, group) {
// create the tasks json
var newTaskCreated = (new Date).getTime();
var newTask = { "task" : $scope.newTaskDescription,
"created" : newTaskCreated,
"group" : group,
"today" : false,
"status" : "incomplete"};
$scope.tasks.push(newTask);
console.log($scope.tasks);
// Save the new data in tasksData.json
dataFile.saveDataFile($scope.tasks);
// add the task to the screen
// reset the blank addtask input box
$scope.newTaskDescription = "";
}
}]);
None of the similar posts I've seen have helped so any help you can offer is greatly appreciated.

Updating array after $http request not working

ng-repeat in md-sidenav
<md-list>
<md-list-item ng-repeat="it in cars">
{{ it.name }}
</md-list-item>
</mdlist>
Car Controller
self.refreshUI = function(select) {
carService.getAllCars()
.then(function (res) {
$scope.cars = carService.carsList;
console.log($scope.cars);
}, function (err) {
//error
})
};
// Load all registered cars
self.refreshUI(null);
Above code runs when controller is loaded (last line) and it's working fine. But when I create new car (cars are stored in mysql db) and I want to update $scope.cars array by self.refreshUI() function it will not work until refreshing page mannualy.
console.log($scope.cars) from refreshUI function returns correct result but console.log(angular.element($0).scope().cars) gives wrong array (without new cars)
Car Service
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
var defer = $q.defer();
$http.get("http://car.app/getCars")
.success(function(res) {
cars.carsList = res;
defer.resolve(res);
})
.error(function(err, status){
defer.reject(err);
});
return defer.promise;
};
return cars;
}
Where could be the problem?
//edit: $rootScope is working fine but i still want to use $scope
Why aren't you using a returned Promise as a result from the $http call? Besides of a better code style, it could solve your problem. With that kind of service-controller infrastructure I never had 'binding problems' like that.
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
return $http.get('http://car.app/getCars').then(function (response) {
cars.carsList = response.data;
return response.data;
});
};
return cars;
}
In your controller you could then do something like that:
self.refreshUI = function() {
carService.getAllCars()
.then(function (data) {
// just obtain the promise data
$scope.cars = data;
}, function (err) {
// error handling
});
};
self.refreshUI();

Meteor-Angular Service function

I'm creating an app in Angular-Meteor, and i'd like create a few functions in my services which I can use in my controllers. However those functions use the $meteor.subscribe function, which queries the database and returns a call back. In my controller I want to call that function and bind that to the $scope, but then it returns undefined, because the call back hasn't returned anything yet. Is there a solution to keep the code in the service? Any tips?
An example:
Service
angular.module('GQ').service('AuthService', ['$meteor', function($meteor)
{
console.log('AuthService init')
this.getUserAuth = function() {
var user = {};
$meteor.subscribe('isAdmin').then(function(res){
//do database query...
//loop over returned values and do a check if query matches or not
// if it does match return true
// else return false
});
// then return the value
return user.isAdmin;
}
}]);
Controller
$scope.isAdmin = AuthService.getUserAuth();
console.log($scope.isAdmin) <--- undefined
You can use angular promises (official doc).
Example for your service:
this.getUserAuth = function() {
var deferred = $q.defer();
var user = {};
$meteor.subscribe('isAdmin').then(function(res, err){
// ....
// just an example
if (!res.isAdmin) deferred.reject('not an admin');
if (err) deferred.reject(err);
else deferred.resolve(res);
});
return deferred.promise;
}
Use in your controller:
AuthService.getUserAuth()
.then(function(res){
console.log(res); // the res from service
$scope.isAdmin = res; // is asynchronous, but angular updates the scope var
}, function(err){
// error handling here
});

Populate an array with data from database (Angular + PHP/MySQL)

I have a simple to-do app I'm working on, which is using Angular and then PHP/MySQL for the backend.
I now have a simple app that works, where I can add new todos, and add the "percentage completed" per day to the Database, using a simple $http post.
However now what I'm looking to do is, populate the $scope.historicalDailyPercentages array, with data from the database.
At the start of the script, I init the object like so:
$scope.historicalDailyPercentages = []; //TODO, this should be initialised with data from the database.
I understand I'll need to have some sort of $http get loop in there, to check for the data and fill the object, but I'm a little unclear on how to get started there.
The entire goalzy.js script is below for reference. Thanks in advance!
angular.module('goalzy', [])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
}])
.controller('TodoController', ['$scope', '$http', function($scope, $http) {
$scope.todos = [];
$scope.historicalDailyPercentages = []; //TODO, this should be initialised with data from the database.
$scope.addTodo = function() {
if ($scope.todoText != "") {
if ($scope.todos.length < 3) {
$scope.todos.push({
text: $scope.todoText,
done: false
});
$scope.todoText = '';
//Save to DB
} else {
alert("You can only have 3 todos per day!");
$scope.todoText = '';
}
} else {
alert("you must write something");
}
};
$scope.remaining = function() {
var count = 0;
angular.forEach($scope.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
$scope.percentComplete = function() {
var countCompleted = 0;
angular.forEach($scope.todos, function(todo) {
countCompleted += todo.done ? 1 : 0; //Simply calculates how many tasks have been completed
console.log(countCompleted);
});
var totalCount = $scope.todos.length;
var percentComplete = countCompleted / totalCount * 100;
return percentComplete;
}
$scope.finaliseDay = function(percentComplete) {
alert("You're finalising this day with a percentage of: " + percentComplete);
var today = new Date();
var alreadyPresent = $scope.historicalDailyPercentages.some(function(item) {
return item.date.getFullYear() === today.getFullYear() &&
item.date.getMonth() === today.getMonth() &&
item.date.getDate() === today.getDate();
});
//Confirm that nothing has alreayd been posted for today
if (!alreadyPresent) {
// Simple POST request example (passing data)
$http.post('/postDailyPercentage.php', {
user_id: 1,
percent: percentComplete,
date: today
}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
if (data) {
$scope.historicalDailyPercentages.push({
user_id: 1,
percent: percentComplete,
date: today
});
} else {
alert("Something went wrong" + data);
}
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log("Post failure");
});
} else {
alert("You're all set for today - see you tomorrow!");
}
//console.log($scope.historicalDailyPercentages);
}
}]);
To populate that object with an $http.get you can do it as follows:
function getHistoricalDataSuccess(data) {
$scope.historicalDailyPercentages = data;
}
function getHistoricalDataError(error) {
//handle the error
}
$http.get('path/to/api')
.success(getHistoricalDataSuccess)
.error(getHistoricalDataError);
var TodoController = function($scope, HistoricalDailyPercentageService) {
HistoricalDailyPercentageService.get().then(function(percentages) {
$scope.historicalDailyPercentages = percentages;
}, function(error) {
alert(error);
});
};
var HistoricalDailyPercentageService = function($http) {
this.get = function() {
return $http.get('yourUrl')
.then(function(xhr) {
var data = xhr.data;
// Transform the data as you see fit
return data;
}, function(xhr) {
// xhr contains the error message - modify this as you see fit.
return xhr.code;
});
};
};
angular.module('goalzy')
.controller('TodoController', ['$scope', 'HistoricalDailyPercentages', TodoController])
.service('HistoricalDailyPercentageService', ['$http', HistoricalDailyPercentageService]);
I would recommend doing it this way; this will make it easier to test by taking the logic of getting the data out of your already busy controller. #RVandersteen's example will only work inside of your controller, which is fine, but it really does make your controller very busy; controllers should really only assign things to a scope, everything else should be handled in a directive (for example, binding events to methods) or a service/factory/provider (for business logic).
After you have finished up your code, could you post on CodeReview? There's a few improvements I could suggest but they are merely review-based things and not appropriate for the scope of this question.
It's worth noting by the way that because I am using then in the controller I must use then in the service, too. If I use success in the service then my changes will not be reflected when I call then in the controller.

Calling service for factory in controller

I have a problem when calling a service created using .factory in my controller.
The code looks like the following.
Factory (app.js):
.factory('Database',function($http){
return {
getDatabase: function(){
var database = {};
$http.get('http://localhost:3001/lookup').
success(function(data){
database.companyInfo = data.info.companyInfo;
});
}).
error(function(data){
console.log('Error' + data);
});
return database;
}
};
})
Controller:
angular.module('webClientApp')
.controller('MainCtrl', function (Database,Features,$scope,$http) {
$scope.databaseString = [];
$scope.quarters = ['Q1','Q2','Q3','Q4'];
$scope.years = ['2004','2005','2006','2007','2008','2009','2010',
'2011','2012','2013','2014'];
$scope.features = Features.getFeatures();
$scope.database = Database.getDatabase();
console.log($scope.database);
Now when I inspect the element in Firebug I get the console.log($scope.database) printed out before the GET statement result. $scope.database is shown as an Object {} with all the proprieties in place.
However if I try to use console.log($scope.database.companyInfo) I get an undefined as result, while instead I should get that data.info.companyInfo' that I passed from theDatabase` service (in this case an array).
What is the problem here? Can someone help me?
(If you need clarifications please let me know..)
The $http.get() call is asynchronous and makes use of promise objects. So, based on the code you provided it seems most likely that you are outputting the $scope.database before the success method is run in the service.
I build all my service methods to pass in a success or failure function. This would be the service:
.factory('Database',function($http){
return {
getDatabase: function(onSuccuess,onFailure){
var database = {};
$http.get('http://localhost:3001/lookup').
success(onSuccess).
error(onFailure);
}
};
})
This would be the controller code:
angular.module('webClientApp')
.controller('MainCtrl', function (Database,Features,$scope,$http) {
$scope.databaseString = [];
$scope.quarters = ['Q1','Q2','Q3','Q4'];
$scope.years = ['2004','2005','2006','2007','2008','2009','2010',
'2011','2012','2013','2014'];
$scope.features = Features.getFeatures();
Database.getDatabase(successFunction,failureFunction);
successFunction = function(data){
$scope.database = data.info.companyInfo;
console.log($scope.database);
});
failureFunction = function(data){
console.log('Error' + data);
}
Change your code in the following way:
.factory('Database',function($http){
return {
getDatabase: function(){
return $http.get('http://localhost:3001/lookup');
}
};
})
Then get the response in controller(Promise chain)
Database.getDatabase()
.then(function(data){
//assign value
})
.catch(function(){
})

Resources