Angularjs: use ".then" and get response - javascript

I want send a http request and get response of this request. I want if data is save, I get database information and if doesn't save, I get errors. For this, I want use .then in angularjs. I create angularjs controller and services to do this. I have below code in angularjs part:
bolouk.js:
'use strict';
var app = angular.module('app');
app.controller('BoloukCtrl', ['$scope', 'Bolouks', function($scope, Bolouks){
$scope.save = function(){
Bolouks.create($scope.bolouk).then(function(data){
$scope.saveBolouk = data;
},function(err){
$scope.err = err;
}
);
};
}]);
boloukService.js:
'use strict';
var app = angular.module('boloukService', ['ngResource']);
app.factory('Bolouks', function($resource) {
return $resource('/api/bolouks.json', {}, {
create: { method: 'POST', isArray: false }
});
});
and I have below code in rails server:
bolouks_controller.rb:
def create
#bolouk = Bolouk.create(bolouk_params)
if #bolouk.valid?
##bolouk.save
respond_with #bolouk, :location => api_bolouks_path
else
respond_with #bolouk.errors, :location => api_bolouks_path
end
end
private
def bolouk_params
params.require(:bolouk).permit(:boloukcode, :north, :south, :east, :west)
end
Request send to rails server correctly and data is save to database right, but I cannot get response of request and when I run function`, I get below error in chrome console:
TypeError: undefined is not a function
at Scope.$scope.save (http://localhost:3000/assets/controllers/bolouk.js?body=1:19:39)
at http://localhost:3000/assets/angular.js?body=1:10973:21
at http://localhost:3000/assets/angular.js?body=1:20088:17
at Scope.$eval (http://localhost:3000/assets/angular.js?body=1:12752:28)
at Scope.$apply (http://localhost:3000/assets/angular.js?body=1:12850:23)
at HTMLFormElement.<anonymous> (http://localhost:3000/assets/angular.js?body=1:20087:21)
at HTMLFormElement.jQuery.event.dispatch (http://localhost:3000/assets/templates/jquery-1.10.2.js?body=1:4627:9)
at HTMLFormElement.elemData.handle (http://localhost:3000/assets/templates/jquery-1.10.2.js?body=1:4295:46)
I think I don't use .then correctly in angularjs controller, I check $q method too, but again get this error. Any one have idea to solve this problem?

you have assign both module in same variable. this may conflict your code. so use this code:
bolouk.js:
'use strict';
var app = angular.module('app',['ngResource']);
app.controller('BoloukCtrl', ['$scope', 'Bolouks', function($scope, Bolouks){
$scope.save = function(){
Bolouks.create($scope.bolouk).$promise.then(function(data){
$scope.saveBolouk = data;
})
.catch(function (err) {
console.log(err);
})
};
}]);
boloukService.js:
'use strict';
app.factory('Bolouks', function($resource) {
return $resource('/api/bolouks.json', {}, {
create: { method: 'POST', isArray: false }
});
});

var app = angular.module('app',['boloukService']);
app.controller('BoloukCtrl', ['$scope', 'Bolouks', function($scope, Bolouks){
$scope.save = function(){
var user = Bolouks.get();
user.get(function(resp) {
//request successful
}, function(err) {
//request error
});
};
}]);
angular.module('boloukService', ['ngResource']);
app.factory('Bolouks', function($resource) {
var savedData = {}
function get() {
return $resource('/api/bolouks.json', {}, {
create: { method: 'POST', isArray: false}
});
}
return {
get: get
}
});
try this one :)

Related

Refactoring Angular controller into separate factory and controller

Learning Angular. Working with 1.6.6 right now.
In my initial stab, I put all my $http requests into my controller, so I'm trying to pull that out of the controller and into a factory for more reusable code. I think that I am missing something related to Promise or injection, but the data from my $http call is not being bound to $scope correctly.
I've been following along this guide.
I have a template that's begin loaded from the controller (the template is loading fine):
<form ng-init="getAllRegions()" ng-submit="getRandomTown()">
<h3>Generate Random Town</h3>
<div class="form-group-row">
<label for="selectRegion">Select Region:</label>
<select name="nameEntity"
id="selectRegion"
ng-model="guidEntity"
ng-options="item.guidEntity as item.nameEntity for item in regions">
<option value="" ng-if="!guidEntity"></option>
</select>
</div>
</form>
The ng-init function is being called, and passes through the controller and the service. In chrome inspector I can see that data is pulling through correctly, but I'm new to working with Promises, so I'm losing something along the way. This was all working as expected when the $http call was right in the controller and the data was being bound to $scope in the controller.
The controller:
angular.
module('randomTown.controller', []).
component('randomTownGenerator', {
templateUrl: 'js/components/randomTownGenerator/randomTownGenerator.tpl.html'
}).
controller('RandomTownCtrl',
function($scope, randomTownFactory) {
$scope.data = {};
$scope.getAllRegions = function () {
$scope.regions = randomTownFactory.getAllDBRegions();
}
}
);
The service:
angular.
module('randomTown.service', []).
factory('randomTownFactory', function ($q, $http) {
var service = {};
service.getAllDBRegions = function() {
var deferred = $q.defer();
$http({
method: 'GET',
url: '/all-regions'
}).then(function success(data) {
deferred.resolve(data);
}), function error(response) {
deferred.reject('There was an error');
}
return deferred.promise;
}
return service;
});
There is no need to manufacture a promise with $q.defer. Simply return the $http promise:
app.factory('randomTownFactory', function ($q, $http) {
var service = {};
service.getAllDBRegions = function() {
̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶r̶e̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶
̲r̲e̲t̲u̲r̲n̲ $http({
method: 'GET',
url: '/all-regions'
}).then(function success( ̶d̶a̶t̶a̶ response) {
̶d̶e̶f̶e̶r̶r̶e̶d̶.̶r̶e̶s̶o̶l̶v̶e̶(̶d̶a̶t̶a̶)̶;̶
return response.data;
}),̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶e̶r̶r̶o̶r̶(̶r̶e̶s̶p̶o̶n̶s̶e̶)̶ ̶{̶
̶d̶e̶f̶e̶r̶r̶e̶d̶.̶r̶e̶j̶e̶c̶t̶(̶'̶T̶h̶e̶r̶e̶ ̶w̶a̶s̶ ̶a̶n̶ ̶e̶r̶r̶o̶r̶'̶)̶;̶
̶}̶
̶r̶e̶t̶u̶r̶n̶ ̶d̶e̶f̶e̶r̶r̶e̶d̶.̶p̶r̶o̶m̶i̶s̶e̶;̶,
}
return service;
});
Also notice that the success handler does not reveal the data. It reveals a response object of which data is one of the properties.
The controller:
app.controller('RandomTownCtrl',
function($scope, randomTownFactory) {
$scope.getAllRegions = function () {
var promise = randomTownFactory.getAllDBRegions();
promise.then(function(data) {
$scope.regions = data;
}).catch(function(errorResponse) {
console.log("ERROR", errorResponse.status)
});
}
}
);
For more information, see
AngularJS $http service API Reference
You're Missing the Point of Promises
Try this:
$scope.getAllRegions = function () {
randomTownFactory.getAllDBRegions()
.then((regions) => {$scope.regions = regions});
}
Why: because etAllDBRegions returns a promise, so you have to use then property to get the result

Angular UI-Grid TypeError: Cannot set property 'data' of undefined. Sending a promise from Service and data coming as undefined

I am exploring Angular.js UI-Grid. However, I can't seem to figure out why data is coming as undefined when I am making an HTTP request in my service. It seems to work fine when I make an HTTP request from my controller. How can I make Ui-Grid work in a modular way?
HTML
<div id="grid1" ui-grid="gridOptions" class="grid"></div>
Controller
app.controller('tableCtrl', function($scope, tableService) {
var getAllArtistData = function() {
tableService.getArtistData().then(function(data) {
console.log("this is controller data", data);
$scope.gridOptions.data = data;
$scope.gridOptions = {};
$scope.gridOptions.columnDefs = [
{name:'artist_id'},
{name:'first_name'}
];
});
};
getAllArtistData();
});
Service
app.service('tableService', function($http, $q) {
/************************************************
GET ARTIST DATA
************************************************/
this.getArtistData = function() {
var defer = $q.defer();
$http.get('../../../data/artists-lite.json')
.success(function(response) {
console.log("this is response", response);
defer.resolve(response);
})
.error(function(err) {
defer.reject(err);
});
return defer.promise;
};
});
App.js
'use strict';
var app = angular.module('bucketfeet', ['ui.router','ui.grid', 'ngAnimate']);
app.run(function($state, $rootScope) {
$rootScope.$state = $state;
});
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise('/');
$stateProvider
.state('stats',
{
url: '/stats',
templateUrl: './js/views/statsTmpl.html'
})
.state('table',
{
url: '/table',
templateUrl: './js/views/tableTmpl.html',
controller: 'tableCtrl'
});
});
In your controller you should initialize your gridOptions before using it. Even better, try extracting setting up of this variable to controller scope, leave filling only the data in asynchronous method:
app.controller('tableCtrl', function($scope, tableService) {
// Initialize gridOptions with all the properties, except for data
$scope.gridOptions = {};
$scope.gridOptions.columnDefs = [
{name:'artist_id'},
{name:'first_name'}
];
$scope.gridOptions.data = [];
var getAllArtistData = function() {
tableService.getArtistData().then(function(data) {
console.log("this is controller data", data);
// fill only data in asynchronous callback
$scope.gridOptions.data = data;
});
};
getAllArtistData();
});
Method tableService.getArtistData() is executed asynchronously and the callback for this method is only executed when the data is retrieved from server. This can happen in couple of milliseconds, it can happen in minutes. The rendering of the grid needs to happen before the callback is executed, and it lacks the metadata information of how to render the grid. That is why I suggest initializing grid metadata before launching the asynchronous call, and inside the callback setting only the data.

Get data before page load in angularJS

I am trying to fetch a drop downlist before the page load using angular $http. I tried few combinations but it keep on giving the same error:
Error: [$injector:unpr] Unknown provider: officeListProvider <- officeList <- myController
http://errors.angularjs.org/1.4.3/$injector/unpr?p0=officeListProvider%20%3C-%20officeList%20%3C-%20myController
I am few weeks old in angular so please pardon in case of any silly mistakes.
var myApp = angular.module('myApp',['ngRoute']);
myApp.config(['$routeProvider',function ($routeProvider) {
$routeProvider.when('../../home/goEeUpdateAngular.obj', {
templateUrl: '/employee_update_angular.jsp',
controller: 'myController',
resolve: {
officeList: function(officeListFactory) {
return officeListFactory.getOfficeList();
}
}
});
}]);
myApp.factory('officeListFactory', function($http, $window) {
$window.alert("Hi");
var factoryResult = {
getOfficeList: function() {
var promise = $http({
method: 'GET',
url: '../../home/goOfficesList.obj'
}).success(function(data, status, headers, config) {
console.log (data);
return data;
});
return promise;
}
};
console.log (factoryResult.getOfficeList());
return factoryResult;
});
myApp.controller('myController',function ($scope,officeList) {
$scope.officeListFactory = officeListFactory.data;
});
The error says "officeListProvider" is not present or not visible, you need to add it as dependency.
Please try the below change:
var ctrl = angular.module('myApp.controllers', []);
to
var ctrl = angular.module('myApp.controllers', ['myApp.services']);
and also please use the same service name it is either srvOfficeList or officeList, and also check your service factory, it is not right - example:AngularJS : factory $http service
Hope it will fix the issue.
Please try to create a CodePen (or similar tool) while posting the question, so that the Answer can tried/fixed in there and shared back with you.
In controller you should call only officeList. Here is the working JSFIDDLE. I too sample webapi instead of your url
var myApp = angular.module('myApp',['ngRoute']);
myApp.config(['$routeProvider',function ($routeProvider) {
$routeProvider.when('../../home/goEeUpdateAngular.obj', {
templateUrl: '/employee_update_angular.jsp',
controller: 'myController',
resolve: {
officeList: function(officeListFactory) {
return officeListFactory.getOfficeList();
}
}
});
}]);
myApp.factory('officeListFactory', function($http, $window) {
$window.alert("Hi");
var factoryResult = {
getOfficeList: function() {
var promise = $http({
method: 'GET',
url: '../../home/goOfficesList.obj'
}).success(function(data, status, headers, config) {
console.log (data);
return data;
});
return promise;
}
};
console.log (factoryResult.getOfficeList());
return factoryResult;
});
myApp.controller('myController',function ($scope,officeList) {
$scope.officeListFactory = officeList.data; //changes are made here
});

How to view json data from angularjs http callback?

I can see my json data in the console and I want to view it on html page after clickbutton function. From my understaning I can either do a promise ($q) or then with http or ngResource. First I want to do http then migrate to ngResource. For some reason my scope is still undefined. Maybe it's a ng-init or ng-repeat I'm missing? Any ideas?
var app = angular.module('myApp', []);
app.factory('httpq', function($http, $q) {
return {
get: function() {
var deferred = $q.defer();
$http.get.apply(null, arguments)
.success(deferred.resolve)
.error(deferred.resolve);
return deferred.promise;
}
}
});
app.controller('myController', function($scope, httpq) {
httpq.get('http://localhost:8080/states')
.then(function(data) {
$scope.returnedData = data;
})
$scope.clickButton = function() {
$scope.returnedData;
}
});
view
<div data-ng-controller="myController">
<button data-ng-click="clickButton()">Get Data From Server</button>
<p>JSON Data : {{returnedData}}</p>
</div>
Use Ajax call
Service:
var demoService = angular.module('demoService', [])
.service('myService',['$http', function($http) {
this.getdata = function(entity){
var promise = $http({
method : 'POST',
url : 'services/entity/add',
data : entity,
headers : {
'Content-Type' : 'application/json'
},
cache : false
}).then(function (response) {
return response;
});
return promise;
};
}]);
Controller :
var demoService = angular.module('demoService', [])
.controller('myctr',['$scope','myService',function($scope,myService){
myService.getdata().then(function(response){
//Success
},function(response){
//Error
});
}]);
now you can see your json in controller success
$http itself is a promise, no need to create a new promise. Just return the $http.get wihoit the success written there and right the sucess fn in the controller itself. So your code will look like this:
app.factory('httpq', function($http) {
return {
get: function() {
return $http.get.apply(null, arguments);
}
}
});
Your controller:
app.controller('myController', function($scope, httpq) {
httpq.get('http://localhost:8080/states').then(function(data) {
$scope.returnedData = data;
})
$scope.clickButton = function() {
$scope.returnedData;
}
});
use
$scope.returnedData=JSON.parse(data);
It will give you values in JSON format
I have not worked with promise. But your factory code seems to be ok.
In controller declare your object first.
If it's just object declare it as
$scope.returnedData = {};
If it's array, declare it as
$scope.returnedData = [];
The the object will not be undefined and changes will affect in HTML

AngularJS: Getting back data with specific id

I'm trying to get a specific product by its id from a JSON file with products. I have some kind of problem as this question
AngularJS : get back data from a json array with an id
the code is similar. I read through that question and the accepted answer there, still can't figured this out. From what I understand the $scope.search() returns a promise which after success triggers the .then() to set get the correct person.
This line of code prints out the products array and also getting the product id from the url.
However it prints out twice in the console.
console.log($scope.products + $routeParams.productId);
app.js
var app = angular.module('gtbApp', [
'ngRoute',
'productControllers'
]);
// Setting up the routes with right controllers and partials
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/main', {
templateUrl: 'partials/product-grid.html',
controller: 'ProductController'
})
.when('/product/:productId', {
templateUrl: 'partials/product-detail.html',
controller: 'ProductDetailCtrl'
})
.otherwise({
redirectTo: '/main'
});
}]);
controllers.js
var app = angular.module('productControllers', []);
// For product-grid.html
app.controller('ProductController', ['$http', function($http){
var store = this;
store.products = [];
$http.get('products.json').success(function(data){
store.products = data;
});
}]);
// For product-detail.html
app.controller('ProductDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){
$scope.search = function() {
var url = 'products.json';
// Return a promise object
return $http.get(url).success(httpSuccess).error(function(){
console.log('Unable to retrieve info form JSON file.');
});
}
httpSuccess = function(response) {
$scope.products = response;
}
function getById(arr, id) {
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i].id === id) {
return arr[i];
}
}
}
$scope.search().then(function(){
// Prints out the products array and id twice
console.log($scope.products + $routeParams.productId);
$scope.product = getById($scope.products, $routeParams.productId);
// Prints out twice "undefined"
console.log($scope.product);
});
}]);
The main question is how to get specific product based on id why in "ProductDetailCtrl"
$scope.product = getById($scope.products, $routeParams.productId);
doesn't work.
Thanks in advance!
Update:
Found out why $scope.product is undefined, it is just because the $routeParams.productId is a string, and in getById() need a integer in second args.
However I don't know why console.log($scope.product); prints out twice.
I don't really understand what your main question is here. But anyways. When you use the $http service it will return a promise, which you eventually will have to unwrap. What you are doing in your code is that you are unwrapping it twice. Which is fine.
With $http response you can either use 'success'/'error' or just 'then' which can take a success and an error callback. Which means you could either unwrap in the search function or after you call the search function.
$scope.search = function() {
var url = 'products.json';
$http.get(url)
.success(function(data){
$scope.product = getById($scope.products, $routeParams.productId);
})
.error(function() {
console.log('Unable to retrieve info form JSON file.');
});
}
You could also do something like:
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
$scope.search().then(function(data) {
$scope.product = getById(data, $routeParams.productId);
}, errorCallback);
And the below would achieve the same result
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
$scope.search()
.success(function(data) {
$scope.product = getById(data, $routeParams.productId);
})
.error(errorCallback);
or reference the promise:
$scope.search = function() {
var url = 'products.json';
return $http.get(url);
}
var dataPromise = $scope.search();
dataPromise.then(function(data) {
$scope.product = getById(data, $routeParams.productId);
}, errorCallback);
What you need to know is that as long as you're returning something within a success/error/then function it will return a promise which you will have to unwrap in order to get the data.
You should be either using the .success() and .error() on the $http-promise or only then .then()
Do it like this:
app.controller('ProductController', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){
$scope.search = function() {
var url = 'products.json';
// Return a promise object
return $http.get(url);
}
.....
$scope.search()
.success(function(data){ // --> data is the products.json
... // handle the successfull call
} );
.error(function(...) {
... // handle the error
} );
// or:
$scope.search().then(
function(data){ // --> data is the products.json
... // handle the successfull call
},
function(...) {
... // handle the error
});
}]);

Categories

Resources