Given the following code:
function Ctrl($scope, $http, $q) {
var search = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=5').
success(function(data3) {
$scope.clicked = false;
$scope.results = data3.results;
});
}
$scope.reset = function () {
$scope.sliding = false;
$scope.name = undefined;
};
};
$scope.$watch('name', search, true);
var done = $scope.getDetails = function (id) {
$scope.clicked = true;
$scope.sliding = true;
var api = 'http://api.discogs.com/artists/';
return $q.all([$http.get(api + id),
$http.get(api + id + '/releases?page=1&per_page=100')]);
};
done.then(function (){
$scope.releases = data2.releases;
$scope.artist = data;
return $http.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=e8aefa857fc74255570c1ee62b01cdba&artist=' + name + '&album='+ title +'&format=json');
});
I'm getting the following console error:
TypeError: Object function (id) {
$scope.clicked = true;
$scope.sliding = true;
var api = 'http://api.discogs.com/artists/';
return $q.all([$http.get(api + id),
$http.get(api + id + '/releases?page=...<omitted>... } has no method 'then'
at new Ctrl (file:///C:/Users/Zuh/Desktop/AngularJS%20Discogs/js/services.js:27:9)
Can anybody point me to where might the error be? I'm defining the .then after getDetails is executed...
Here's a working Plunker.
Here is your updated plunkr http://plnkr.co/edit/lTdnkRB1WfHqPusaJmg2?p=preview
angular.module('myApp', ['ngResource']);
function Ctrl($scope, $http, $q) {
var search = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=5').
success(function(data3) {
console.log(arguments)
$scope.clicked = false;
$scope.results = data3.results;
});
}
$scope.reset = function () {
$scope.sliding = false;
$scope.name = undefined;
};
};
$scope.$watch('name', search, true);
var done = $scope.getDetails = function (id) {
$scope.clicked = true;
$scope.sliding = true;
var api = 'http://api.discogs.com/artists/';
var q = $q.all([$http.get(api + id),
$http.get(api + id + '/releases?page=1&per_page=100')])
.then(function (ret){
//console.log(arguments)
$scope.releases = ret[1].data.releases;
$scope.artist = ret[0];
return $http.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=e8aefa857fc74255570c1ee62b01cdba&artist=' + name + '&album='+ title +'&format=json');
})
return q
};
}
To sum up fixes:
move $q.all().then() part into done method
pay more attention to what parameters handlers received in then part.
Related
I created an application where I have controller and factory. I have an array inside of the factory where I want to push id of the element to this array. However, when I am trying to push element to array I got an error that
"favorites.push is not a function"
Below you can find my controller and factory. Thank you for reading:
Factory:
.factory('favoriteFactory',['$resource', 'baseURL','$localStorage', function ($resource, baseURL, $localStorage) {
var favFac = {};
var favorites = $localStorage.get('favorites', []);
favFac.addFavorites = function (index) {
for(var i=0; i<favorites.length; i++){
if(favorites[i].id == index)
return
}
favorites.push({id: index});
$localStorage.storeObject('favorites',favorites)
}
favFac.deleteFromFavorites = function (index) {
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index) {
favorites.splice(i, 1);
}
}
$localStorage.storeObject('favorites', favorites)
};
favFac.getFavorites = function () {
return $localStorage.getObject('favorites',[]);
};
return favFac
}])
Controller:
.controller('MenuController', ['$scope', 'menuFactory', 'favoriteFactory','baseURL', '$ionicListDelegate', 'dishes', '$localStorage',
function($scope, menuFactory,favoriteFactory, baseURL, $ionicListDelegate, dishes, $localStorage) {
$scope.baseURL = baseURL;
$scope.tab = 1;
$scope.filtText = '';
$scope.showDetails = false;
$scope.showMenu = true;
$scope.message = "Loading ...";
$scope.addFavorite = function (index) {
console.log("index:" +index);
favoriteFactory.addFavorites(index);
$ionicListDelegate.closeOptionButtons();
};
$scope.dishes = dishes;
$scope.select = function(setTab) {
$scope.tab = setTab;
if (setTab === 2) {
$scope.filtText = "appetizer";
}
else if (setTab === 3) {
$scope.filtText = "mains";
}
else if (setTab === 4) {
$scope.filtText = "dessert";
}
else {
$scope.filtText = "";
}
};
$scope.isSelected = function (checkTab) {
return ($scope.tab === checkTab);
};
$scope.toggleDetails = function() {
$scope.showDetails = !$scope.showDetails;
};
}])
I assume you are using ngStorage. The get method does not have a second parameter. Therefore, your attempt at returning a default value of [](empty array) is simply returning undefined and then you are attempting to push to undefined and not to an array.
The source code for ngStorage shows no second parameter for get:
https://github.com/gsklee/ngStorage/blob/master/ngStorage.js
So this line:
var favorites = $localStorage.get('favorites', []);
Should be this:
var favorites = $localStorage.get('favorites') || [];
I have this factory which is called multiple times by directives. Since it returns a lot of data the rendering at the end is slow. How can i call it only once or save it in a cashe when its called the second time and n time?
appBMdata.factory('Trends',['$http','Config','$q',
function($http,Config,$q){
function getAllData() {
var source1 = $http.get(Config.api_server + 'bizmonitor/indicators/get/2016');
var source2 = $http.post(Config.api_server + 'trends');
return $q.all([source1, source2]);
};
return {
getAllData : getAllData,
};
}]);
You can save the promise in a var, and return it if it has been already set:
appBMdata.factory('Trends',['$http','Config','$q',
function($http,Config,$q){
var _cacheGetAllData;
function getAllData() {
var source1 = $http.get(Config.api_server + 'bizmonitor/indicators/get/2016');
var source2 = $http.post(Config.api_server + 'trends');
_cacheGetAllData = _cacheGetAllData || $q.all([source1, source2]);
return _cacheGetAllData;
}
return {
getAllData : getAllData,
};
}]);
If you want successive calls to force to update, you can edit it to something like this:
appBMdata.factory('Trends',['$http','Config','$q',
function($http,Config,$q){
var _cacheGetAllData;
function getAllData(ignoreCache) {
var source1 = $http.get(Config.api_server + 'bizmonitor/indicators/get/2016');
var source2 = $http.post(Config.api_server + 'trends');
if (ignoreCache) {_cacheGetAllData = undefined;}
_cacheGetAllData = _cacheGetAllData || $q.all([source1, source2]);
return _cacheGetAllData;
}
return {
getAllData : getAllData,
};
}]);
I'm resolving it in the service and then store data, if it has data, returning data in a promise. If you want to fetch data again just add true as first arguement.
appBMdata.factory('Trends', ['$http', 'Config', '$q', function($http, Config, $q) {
var data;
function getAllData(nocache) {
var deferred = $q.defer();
if (data.length && !nocache) {
deferred.resolve(data);
} else {
var source1 = $http.get(Config.api_server + 'bizmonitor/indicators/get/2016');
var source2 = $http.post(Config.api_server + 'trends');
$q.all([source1, source2])
.then(function (values) {
data = values;
deferred.resolve(data);
})
.catch(function (err) {
deferred.reject(err);
});
}
return deferred.promise;
}
return {
getAllData : getAllData
};
}]);
Yes you can keep the data on $rootScope and return the data from there when its called multiple times.
appBMdata.factory('Trends',['$http','Config','$q','$rootScope'
function($http,Config,$q,$rootScope){
function getAllData() {
var source1 = $http.get(Config.api_server + 'bizmonitor/indicators/get/2016');
var source2 = $http.post(Config.api_server + 'trends');
return $q.all([source1, source2]);
};
if($rootScope.data){ // check if data already present
$rootScope.data=getAllData(); // assign data to rootscope
}
return {
getAllData : $rootScope.data, //return data from rootscope
};
}]);
I need to inject some piece of code into a function, to prevent DRY. Here is an example of my code.
angular.module('crypt', ['ui.chart'])
.controller('MainCtrl', ['$http', function($http) {
var self = this;
self.encrypt = function() {
$http.post('/encrypt',
{'crypt': {'text': self.plain, 'shift':self.rot}})
.then(function(response) {
self.encrypted = response.data.encrypted;
self.plain = '';
// reusable function goes here
// var frequencyArr = response.data.frequency;
// var frequencyArrLength = frequencyArr.length;
// if (frequencyArrLength) self.cryptChart = [frequencyArr];
});
};
self.decrypt = function() {
$http.post('/decrypt',
{'crypt': {'text': self.encrypted, 'shift':self.rot}})
.then(function(response) {
self.plain = response.data.plain;
self.encrypted = '';
// and here
// the stuff to become a function
var frequencyArr = response.data.frequency;
var frequencyArrLength = frequencyArr.length;
if (frequencyArrLength) self.cryptChart = [frequencyArr];
});
};
// ...
}])
So how do I pack that 3 lines and make a reusable function in Angular way?
Maybe like this:
angular.module('crypt', ['ui.chart'])
.controller('MainCtrl', ['$http', function($http) {
var self = this;
function cryption(decrypt, callBack) {
$http.post(
decrypt ? '/decrypt' : '/encrypt',
{crypt: {text: decrypt ? self.encrypted : self.plain, shift: self.rot }})
.then(callBack);
}
function cryptChart(response) {
var frequencyArr = response.data.frequency;
var frequencyArrLength = frequencyArr.length;
if (frequencyArrLength) // can be simplyfied to response.data.frequency.length
self.cryptChart = [frequencyArr];
}
self.encrypt = cryption(false, function(response) {
self.encrypted = response.data.encrypted;
self.plain = '';
cryptChart(response);
});
self.decrypt = cryption(true, function(response) {
self.plain = response.data.plain;
self.encrypted = '';
cryptChart(response);
});
// ...
}])
I went bit further and extracted the shared $http.post call into function as well.
I have a code
angular.module('ngMailChimp', ['ngAria', 'ngMessages', 'ngAnimate'])
.controller('SignUpController', function () {
var ctrl = this,
newCustomer = { email:'', userName:'', college:'' },
actions,
MailChimpSubscription;
var signup = function () {
if( ctrl.signupForm.$valid) {
$http({
url: 'http://' + 'campusconnect' + '.' + 'us11' +'.list-manage.com/subscribe/post-json',
method: "GET",
params: {NAME: ctrl.newCustomer.userName,
COLL : ctrl.newCustomer.college,
EMAIL : ctrl.newCustomer.email,
u : "35f503a1404877769e67c22f9",
id : "d5a2aab2f9" }
});
//MailChimpSubscription.save(
// Successfully sent data to MailChimp.
//function (response) {
// if (response.result === 'error')
// {
// ctrl.showSubmittedPrompt = false;
// }
// else
// {
// ctrl.showSubmittedPrompt = true;
// clearForm();
// }
//},
//function (error) {
// $log.error('MailChimp Error: %o', error);
//}
//);
ctrl.showSubmittedPrompt = true;
clearForm();
}
};
var clearForm = function () {
ctrl.newCustomer = { email:'', userName:'', college:'' }
ctrl.params={}
ctrl.signupForm.$setUntouched();
ctrl.signupForm.$setPristine();
};
var getPasswordType = function () {
return ctrl.signupForm.showPassword ? 'text' : 'password';
};
var toggleEmailPrompt = function (value) {
ctrl.showEmailPrompt = value;
};
var toggleUsernamePrompt = function (value) {
ctrl.showUsernamePrompt = value;
};
var toggleCollegePrompt = function (value) {
ctrl.showCollegePrompt = value;
};
var hasErrorClass = function (field) {
return ctrl.signupForm[field].$touched && ctrl.signupForm[field].$invalid;
};
var showMessages = function (field) {
return ctrl.signupForm[field].$touched || ctrl.signupForm.$submitted
};
ctrl.showEmailPrompt = false;
ctrl.showUsernamePrompt = false;
ctrl.showCollegePrompt = false;
ctrl.showSubmittedPrompt = false;
ctrl.toggleEmailPrompt = toggleEmailPrompt;
ctrl.toggleUsernamePrompt = toggleUsernamePrompt;
ctrl.toggleCollegePrompt = toggleCollegePrompt;
ctrl.getPasswordType = getPasswordType;
ctrl.hasErrorClass = hasErrorClass;
ctrl.showMessages = showMessages;
ctrl.newCustomer = newCustomer;
ctrl.signup = signup;
ctrl.clearForm = clearForm;
})
.directive('validatePasswordCharacters', function () {
return {
require: 'ngModel',
link: function ($scope, element, attrs, ngModel) {
ngModel.$validators.lowerCase = function (value) {
var pattern = /[a-z]+/;
return (typeof value !== 'undefined') && pattern.test(value);
};
ngModel.$validators.upperCase = function (value) {
var pattern = /[A-Z]+/;
return (typeof value !== 'undefined') && pattern.test(value);
};
ngModel.$validators.number = function (value) {
var pattern = /\d+/;
return (typeof value !== 'undefined') && pattern.test(value);
};
ngModel.$validators.specialCharacter = function (value) {
var pattern = /\W+/;
return (typeof value !== 'undefined') && pattern.test(value);
};
ngModel.$validators.eightCharacters = function (value) {
return (typeof value !== 'undefined') && value.length >= 8;
};
}
}
})
;
However, On debugging, it doesnt budge ast this line. Whats is the error????
the ctrl.newCustomer is a valid object and I am able to get the strings from my HTML page.
NAME - text input
COLL - text input
EMAIL - email input
Validation is taken care of
You must inject the $http service:
angular.module('ngMailChimp', ['ngAria', 'ngMessages', 'ngAnimate'])
.controller('SignUpController', function ($http) {
...
Please notice that this form is not safe for minimization, in that case you should use:
.controller('SignUpController', ['$http', function ($http) {
// your code
}]);
In the script below i try to access the data from the cartDataService, even though i manage to read this.test from the cartDataService, i get an empty value for the cart_id. I know it is due to the asynchronous characteristics of javascript
i am pretty sure that i try to access the cart_id from the service before it is assigned, how do i make sure that the cart_id from the service is assigned? thank you
var app = angular.module('myApp', [])
app.service('cartDataService', function () {
this.cart_id = ""
this.getcart_id = function(){ return this.cart_id};
this.setcart_id = function(id){
this.cart_id = id
}
this.test = "byebye"
})
app.controller('OrderDetailCtrl', ['$http', 'cartDataService', function ($http, cartDataService) {
var self = this
self.msg = 'Order Detail'
self.order_id = outer_id
self.orders = {
get: function () {
return $http.get('http://apimucommerce/api/order/' + self.order_id + '/')
.then(function (response) {
return response.data
})
}
}
self.orders.get().then(function (data) {
self.order = data
self.cart_id = self.order.cart_id
cartDataService.setcart_id(self.order.cart_id)
})
}])
app.controller('CartController', ['cartDataService', function (cartDataService) {
var self = this
self.cart_id = cartDataService.getcart_id()
alert(cartDataService.cart_id)
self.msg = cartDataService.test
}])
You can use this:
app.controller('CartController', ['$scope', 'cartDataService', function ($scope, cartDataService) {
var self = this
$scope.$watch(
function () watcher{
return cartDataService.getcart_id();
},
function () onCardIdChanged{
self.cart_id = cartDataService.getcart_id()
alert(self.cart_id);
}
);
}]);
Another way to solve your problem:
app.service('cartDataService', ['$q', function ($q) {
var deffered = $q.defer();
this.cart_id = "";
this.getcart_id = function(){
return deffered.promise;
};
this.setcart_id = function(id){
this.cart_id = id;
deffered.resolve(;
}
}]);
app.controller('CartController', ['$scope', 'cartDataService', function ($scope, cartDataService) {
var self = this;
cartDataService.getcart_id().then(function (cardId) {
self.cart_id = cartDataService.getcart_id()
alert(self.cart_id);
});
}]);
UPD:
app.service('cartDataService', ['$q', function ($q) {
var deffered = $q.defer();
this.cart_id = "";
this.getcart_id = function(){
return deffered.promise;
};
this.setcart_id = function(id){
this.cart_id = id;
deffered.resolve(id);
}
}]);
app.controller('CartController', ['$scope', 'cartDataService', function ($scope, cartDataService) {
var self = this;
cartDataService.getcart_id().then(function (cardId) {
self.cart_id = cardId;
alert(self.cart_id);
});
}]);