AngularJS: Pass data from Controller to Service - angularjs

First: Here is a plunk.
Currently I am trying to build a basic sign-up app with AngularJS hosted on a SharePoint site. I am pulling the current user data with a factory like so:
app.factory('Data', function ($http, $log) {
return {
getCurrentUser: function (complete, failure) {
jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/currentUser",
type: "GET",
dataType: "json",
headers: {
"Accept": "application/json;odata=verbose"
},
success: function (data) {
complete(data.d);
},
error: function (data) {
failure(data);
}
});
}
I then use a controller to assign the results (in this case the user Title) to a value:
app.controller('IndexCtrl', function ($scope, Data) {
Data.getCurrentUser(function (user) {
CurrentUser = user.Title;
});
Now, the issue I am having is that the value of CurrentUser is not usable in all parts of the factory. Right now, everything is in one factory and one controller. So, I can use CurrentUser to create a new appointment like this:
app.factory('Data', function ($http, $log) {
return {
updateAppointment: function (appointment) {
var Title = appointment.Title;
var Appointment = appointment.Appointment;
var CurrentSpots = appointment.Openings;
var Id = appointment.Id;
// Create new Reservations list item
jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/getByTitle('SharePointList')/Items",
type: "POST",
data: JSON.stringify({
"__metadata": { type: "SP.Data.SharePointListItem" },
Title: Title,
Appointment: Appointment,
Colleague: CurrentUser,
AppointmentId: Id
}),
headers: {
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val()
},
success: function (data, textStatus, jqXHR) {
},
failure: function (jqXHR, textStatus, errorThrown) {
var response = JSON.parse(jqXHR.responseText);
var message = response ? response.error.message.value : textStatus;
alert("Error: " + message);
}
});
But I cannot seem to use it when I try to do a query including that CurrentUser value in something like this:
app.factory('Data', function ($http, $log) {
return {
getCurrentAppointment: function (successCallback) {
$http({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/getByTitle('SharePointList')/Items?$filter=User eq '" + CurrentUser + "'",
method: "GET",
dataType: "json",
async: "true",
headers: {
"Accept": "application/json;odata=verbose"
}
})
.success(function (data, status, headers, config) {
successCallback(data.d.results);
})
.error(function (data, status, headers, config) {
$log.warn(data, status, headers, config);
});
}
No matter what I've tried, it consistently gives me an undefined return for that CurrentUser value. Any help would be appreciated. Thank you in advance!

You don't demonstrate where you are declaring CurrentUser (eg var CurrentUser;) (I couldnt see it).
I trust you are not using a global variable (evil).
Also it is unclear where you are invoking these factory methods that are accessing CurrentUser. You are assigning CurrentUser inside the Data.getCurrentUser invocation in your controller. Assuming you have declared CurrentUser outside that function somewhere, it will not be assigned until the asynchronous request has completed. I'd suggest refactoring your method updateAppointment to receive the CurrentUser parameter instead of relying on outside scope.

Related

return a value from $get factory method when calling service from controller in AngularJs

Im trying to call service from controller which gives me below error..
Provider 'loginService' must return a value from $get factory method.
Below is my code.What is that im doing wrong.
CONTROLLLER CODE
app.controller('loginController', ['$scope', '$http', 'loginService', function ($scope, $http, loginService) {
$scope.checkdata = function () {
var userName = $scope.username;
var password = $scope.password;
//Call the login service
loginService.validateUser(userName, password);
alert(response.data);
}
}])
Service code
app.factory('loginService', function ($http) {
this.validateUser = function (userName, password) {
var userData = new Object();
userData.userName = userName;//Data.username;
userData.password = password;//Data.password;
return $http({
url: "http://localhost:53181/api/User",
dataType: 'json',
method: 'POST',
data: userData,
headers: {
"Content-Type": "application/json"
}
}).then(function (response) {
alert(response);
if (response.data && response.data.data && response.data.data.length == 1)
return response.data.data[0];
});
}
});
Create service funtcion like this:
yourAPICallingFuntion: function() {
var url = "your url";
var deferred = $q.defer();
$http.get(url, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(function(data) {
deferred.resolve(data.data);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
}
In Controller Call like this:
loginService.yourAPICallingFuntion().then(function(data){
//Now this will give you response in form of data
//you can this data according to your requirement
});
factory service is expected to return a value from factory function. It doesn't have this context (it's either window or undefined).
If you want to use this like this.validateUser = ..., use service service instead.

How do I refresh ng-repeat after an Angular Update

Using the code below, I am able to add items in my database, but the table showing the current entries doesn't update (I thought Angular did that automatically?) --- How do I force a refresh of the data?
.controller("addItemsController", function ($scope, $http) {
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('MyContacts')/items";
var vm = $scope;
var requestDigest = $("#__REQUESTDIGEST").val()
vm.addContact = function () {
return $http({
headers: { "accept": "application/json; odata=verbose", "X-RequestDigest": requestDigest, "content-Type": "application/json;odata=verbose" },
method: "POST",
url: url,
data: {
'Title': vm.LastName,
'FirstName': vm.FirstName,
"__metadata": { "type": "SP.Data.MyContactsListItem" }
}
})
.then(saveContact)
.catch(function (message) {
console.log("addContact() error: " + message);
});
function saveContact(data, status, headers, config) {
alert("Item Added Successfully");
return data.data.d;
}
}
})
NOTE: I tried using $scope.contacts.push(data) as suggested elsewhere in the forum, but contacts came back undefined (?!)

Accessing API with $http POST Content-Type application/x-www-form-urlencoded always gets 'false' results

I have the following REST Service which I have to access on POST Method,
I can access it via jQuery but I don't know how to do it with AngularJS (v1)
<string xmlns = "http://schemas.microsoft.com/2003/10/Serialization/">
<script id = "tinyhippos-injected" />
{
"volumeResult": {
"gyydt": "9771241.17704773",
"gytotal": "29864436.1770477",
"gybudgeted": "29864436.1770477",
"lyydt": "10197350",
"lytotal": "27859381",
"lybudgeted": "10197350",
"cyytd": "6992208",
"lastUpdate": "March-2017"
},
"valueResult": {
"gyydt": "26862094",
"gytotal": "68217952",
"gybudgeted": "68232952",
"lyydt": "0",
"lytotal": "0",
"lybudgeted": "0",
"cyytd": "68217952",
"lastUpdate": "March-2017"
},
"trucksResult": {
"gyydt": "165951",
"gytotal": "497879",
"gybudgeted": "497879",
"lyydt": "168822",
"lytotal": "468814",
"lybudgeted": "168822",
"cyytd": "119442",
"lastUpdate": "March-2017"
}
}
</string>
Here is my controller.js:
angular.module('starter.controllers', [])
.controller('DashCtrl', ['$scope', '$http', function ($scope, $http) {
$http({
//headers: {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
headers: {'Content-Type' : 'application/json'},
url: 'https://myurl../api/getHPData',
method: 'POST',
// data: data,
params: {
"stationId": 263,
"crusherId": 27,
"monthYear": '2016-04'
}
})
.then(function (response) {
console.log(response);
})
// I don't have to use .success and .error function as they are [depricated][2]
//.success(function (data, status, headers, config) {
// $scope.greeting = data;
// var Result = JSON.stringify(data);
// var Result = JSON.parse(data);
//})
//.error(function (error, status, headers, config) {
// console.log("====================== Error Status is: " + error);
// console.log("====================== Status is: " + status);
// console.log("====================== Error occured");
//})
}]) // eof controller DashCtrl
.controller('MapsCtrl', function($scope) {})
.controller('AccountCtrl', function($scope) {
$scope.settings = {
enableFriends: true
};
});
What I want is value of:
"volumeResult" > "gytotal"
Problems:
It always return:
Object {data: "{"result":"false"}", status: 200, config: Object, statusText: "OK", headers: function}
and
When I pass monthYear without quotes it process (arithmetic) it as (2016-04 = 2012)
As the service is POST but when I analyze it in Chrome Developers Tool so I get: (Query String, which isn't meant to be POST)
ionic.bundle.js:25005
XHR finished loading: POST
"https://myurl../api/getHPData?crusherId=27&monthYear=2016-4&stationId=263"
Possible solutions:
Either I am using wrong header:
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json'
},
Or header may be,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
Or as per my friend says:
When I change your code to use the code above, I get this error:
"{"Message":"The requested resource does not support http method
'OPTIONS'."}" Which means that there is a CORS (Cross-origin Resource Sharing) issue. Chrome is trying to make a "preflight" request to allow
CORS, but the server doesn't know what to do with it.
But I don't think it is because of this as I am receiving:
Object {data: "{"result":"false"}", status: 200, config: Object,
statusText: "OK", headers: function}
from server. Noted that: {"result":"false"} is the message displayed by the server when it didn't find data or you pass wrong parametes. Also bellow jQuery code is proof that I can access the server. :)
Edit
jQuery Snippet:
<script>
$(document).ready(function() {
get_homepage_data(263, 27, '2016-04');
function get_homepage_data(stationIds, crusherIds, date) {
var url = "https://myurl..";
var data_to_send = {
'stationId': stationIds,
'crusherId': crusherIds,
'monthYear': date
};
console.log("Value is: " + JSON.stringify(data_to_send));
//change sender name with account holder name
// console.log(data_to_send)
$.ajax({
url: url,
method: 'post',
dataType: 'json',
//contentType: 'application/json',
data: data_to_send,
processData: true,
// crossDomain: true,
beforeSend: function () {
}
, complete: function () {}
, success: function (result1) {
// I know I can do it in one line but lazy enough to edit it here :p
var Result = JSON.parse(result1);
var value_data = Result["valueResult"];
var foo = value_data["gyydt"];
console.log("Log of foo is: " + foo);
var foo2 = 0;
// 10 lac is one million.
foo2 = foo / 1000000 + ' million';
console.log(JSON.stringify(value_data["gyydt"]) + " in million is: " + foo2);
}
, error: function (request, error) {
return false;
}
});
}
}); // eof Document. Ready
</script>
Output of above script is script is:
Value is: {"stationId":263,"crusherId":27,"monthYear":"2016-04"}
XHR finished loading: POST "https://myurl../api/getHPData".
Log of foo is: 26862094
"26862094" in million is: 26.862094 million
Which is indeed perfect. :)
try to use $http this way ..
$http.post("https://myurl../..",JSON.stringify({
stationId: 263,
crusherId: 27,
monthYear:'2016-04'
})).then(function(res){
console.log(res);
}).catch(function(errors){
console.log(errors);
})
I got answer. Whao.
Thank you georgeawg for his answer:
He says:
When posting form data that is URL encoded, transform the request with the $httpParamSerializer service:
$http({
headers: {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
url: 'https://myurl..',
method: 'POST',
transformRequest: $httpParamSerializer,
transformResponse: function (x) {
return angular.fromJson(angular.fromJson(x));
},
data: {
"stationId": 263,
"crusherId": 27,
"monthYear": '2016-04'
}
})
.then(function(response) {
console.log(response);
$scope.res = response.data;
console.log($scope.res);
});
Normally the $http service automatically parses the results from a JSON encoded object but this API is returning a string that has been doubly serialized from an object. The transformResponse function fixes that problem.
Now I am able to get value of gytotal as:
var myData = parseFloat(response.data.valueResult.gytotal);
console.log(myData);

AngularJS : factory function undefined in controller

I used to make it work the exact same way before, and it's driving me crazy. I want to perform a $http GET call into a factory and then get back the result into the controller, to be processed.
The factory (don't pay attention to the madness of the request url ):
App.factory('MessageFactory', function ($http) {
var MessageFactory = {
getCast: function () {
var request = {
method: "GET",
url: spHostUrl + "/_api/web/Lists/getByTitle('" + listTitle + "')/items?$select=AuthorId,Author/Name,Author/Title,Type_x0020_message,Title,Modified,Body,Expires,Attachments&$expand=Author/Id",
headers: {
"Content-Type": "application/json;odata=verbose",
"Accept": "application/json;odata=verbose"
}
};
$http(request)
.then(function (res) {
return res.data;
}).catch(function (res) {
console.error("error ", res.status, res.data);
}).finally(function () {
console.log("end");
});
}
};
return MessageFactory;
});
Now the controller :
App.controller('MessageController', function ($scope, $http, $log, $attrs, MessageFactory) {
$scope.messages = MessageFactory;
MessageFactory.getCast().then(function (asyncCastData) {
$scope.messages.cast = asyncCastData;
});
$scope.$watch('messages.cast', function (cast) {
//do stuff
});
});
When I test it I get the following error :
Error: MessageFactory.getCast(...) is undefined
#/Scripts/App.js:167:9
The line 167 is indeed this line in the controller
MessageFactory.getCast().then(function (asyncCastData) {
My app works fine for any other feature, so my issue appeared when adding this part, and I'm pretty sure my controller doesn't know my factory yet and thus try to access to his function. As it's an asynchronous call, it should work with the code in the controller. I need your help on this, thanks.
You must be getting .then of undefined error
Because you missed to return promise from service method.
Service
var MessageFactory = {
getCast: function() {
var request = {
method: "GET",
url: spHostUrl + "/_api/web/Lists/getByTitle('" + listTitle + "')/items?$select=AuthorId,Author/Name,Author/Title,Type_x0020_message,Title,Modified,Body,Expires,Attachments&$expand=Author/Id",
headers: {
"Content-Type": "application/json;odata=verbose",
"Accept": "application/json;odata=verbose"
}
};
return $http(request) //returned promise from here
.then(function(res) {
return res.data;
}).catch(function(res) {
console.error("error ", res.status, res.data);
}).finally(function() {
console.log("end");
});
}
};

Angular Factory to share web api 2 token with multiple controllers

I am trying to create a factory that gets a token from a web api and then shares that token with multiple controllers. I've tried my best to create the factory and inject it into the controller but I am not sure if I am doing this correctly yet? I'm getting an angular 'unknown provider' error. Please advise, new to angular. Thank you.
securityApp.factory('getToken', function ($scope, $http) {
var token = "";
$http({
method: 'POST', url: 'http://localhost:62791/token', data: { username: $scope.userName, password: $scope.password, grant_type: 'password' }, transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
}
}).success(function (data, status, headers, config) {
token = data.access_token;
return token;
});
});
securityApp.controller('membersController', function ($scope, $http, getToken) {
$http({ method: 'GET', url: '/api/Members/?access_token=' + getToken.token, headers: { 'Authorization': 'Bearer ' + getToken.token } })
.then(function (response) {
$scope.members = response.data;
});
});
A service can't be injected with $scope. Only controllers can. The only scope that can be injected in a service is the $rootScope. You need to pass the user name and the password to your service when calling it. It can't bet the user name and password from nowhere.
PS: when you ask about an error, post the complete and exact error message.
Your factory not return any thing (Read this). Its should be like this
securityApp.factory('getToken', function ($scope, $http) {
return {
getAccessToken: function () {
$http({
method: 'POST', url: 'http://localhost:62791/token', data: { username: $scope.userName, password: $scope.password, grant_type: 'password' }, transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
}
}).success(function (data, status, headers, config) {
return data.access_token;
});
},
};
});
and call it in your controller like below.
securityApp.controller('membersController', function ($scope, $http, getToken) {
$scope.token = getToken.getAccessToken();
$http({ method: 'GET', url: '/api/Members/?access_token=' + $scope.token, headers: { 'Authorization': 'Bearer ' + $scope.token } })
.then(function (response) {
$scope.members = response.data;
});
});
Update:
To solve the error: "Error: [$injector:unpr] Unknown provider change the code
securityApp.controller('membersController', ['$scope', '$http','getToken', function ($scope, $http, getToken) {
$scope.token = getToken.getAccessToken();
$http({ method: 'GET', url: '/api/Members/?access_token=' + $scope.token, headers: { 'Authorization': 'Bearer ' + $scope.token} })
.then(function (response) {
$scope.members = response.data;
});
} ]);
Demo Sample

Resources