I'm newbie in angularjs and I'm trying to create new provider. This is my code:
myApp.provider('$Data', function() {
this.URL = 'http://maps.googleapis.com/maps/api/geocode/json?address=Singapore, SG, Singapore, 153 Bukit Batok Street 1&sensor=true';
this.$get = $get;
$get.$inject = ['$http', '$q'];
function $get($http, $q) {
var that = this;
return {
isConnected: function() {
var bIsConnected = 'Default';
$http({method: 'GET', url:that.URL}).then(function (data) {
bIsConnected = 'Yes';
alert('Run this code!');
}, function (data) {
bIsConnected = 'No';
});
return bIsConnected;
}
}
}
});
Jsfiddle demo:
http://jsfiddle.net/0udm9/9dPsb/6/
After I run $Data.isConnected(), the result is always 'Default' although browser show the alert box. I think it's from success function is not of $get. And I have to use provider, not service or factory for this case. Can I do anything to fix this issue?
Thanks,
You have to use promise in your code.
DEMO
Provider:
isConnected: function() {
var deferred = $q.defer();
$http.get(that.url).then(function(res) {
deferred.resolve('Yes');
console.log('example:success', res);
}, function(err) {
deferred.resolve('No');
console.log('example:error', err);
});
return deferred.promise;
}
Controller:
$Data.isConnected().then(function(data) {
$scope.data = data;
});
// UPD
You must use objects if you need to use return values with async code.
DEMO
// UPD 2
FRESH DEMO LINK
Related
I'm working on some legacy code that uses angularjs 1.x for a web frontend. I need to create a modal dialog that will make a RESTful call to the backend when the modal is opened and wait for the data to be returned before rendering the view.
I was able to figure out most of what I needed to do, but there is one thing I still can't wrap my head around. My understanding was that I needed to use 'resolve' to define a function that would return a $promise to the controller. When I put a breakpoint inside my controller though, the parameter is an object containing the promise, the resolution status, and finally my actual data.
I can pull the data I need out of this object, but it feels like I shouldn't have to do that. My controller doesn't care about the promise itself; just the data that got returned. Is there some way to structure this so only the data gets sent to the controller or is this just how angular modals are expected to behave?
A sample of my code:
$scope.openTerritorySelect = function () {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'prospect/detail/selectTerritoriesModal.tpl.html',
controller: function($scope, $modalInstance, availableReps){
$scope.reps = availableReps;
$scope.ok=function()
{
$modalInstance.close();
};
$scope.cancel=function()
{
$modalInstance.dismiss('cancel');
};
},
resolve: {
availableReps: function () {
return Prospect.getRelatedReps({}, function (data, header) {
$scope.busy = false;
return data.result;
}, function (response) {
$scope.busy = false;
if (response.status === 404) {
$rootScope.navError = "Could not get reps";
$location.path("/naverror");
}
}).$promise;
}
}
});
modalInstance.result.then(function (selectedReps) {
}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
The 'Prospect' service class:
angular.module('customer.prospect', [ "ngResource" ]).factory('Prospect', [ 'contextRoute', '$resource', function(contextRoute, $resource) {
return {
getRelatedReps : function(args, success, fail) {
return this.payload.getRelatedReps(args, success, fail);
},
payload : $resource(contextRoute + '/api/v1/prospects/:id', {
}, {
'getRelatedReps' : {
url : contextRoute + '/api/v1/prospects/territories/reps',
method : 'GET',
isArray : false
}
})
};
} ]);
You could simplify things a great deal by making the REST request before you even open the modal. Would you even want to open the modal if the request were to fail?
$scope.openTerritorySelect = function () {
Prospect.getRelatedReps({}, function (data, header) {
$scope.busy = false;
var modalInstance = $modal.open({
animation: true,
templateUrl: 'prospect/detail/selectTerritoriesModal.tpl.html',
controller: function($scope, $modalInstance, availableReps){
$scope.reps = availableReps;
$scope.ok = function() {
$modalInstance.close();
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
},
resolve: {
availableReps: function () {
return data.result;
}
});
modalInstance.result.then(function (selectedReps) {},
function () {
console.log('Modal dismissed at: ' + new Date());
});
}, function (response) {
$scope.busy = false;
if (response.status === 404) {
$rootScope.navError = "Could not get reps";
$location.path("/naverror");
}
});
};
I'm getting the following syntax error in the console while trying to get data from 'openweathermap'
Uncaught SyntaxError: Unexpected token :
Here is the JS file :
var app = angular.module('App', ['ngResource']);
app.factory('weatherService', function($http) {
return {
getWeather: function() {
var weather = '';
// if (!!prmSearchValue) {
// var searchValue = prmSearchValue;
$http.jsonp('https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=c19bc0731cec50456576c7b36a675ca7&mode=json').success(function(data) {
weather = 3232;
});
// }
/* else {
weather = {};
} */
return weather;
}
};
});
//Eilat,Israel
app.controller('httpAppCtrlr', function($scope, weatherService) {
$scope.searchText = '';
$scope.searchWeather = function() {
var prmSearchValue = $scope.searchText;
$scope.weather = weatherService.getWeather();
};
});
It looks as if the data that returns is broken in some way..
Fiddle
Use $http Get instead of JSONP. Better way to handle the error is using .then, Change your Factory as follows,
app.factory('weatherService', function ($http) {
return {
getWeather: function () {
var weatherForcast = {};
$http({
method: 'GET',
url: "https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=c19bc0731cec50456576c7b36a675ca7"
}).then(function successCallback(response) {
angular.extend(weatherForcast, response.data);
}, function errorCallback(response) {
alert('API call failed, possibly due to rate limiting or bad zip code.');
});
return weatherForcast;
}
};
});
WORKING FIDDLE
In AngularJS jsonp, you need to append callback=JSON_CALLBACK to the url. (I'll assume there is a reason you're using jsonp instead of get.)
Replace
https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=c19bc0731cec50456576c7b36a675ca7&mode=json
with
https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=c19bc0731cec50456576c7b36a675ca7&mode=json&callback=JSON_CALLBACK
Fiddle
I have an AngularJs application working with components and several modules. I created a plunker example to present my problem here.
I have my NavbarComponent where I declared my Controller where I inject my service called NavbarService.
In the NavbarService, I inject a factory resource to make my Rest call, once this call is made I'm trying to made some treatment on the response before returning it back to the controller, in this example I just apply a simple filter on it, but it doesn't work. If I omit my treatment and return only the categories, the code works and you can visualize a list of two.
I can make my treatment in the controller but this is a bad practice 'cause I believe it should be done in the Service, secondly since it's an asynchronous response I must do something like this to make it work, which is really really ugly:
navbarService.getCategories().$promise.then(function (response) {
console.log("controller", response[0].category);
vm.categories = categoryFilter(response[0].category);
}, function (error) {
console.log("an error occured");
});
Can someone please guide me through this, I'm out of solutions. Thank you
Another simple way is to pass a callback function to service from you component like this
'use strict';
angular.module('navbar').component('appNavbar', {
templateUrl: "navbar.template.html",
controller: [ 'navbarService', function appNavbarController(navbarService) {
var vm = this;
navbarService.getCategories(function(data){
// this will be called when service will get the response and filter function has filtered the response
vm.categories = data;
});
}]
});
Now service should be like this
'use strict';
angular.module('navbar').service('navbarService', ['categoryResourceService', 'categoryFilter', function(categoryResourceService, categoryFilter) {
var vm = this;
vm.getCategories = function(callback) {
categoryResourceService.query(function(response) {
console.log("[NavbarService] response:", response);
callback(categoryFilter(response));
}, function(error) {
console.log("[NavbarService] error:", error);
});
//return vm.categories;
}
}]);
Filter will be like this
'use strict';
angular.module('navbar').filter('category', function() {
return function(categories) {
var categoryIds = ['World'];
var result = [];
angular.forEach(categoryIds, function (categoryId) {
angular.forEach(categories, function (category) {
if (category.name == categoryId) {
console.log("Match");
result.push(category);
}
});
});
return result;
};
});
Your filter should be like this and it should be called in transformResponse in $resource query instead of service, i hope this will help you
'use strict';
angular.module('navbar').filter('category', function() {
return function(categories) {
var categoryIds = ['World'];
var result = [];
angular.forEach(categoryIds, function (categoryId) {
angular.forEach(categories, function (category) {
if (category.name == categoryId) {
console.log("Match");
result.push(category);
}
});
});
return result;
};
});
Your categoryResource.service should be like this
angular.module('shared').factory('categoryResourceService',
['$resource','categoryFilter', function($resource, categoryFilter) {
var provider = "categories.json";
var params = {
id: '#id'
};
return $resource(provider, params, {
query: {
isArray: true,
method: 'GET',
params: {},
transformResponse: function(categories) {
var results = categoryFilter(angular.fromJson(categories));
console.log("[categoryResourceService] filtered response:", results);
return results;
}
}
});
}]);
navbar.service should be like this simply
'use strict';
angular.module('navbar')
.service('navbarService', [ 'categoryResourceService', function (categoryResourceService) {
var vm = this;
vm.getCategories = function(){
vm.categories = categoryResourceService.query(function(response){
console.log("[NavbarService] response:", response);
}, function(error){
console.log("[NavbarService] error:", error);
});
return vm.categories;
}
}]);
And components like this
'use strict';
angular.module('navbar').component('appNavbar', {
templateUrl: "navbar.template.html",
controller: [ 'navbarService', function appNavbarController(navbarService) {
var vm = this;
vm.categories = navbarService.getCategories();
}]
});
I want to have a button that refresh a page (request to http to load data) :
http://plnkr.co/edit/Ol6iEoLp037ZHu0P40Wr?p=preview
refresh button with Factory - - not working
$scope.doRefresh = function() {
Content.content.success(function(data){
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
Now when you delete some data and want to have theme back you should hit refresh button but it's not working .
working demo
http://plnkr.co/edit/WHSEPxyQDi3YNkEP8irL?p=preview
$scope.doRefresh = function() {
$http.get("data.json")
.success(function(data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
})
}
now it's working with $http
I want to do it with factory , but i can't handle this , Any advice ?
Update *****
Factory
app.factory('Content', function ($http) {
return {
content: $http.get('data.json')
}
})
You've got to tell your service to retrieve the data every time the content is requested.
app.factory('Content', function ($http, $q) {
return {
getContent: function() {
var deferred = $q.defer();
$http.get('data.json').succes(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
})
Then in your controller you can do:
$scope.doRefresh = function() {
Content.getContent().then(function(data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
You can also just cache the data in your factory and return it without doing a request:
app.factory('Content', function($http, $q, $timeout) {
var originalData;
return {
getContent: function() {
var deferred = $q.defer();
if (!originalData) {
$http.get('data.json').succes(function(data) {
originalData = data;
deferred.resolve(data);
});
} else {
/// gonna use timeout to simulate async behaviour -- kinda hacky but it makes for a pretty interface
$timeout(function() {
defered.resolve(originalData);
}, 0);
}
return deferred.promise;
}
}
})
Careful though, changes done to the returned object will affect the originalData object.
app.factory('Content', function ($http) {
function getContent(onSuccess) {
$http.get('data.json').success(function (data) {
if (onSuccess) {
onSuccess(data)
}
}
}
return {
content: getContent
}
})
in your controller:
$scope.doRefresh = function () {
Content.content(function (data) {
$scope.data = data.artists;
console.log($scope.data);
$scope.$broadcast('scroll.refreshComplete');
});
};
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I got this angular factory:
var productApp = angular.module('productApp', ['ngRoute', 'LocalStorageModule', 'angularSlideables', 'ui.bootstrap']);
productApp.factory('productFactory', function($http, localStorageService, $q) {
var factory = {};
factory.getProductById = function(prod_id) {
if(prod_id !== '') {
$http({
url: 'rest/message/getProductById/' + prod_id,
method: 'GET'
}).success(function(data, status) {
return data;
}).error(function(data, status){
// do nothing
});
}else {
alert("There was an error while passing the ID. Please refresh the page and try again");
}
}
return factory;
});
Injecting the factory in a controller and calling to the "getProductById" function:
productApp.controller('ModalInstanceCtrl', function ($scope, $modalInstance, productFactory, prodId) {
console.log("this is the prod id " + prodId);
// search product in the database
$scope.prod = productFactory.getProductById(prodId);
console.log($scope.prod);
$scope.ok = function () {
console.log($scope.prodData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Now, don't know what's wrong with it... the function RETURNS the data because i did a console.log(data) and saw all the response, but in the controller if i inspect the $scope.prod, it's undefined. It's not returning the data back from the function.
(Just in case you guys ask, the "prodId" in the controller parameter is fine, and retrieving that from another controller)
How can i solve this? :(
Thanks in advance.
The pattern I have used to solve this problem is to pass in the success & error callback functions to the factory... like this:
var productApp = angular.module('productApp', ['ngRoute', 'LocalStorageModule', 'angularSlideables', 'ui.bootstrap']);
productApp.factory('productFactory', function($http, localStorageService, $q) {
var factory = {};
factory.getProductById = function(prod_id, successCallback, errorCallback) {
if(prod_id !== '') {
$http({
url: 'rest/message/getProductById/' + prod_id,
method: 'GET'
})
.success(successCallback)
.error(errroCallback);
} else {
alert("There was an error while passing the ID. Please refresh the page and try again");
}
}
return factory;
});
and then:
productApp.controller('ModalInstanceCtrl', function ($scope, $modalInstance, productFactory, prodId) {
console.log("this is the prod id " + prodId);
// search product in the database
productFactory.getProductById(prodId, function successCallback(data) {
$scope.prod = data;
}, function errorCallback(data, status) {
alert("An error occurred retrieving product. Please refresh the page & try again.");
});
console.log($scope.prod);
$scope.ok = function () {
console.log($scope.prodData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
By doing it this way instead, you have access to the scope in the controller & can do whatever you need to with the returned data.
Here's what I do. I'm using $resournce instead of $http, but it should be enough to get you going. You may even want to use the $resource since it has the built in fns.
My factory:
.factory('WorkOrder', function($resource){
// $resource Usage: $resource(url[, paramDefaults][, actions]);
return $resource('/controller/get/:id.json', {}, {
/*
* By default, the following actions are returned; modify or add as needed
* { 'get': {method:'GET'},
* 'save': {method:'POST'},
* 'query': {method:'GET', isArray:true},
* 'delete': {method:'DELETE'} };
*/
});
})
My controller:
// get the work order data using the work order id from the tag attribute
var getWO = function() {
WorkOrder.get({woId:$attrs.id},
// success callback
function(response) {
// Assign the work order data to the scope
$scope.WorkOrder = response.WorkOrder;
},
// fail callback
function(response) {
// whatever...
}
);
};
getWO();
I put my success and fail fns in my controller because that's where I most likely know how I want to respond to success or failed calls. I also assign the function to a variable and then call it right after in case I want to include the fn call inside a $timeout or call it elsewhere.
Hope this answers your question.