Related
angular.module('snswMock').factory('snswService', ['$http','$location' ,
function ($http, $location ) {
'use strict';
return {
getData: function(jsonData){
var jsonString = JSON.stringify(jsonData);
var serviceUrl = getServiceUrl();
$http({
url: serviceUrl,
dataType: 'string',
method: 'POST',
data: jsonString
}).success(function(response){
alert ("Success");
}).error(function(error){
alert ("Save company!");
});
},
getServiceUrl :function(){
var host = $location.host();
if (host === 'localhost') {
return $location.protocol() + '://' + host + ':9000/services/insert';
} else {
return $location.protocol() + '://' + host + '/services/insert';
}
}
}
}
]);
Hi am very new to the angular
this is my service
I am calling getServiceUrl inside getData function i am getting the below error
angular.js:11706 ReferenceError: getServiceUrl is not defined
can anyone please help me how can I call the method. is there any other way is there to call web service by passing a string as post request?
The controller where you are trying to access this service, do below things.
Inject this service in the controller.
Call this service like below
snswService.getServiceUrl();
You need to use this context to access a global object function -> this.getServiceUrl(). In your case myFactory is the object and inside your object all functions are globally accessible inside your object scope by using this context.
angular.module('snswMock').factory('snswService', ['$http', '$location', function($http, $location) {
'use strict';
var myFactory = {
getData: function(jsonData) {
var jsonString = JSON.stringify(jsonData);
var serviceUrl = this.getServiceUrl(); //modified
$http({
url: serviceUrl,
dataType: 'string',
method: 'POST',
data: jsonString
}).success(function(response) {
alert("Success");
}).error(function(error) {
alert("Save company!");
});
},
getServiceUrl: function() {
var host = $location.host();
if (host === 'localhost') {
return $location.protocol() + '://' + host + ':9000/services/insert';
} else {
return $location.protocol() + '://' + host + '/services/insert';
}
}
}
return myFactory;
}]);
Below is my code
<script>
var app = angular.module("myApp2", [])
app.controller("ShowController", ['$scope', function ($http) {
$scope.Get = function () {
var adata = { EmpId: 'EmpId' };
var JSon = JSON.stringify(adata);
EmpId = $("#EmpIdb").val();
$http({
method: "Get",
url: servUrl + "Show",
data: JSon,
}).then(function mySucces(response) {
alert(response.data);
}, function myError(error) {
alert(response.statusText);
});
}
}])
</script>
</title>
</head>
<body ng-app="myApp2" ng-controller="ShowController">
<center>
<h3> Please Enter Your Emp Id</h3></br>
<input type ="text" id="EmpIdb" /></br>
<input type="button" id ="Fetch" value="Fetch Details" ng-click="Get();"/>
<div ng-view></div>
</center>
which is not working.
There is no error in the console and I am not able to debug it either.
Any help welcomed
There are multiple problems. But I do not really get why error is not coming
1 . Where is the servUrl coming from?
2 .
$http({
method: "Get",
url: servUrl + "Show",
data: JSon,
})
to
$http({
method: "GET",
url: servUrl + "Show",
data: JSon,
})
3 . Change this in 3rd line
app.controller("ShowController", ['$scope', function ($http) {
to
app.controller("ShowController", ['$scope', '$http', function ( $scope, $http) {
Fix these. then try again.
EDITED
DEMO Plunker with working code.
Change your code like below. You are not passing scope in controller function.
<script>
var app = angular.module("myApp2", [])
app.controller("ShowController", ['$scope', '$http', function ($scope, $http) {
$scope.Get = function () {
var adata = { EmpId: 'EmpId' };
var JSon = JSON.stringify(adata);
EmpId = $("#EmpIdb").val();
$http({
method: "GET",
url: servUrl + "Show",
data: JSon,
}).then(function mySucces(response) {
alert(response.data);
}, function myError(error) {
alert(response.statusText);
});
}
}])
</script>
Try this. just inject $scope and $http in your controller
var app = angular.module("myApp2", [])
app.controller("ShowController", ['$http', '$scope', function ($http, $scope) {
$scope.Get = function () {
var adata = { EmpId: 'EmpId' };
var JSon = JSON.stringify(adata);
EmpId = $("#EmpIdb").val();
$http({
method: "Get",
url: servUrl + "Show",
data: JSon,
}).then(function mySucces(response) {
alert(response.data);
}, function myError(error) {
alert(response.statusText);
});
}
}])
I've set a factory with callback for success and error. However when I use it in the controller I need to alway define both success and error functions if I don't define a error callback function, it won't work.
Is there anyways that could make error callback optional when it needs to be use.
Controller
$scope.saveUsername = function(){
atFactory.saveUsername($scope, function(){
// this is success
}, function(){
// this is error
});
}
Factory
at.factory('atFactory', ['$http' , function ( $http ){
var factory = {};
factory.saveUsername = function($scope,callback){
$scope.url = '/member/username';
$scope.post_data = {
username : $scope.username
};
factory.doPostHttpRequest($scope).success(callback).error(callback);
}
factory.doPostHttpRequest = function($scope){
return $http({
url : $scope.url,
method: 'POST',
data: $scope.post_data
})
}
return factory;
}]);
My suggestion to you is to return the $http promise back to the controller, then you can call the success() in your controller (and optionally error()).
So in your factory:
factory.saveUsername = function($scope){
$scope.url = '/member/username';
$scope.post_data = {
username : $scope.username
};
return factory.doPostHttpRequest($scope);
}
factory.doPostHttpRequest = function($scope){
return $http({
url : $scope.url,
method: 'POST',
data: $scope.post_data
})
}
Then in your controller, you can do:
atFactory.saveUsername($scope)
.success(function(response) {
// success callback (optional)
})
.error(function(error) {
// error callback (optional)
});
you can use :
at.factory('atFactory', ['$http' , function ( $http ){
var factory = {};
factory.saveUsername = function($scope,successCallBack, errorCallBack){
$scope.url = '/member/username';
$scope.post_data = {
username : $scope.username
};
return factory.doPostHttpRequest($scope).success(function(){
if(successCallBack){
successCallBack();
}
}).error(function(){
if(errorCallBack){
errorCallBack();
}
});
}
factory.doPostHttpRequest = function($scope){
return $http({
url : $scope.url,
method: 'POST',
data: $scope.post_data
})
}
return factory;
}]);
I'm trying to create a service from a $resource, because the request needs authentication, I'm sending an Authorization header.
So I have 2 services:
authService
userInforService
authService:
var ouveerApiServices = angular.module('ouveerServices.api', []);
ouveerApiServices.factory('authService', ['$http', '$rootScope', 'localStorageService', 'apiService',
function($http, $rootScope, localStorageService, apiService){
return {
isLogged : function(){
return (localStorageService.get('accessToken')) ? true : false;
},
logIn : function(email, password){
var dataQuery = $.param({
grant_type: "password",
username : email,
password : password
});
return $http({
url: $rootScope.apiURL + 'Auth',
method: 'POST',
data : dataQuery,
withcredentials : true,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
}
});
},
logOut : function(){
return apiService.post({ url: 'api/Account/Logout' });
},
getAccessToken : function(){
return localStorageService.get('accessToken');
}
} //return
} //function
]);
And the userInfoService:
var ouveerUserServices = angular.module('ouveerServices.user', []);
//user related queries
ouveerApiServices.factory('userInfoService', ['$resource', '$rootScope', 'localStorageService', 'authService',
function($resource, $rootScope, localStorageService, authService){
return $resource($rootScope.apiURL + 'api/users/:userId', { userId : '#id' }, {
update : {
method: 'PUT',
isArray : false
},
account : {
method : 'GET',
isArray : false,
url: $rootScope.apiURL + 'api/Account/UserInfo',
headers : {
'Authorization' : 'Bearer ' + authService.getAccessToken()
}
}
});
}
]);
The problems is at the time I call (in a controller):
$scope.signIn = function(){
$scope.messages = [];
console.log($scope.user.semail);
if($scope.user.semail && $scope.user.spassword){
authService.logIn($scope.user.semail, $scope.user.spassword).success(function(data){
localStorageService.add('accessToken', data.access_token);
console.log(authService.getAccessToken());
//setting userID in localstorage
userInfoService.account(function(){
localStorageService.add('userId', userData.userId);
$location.path('/library');
});
}).error(function(){
$scope.status = 'error';
$scope.messages[0] = ['Review the fields please, something is wrong...'];
});
} else {
$scope.status = 'error';
$scope.messages[0] = ['Type your email and password.'];
}
}
It returns null, but as you note I'm dumping the var just before the call of userInfoService and it response the Auth code, anything I'm doing wrong?
Note that you initialize the account property in following way:
account : {
method : 'GET',
isArray : false,
url: $rootScope.apiURL + 'api/Account/UserInfo',
headers : {
'Authorization' : 'Bearer ' + authService.getAccessToken()
}
}
This code (including authService.getAccessToken()) is run upon the creation of the service, i.e long before the code in the controller. Hence, authService.getAccessToken() is resolved, and at that point in time it is null.
To put another way, when you try to actually use the header in the account resource, it is just a string, created long ago.
Some time ago, I setup an abstract data factory in AngularJS, and need a hint on how to simplify its use. I was initially under the impression that I would create another factory per entity that would be called from an AngularJS controller. Turns out it just looks too complicated and I would like to remove the intermediary entity factory (ContentTypesFactory), and simply call the abstract factory directly from the AngularJS controller.
In the following example I'm wiring up a KendoUI datasource.
AbstractRepository.js:
app.factory('abstractRepository', [function () {
// we will inject the $http service as repository service
// however we can later refactor this to use another service
function abstractRepository(repositoryService, whichEntity, odataUrlBase) {
//this.http = $http;
this.http = repositoryService;
this.whichEntity = whichEntity;
this.odataUrlBase = odataUrlBase;
this.route;
}
abstractRepository.prototype = {
getList: function () {
return this.http.get(this.odataUrlBase);
},
get: function (id) {
return this.http.get(this.odataUrlBase + '/' + id);
},
insert: function (entity) {
return this.http.post(this.odataUrlBase, entity);
},
update: function (entity) {
return this.http.put(this.odataUrlBase + '/' + entity.ID, this.whichEntity);
},
remove: function (id) {
return this.http.delete(this.odataUrlBase + '/' + id);
}
};
abstractRepository.extend = function (repository) {
repository.prototype = Object.create(abstractRepository.prototype);
repository.prototype.constructor = repository;
}
return abstractRepository;
}]);
ContentTypesFactory.js:
/// <reference path="../Scripts/angular.min.js" />
/// <reference path="../app.js" />
/// <reference path="AbstractRepository.js" />
// each function returns a promise that can be wired up to callback functions by the caller
// the object returned from the factory is a singleton and can be reused by different controllers
app.factory('contentTypesRepository', ['$http', 'abstractRepository', function ($http, abstractRepository) {
var odataUrlBase = '/odata/ContentTypes'
var whichEntity = 'ContentTypes';
function contentTypesRepository() {
abstractRepository.call(this, $http, whichEntity, odataUrlBase);
}
abstractRepository.extend(contentTypesRepository);
return new contentTypesRepository();
}]);
ContentTypesController.js:
app.controller('contentTypesController', ['$scope', '$log', 'contentTypesRepository',
function ($scope, $log, contentTypesFactory) {
$scope.odataUrlBase = '/odata/ContentTypes';
$scope.status;
//
// Grid
//
$scope.contentTypesDataSource = new kendo.data.HierarchicalDataSource({
type: "odata",
transport: {
create: {
url: $scope.odataUrlBase
},
read: {
type: "GET",
url: $scope.odataUrlBase,
//function (data) {
// pass in the URL to the abstract factory
//},
dataType: "json" // the default result type is JSONP, but WebAPI does not support JSONP
},
update: {
contentType: "application/json",
url: function (data) {
return $scope.odataUrlBase + '(' + data.ContentTypesId + ')';
} . . .
Now, removing the reference to ContentTypesFactory, my new controller code looks like this:
app.controller('contentTypesController', ['http', '$scope', '$log', 'abstractDataFactory',
// the abstract data factory accepts controller type parameters for RESTful CRUD
function ($scope, $log, abstractDataFactory) {
//function ContentTypeController($scope) {
var crudServiceBaseUrl = "/odata/ContentTypes";
var odataUrlBase = '/odata/ContentTypes'
var whichEntity = 'ContentTypes';
// Pulled the following code from the ControlerTypesFactory, but not sure how to implement it in this ContentTypesController:
//function contentTypesRepository() {
// abstractRepository.call(this, $http, whichEntity, odataUrlBase);
//}
//abstractRepository.extend(contentTypesRepository);
//return new contentTypesRepository();
$scope.greeting = 'Hola!';
var dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
url: crudServiceBaseUrl,
dataType: "json"
},
update: { // PUT
url: function (data) {
console.log(data);
dataType: "json"
return crudServiceBaseUrl + "(" + data.ContentTypeId + ")";
},
error: function (e) {
console.log("error: " + e);
}
}, . . .
I'm sure the change is not that difficult, but I'm fairly new to Angular. How can I wire this up so to use the abstract repository, and looking for any other Angular best-practices and naming suggestions?
Taking a fresh look at this this morning, I believe I have a working solution.
Once again, I wanted to remove the intermediary factory abstraction, and have only one abstract data fetching factory that I could pass in parameters directly from from each controller.
$http is injected into the factory which takes in two parameters whichEntity, odataUrlBase, and are set upon instantiation. The factory exposes methods like getList(odataOptions). It is these options that are required to to be passed along with the requests as part of the query string, and are done so through $http's params.
The new abstract factory is injected into the controller, then instantiated with the required parameters:
app.controller('contentTypeController', ['$scope', '$log', 'abstractFactory3',
function ($scope, $log, abstractFactory3) {
var dataFactory = new abstractFactory3("ContentType", "/odata/ContentType");
Here is the new abstract factory:
app.factory('abstractFactory3', function ($http) {
function abstractFactory3(whichEntity, odataUrlBase) {
this.whichEntity = whichEntity;
this.odataUrlBase = odataUrlBase;
}
abstractFactory3.prototype = {
getList: function (odataOptions) {
//var result = $http({
// url: this.odataUrlBase,
// method: 'GET',
// params: odataParams
//});
return $http.get(this.odataUrlBase, {
params: odataOptions
});
}
};
return abstractFactory3;
});
Since this is being used through through a kendo.data.DataSource, we have to extract the OData parameters:
var odataParams = kendo.data.transports["odata"].parameterMap(options.data, "read");
Upon a successful get, we pass back the data source's options with the result:
var dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read:
function (options) {
var odataParams = kendo.data.transports["odata"].parameterMap(options.data, "read");
dataFactory.getList(odataParams)
.success(function (result) {
options.success(result);
});
//$http({ // // example of using $http directly ($http injection was removed from this controller, as this is now handled by the abstract data factory)
// url: crudServiceBaseUrl,
// method: 'GET',
// params: odataParams
//})
//.success(function (result) {
// options.success(result);
//});
}, // update, create, destroy, . . .
I realize that in my original question, the controller was in fact using the Kendo transport, rather than the Angular factory that I had setup.
So what I have now is:
angular controller (KendoUI datasource) -> angular data factory
I have also reworded the question in order to more-accurately reflect what the entire problem was, and hope this is of assistance to someone.
There are some other little nuances, like getting and passing data ID's, objects, JSON.stringification that are best shown in a full solution. Hopefully the following helps:
AngularJS abstract data factory:
app.factory('abstractFactory3', function ($http) {
function abstractFactory3(odataUrlBase) {
this.odataUrlBase = odataUrlBase;
}
abstractFactory3.prototype = {
getList: function (odataOptions) {
//var result = $http({
// url: this.odataUrlBase,
// method: 'GET',
// params: odataParams
//});
return $http.get(this.odataUrlBase, {
params: odataOptions
});
},
get: function (id, odataOptions) {
return $http.get(this.odataUrlBase + '/' + id, {
params: odataOptions
});
},
insert: function (data) {
return $http.post(this.odataUrlBase, data);
},
update: function (id, data) {
return $http.put(this.odataUrlBase + '(' + id + ')', data);
},
remove: function (id) {
return $http.delete(this.odataUrlBase + '(' + id + ')');
}
};
return abstractFactory3;
});
AngularJS Controller:
app.controller('contentTypeController', ['$scope', '$log', 'abstractFactory3',
// the abstract data factory accepts controller type parameters for RESTful CRUD
function ($scope, $log, abstractFactory3) {
var dataFactory = new abstractFactory3("/odata/ContentType");
var crudServiceBaseUrl = "/odata/ContentType";
var dataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read:
function (options) {
var odataParams = kendo.data.transports["odata"].parameterMap(options.data, "read");
dataFactory.getList(odataParams)
.success(function (result) {
options.success(result);
})
.error (function (error) {
console.log("data error");
});
},
update:
function (options) {
var data = options.data;
dataFactory.update(data.ContentTypeId, data)
.success(function (result) {
options.success(result);
})
.error(function (error) {
console.log("data error");
});
},
create:
function (options) {
var data = options.data;
data.ContentTypeId = "0"; // required for valid field data
dataFactory.insert(data)
.success(function (result) {
options.success(result);
})
.error(function (error) {
console.log("data error");
});
},
destroy:
function (options) {
var data = options.data;
dataFactory.remove(data.ContentTypeId)
.success(function (result) {
options.success(result);
})
.error(function (error) {
console.log("data error");
});
},
parameterMap: function (options, type) {
// this is optional - if we need to remove any parameters (due to partial OData support in WebAPI
if (operation !== "read" && options.models) {
return JSON.stringify({ models: options });
}
},
},
batch: false,
pageSize: 10,
serverPaging: true,
change: function (e) {
console.log("change: " + e.action);
// do something with e
},
schema: {
data: function (data) {
//console.log(data)
return data.value;
},
total: function (data) {
console.log("count: " + data["odata.count"]);
return data["odata.count"];
},
model: {
id: "ContentTypeId",
fields: {
ContentTypeId: { editable: false, nullable: true },
//UserId: {editable: false, nullable: false },
Description: { type: "string", validation: { required: true } },
//msrepl_tran_version: { type: "string", validation: { required: true } }
}
}
},
error: function (e) {
//var response = JSON.parse(e.responseText);
var response = e.status;
console.log(response);
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 400,
toolbar: ["create"],
columns: [
{ field: "ContentTypeId", editable: false, width: 90, title: "ID" },
{ field: "Description", title: "Content Type" },
{ command: ["edit", "destroy"] }
],
editable: "inline"
});
}]);
You mention best practices, I think it's better to leave your data source and manipulation in a factory or service like the data factories you had. Here's some specific references:
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/#/keep_controllers_simple
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/#/business_logic