Working with OfflineJS and AngularJS - javascript

I am working on an angular app where I want to integrate OfflineJS functionality.
I have created a general service for getting and posting data to/from an API,and a specific service for each module.
Here is the code
app.service('MethodProvider', function ($http) {
var self = this;
self.get = function (url) {
var obj = {
url: url,
method: 'GET',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.post = function (url, data) {
var obj = {
url: url,
method: 'POST',
async: true,
data: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.put = function (url, data) {
var obj = {
url: url,
method: 'PUT',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.data = JSON.stringify(data);
}
return $http(obj);
};
self.delete = function (url) {
var obj = {
url: url,
method: 'POST',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
return self;
});
And a specific module service like User module
app.service('UserSrvc', function (MethodProvider) {
var self = this;
self.create = function (data) {
var url = apiUrl + '/user/add';
return MethodProvider.post(url, data);
};
return self;
});
How do I integrate OfflineJS in this code , I want to intercept HTTP request when network connectivity is down and resume requests when network connectivity is up . I have studied this example but unable to integrate this in angular need an example to get started.

hope this helps the future users:
Offlinejs adds Offline object to the global window object.
Offlinejs does not trigger check() by itself (it does it once if checkOnLoad option is set to true).
You may call Offline.check() just before you make an ajax request to your server and check for connection.
You can also do polling, if your app is xhr intensive.
var run = function(){
if(Offline.state=="up")
Offline.check();
};
setInterval(run, 20000); // check after 20sec
Offline.on('down',function(){ /**code to handle network down*/ });
As pointed by #Adnan Umer You need to set Offline.options = { interceptRequests: true, requests: true }
to intercept failed requests and try again once connection is back.
One caveat here is that the requests resent by Offline will be out of the scope of Angular, accordingly, all the GET requests will result to nothing. Which is actually fine, usually the user initiates the get requests.
Offline.options = {
checks: {xhr: {url: "put_url_to_check_status_of_your_server"}}
}
By default, Offlinejs checks for favicon.ico.

Related

Adaptation to previous question, ReferenceError: object is not defined

The previous question was marked as a duplicate, with the link leading me here: How do I return the response from an asynchronous call?.
I still couldn't find a solution, but I guess i will need AJAX to return this object, because my functions/GET Request hasn't completed, which leads me to a new question. How can I adapt this to return asynchronously. I understand the concepet of Promises and async/await, but I'm unsure how I can implement this here so I can access the object globally.
[Original Question]
Returning object from the below function, but I'm receiving this error ReferenceError: object is not defined. I would like to access this globally, but can't seem to access the object because of scope. Is there something that I'm missing?
When setting a global variable, this doesn't seem to update.
For example setting var globalObject = {}; outside and using globalObject = object inside the object doesn't seem to change the variable {}
function getTicket (ticketID) {
var urlID = contentID;
var request = require("request");
var options = {
method: 'GET',
url: `https://www.mywebsite.com/api/${urlID}/body.json`,
headers: {'content-type': 'application/json', authorization: 'Basic PASSWORD=='}
};
request(options, function (response, body) {
var obj = JSON.parse(JSON.stringify(body));
var objContent = JSON.parse(obj.body);
var object = {
id: urlID,
url: 'https://www.mywebsite.com/api/' + urlID,
value: objContent
};
console.log(object.id);
console.log(object.url);
console.log(objContent.body[0].body);
});
return object;
}
getTicket(380289);
You can convert your function to return a promise and then use await when calling it:
function getTicket(ticketID) {
var urlID = contentID;
var request = require('request');
var options = {
method: 'GET',
url: `https://www.mywebsite.com/api/${urlID}/body.json`,
headers: { 'content-type': 'application/json', authorization: 'Basic PASSWORD==' }
};
return Promise(resolve => {
request(options, function(response, body) {
var obj = JSON.parse(JSON.stringify(body));
var objContent = JSON.parse(obj.body);
var object = {
id: urlID,
url: 'https://www.mywebsite.com/api/' + urlID,
value: objContent
};
console.log(object.id);
console.log(object.url);
console.log(objContent.body[0].body);
resolve(object);
});
});
}
await getTicket(380289);
Note that your call will need to happen in an async scope. If you are in the global scope, you can use:
(async function() {
await getTicket(380289);
})();
See using await on global scope without async keyword for more details

How to send a rest PUT request in angular passing body

I need to send a rest request to a web server, I am using this code :
var getData = function(...) {
return $http({
method: "PUT",
url: getStatistics,
headers: {
'loginId': ...,
'token': ...,
'Content-Type': 'application/x-www-form-urlencoded',
},
data: {"...":"...","...":"...","...":"...","...":"...",
"...":"....","....":"...",
"datefrom":"2017-01-01","dateto":"2017-10-20"}
}).then(function(result){
var dataString = JSON.stringify(result.data);
alert(result.data);
return result.data;
});
};
The problem is that I am receiving error 400 bad request, What should I do?
The request works on Postman With this structure
https://i.stack.imgur.com/BBrwF.jpg
https://i.stack.imgur.com/NbQuO.jpg
Should it be a problem of how Am I passing the data object ?
That's how I implemented the $httpParamSerializerJQLike, it it Correct?
app.factory('statistics', function($http,$httpParamSerializerJQLike) {
var getData = function(loginId,token,id,dataInizio,dataFine,periodo,selezione) {
// Angular $http() and then() both return promises themselves
var data = '{"datefrom":"2017-01-01","dateto":"2017-10-20"}';
alert(data);
return $http({
method: "PUT",
url: getStatistics,
headers: {
'loginId': loginId,
'token': token,
'Content-Type': 'application/x-www-form-urlencoded',
},
data: { 'data': $httpParamSerializerJQLike(data)}
}).then(function(result){
var dataString = JSON.stringify(result.data);
alert(result.data);
return result.data;
});
};
return { getData: getData };
});
you're sending an x-www-form-urlencoded body, but it contains a single parameter named data, containing JSON.
You thus need
data: $httpParamSerializerJQLike({data: angular.toJson(data)})

Make another ajax call to get headers before each actual ajax call - jquery

I have to make an async call which uses cookie to get bearer token which has to be passed to make actual ajax call for the resource.
And I have written the following code which works awesome and get's me the result.
Can I use ajaxPrefilter or beforeSend options to get the tokens, I tried to find documentation for ajaxPrefilter which says it accepts a function, but does that waits for that function to be finished before making actual call?
Token retrieval function
function getTokenUsingCookieAsync() {
return new Promise(function (resolve, reject) {
$.ajax('/retrieve-token').done(function (result) {
resolve(result.token);
}).fail(function (message) {
reject(message);
});
});
}
Actual execute function:
function execute(url, method, data) {
var deferred = $.Deferred();
getTokenUsingCookieAsync().then(function (response) {
var reqSettings = {
async: true,
url: url,
cache: false,
type: method,
headers: {
Authorization: 'Bearer '+ response,
},
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: data ? JSON.stringify(data) : null
};
$.ajax(reqSettings).done(function (result) {
deferred.resolve(result);
}).fail(function (message) {
deferred.reject(message);
});
}).catch(function (message) {
deferred.reject(message);
});
return deferred.promise();
}
So the following pseudo code is possible or not?
$.ajaxPrefilter((options) => {
$.ajax('/retrieve-token').done((result) => {
options.headers = {
Authorization: `Bearer ${result}`
};
});
});
$.ajax('actual-url')
.done(whatever);

Angular JS methods - One depending on result of another

I have an AngularJS (v1.5) client that is used to schedule an Operating Room at a hospital. The app has a single controller and two functions within that controller. These two functions are both $http POST requests.
The first method called (requestAccessToken) passes a username, password, and grant_type to receive back an OAuth 2 access token which is then assigned to a variable on the scope. This works fine.
The second method (scheduleORSuite) makes an API call passing the access token obtained from the first method (requestAccessToken) . The problem is that when the method () executes the access token is null. I know I am receiving back a valid access token because when I call the method requestAccessToken directly I get back a valid access token. When I step through the debugger in Chrome it looks like the method (scheduleORSuite), that uses the access token, does not even wait for the method that obtains the access token to return.
<script type="text/javascript">
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function ($scope, $http) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
// This method requests the access token
viewModel.requestAccessToken = function () {
$http({
method : 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(_requestAccessTokenSuccess, _requestAccessTokenError);
};
// This method contacts the API endpoint the schedule an OR suite
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken();
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method : 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data : angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
};
// Called when request for access token is successful
function _requestAccessTokenSuccess(response) {
viewModel.tokenDisplay = response.data;
};
// Called when request for access token results in error
function _requestAccessTokenError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
</script>
Here is the HTML form that makes use of the controller.
<form ng-submit="viewModel.scheduleORSuite()" novalidate>
...
...
</form>
Is there a way to make the second method (scheduleORSuite) wait until the first method (requestAccessToken) completes? The access token is required in order to call the API to schedule an OR suite.
$http is an async method, so you need to use callbacks
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function($scope, $http) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
viewModel.requestAccessToken = function() {
viewModel._requestAccessToken().then(_requestAccessTokenSuccess, _requestAccessTokenError);
};
viewModel.scheduleORSuite = function() {
if (viewModel.accessToken) {
viewModel._scheduleORSuite.then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
} else {
viewModel._requestAccessToken().then(function(response) {
viewModel.tokenDisplay = response.data;
viewModel._scheduleORSuite.then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, _requestAccessTokenError);
}
};
// This method contacts the API endpoint the schedule an OR suite
viewModel._scheduleORSuite = function() {
return $http({
method: 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data: angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
});
};
// This method requests the access token
viewModel._requestAccessToken = function() {
return $http({
method: 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
};
// Called when request for access token is successful
function _requestAccessTokenSuccess(response) {
viewModel.tokenDisplay = response.data;
};
// Called when request for access token results in error
function _requestAccessTokenError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
It's because your requestAccessToken() method contains a promise, and JavaScript won't wait for this to complete before carrying on with the rest of the code.
The best thing to do would be to return the promise from requestAccessToken() for use in scheduleORSuite()
viewModel.requestAccessToken = function () {
return $http({
method : 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
};
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken().then(function(response) {
viewModel._requestAccessTokenSuccess(response);
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method : 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data : angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, _requestAccessTokenError);
};
I've also noticed though that the variable you're checking for your access token, viewModel.accesstoken, is being set until the _scheduleORSuiteSuccess() function? I'm presuming this is an error and it should be set in _requestAccessTokenSuccess() instead?
What you want todo is make sure the request returns with the access token first, then make the second request. Todo that, use a promise. the $q library works well for this. See viewModel.requestAccessTokenfor the changes I made.
<script type="text/javascript">
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function($scope, $http, $q) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
// This method requests the access token
viewModel.requestAccessToken = function() {
var defer = $q.defer();
$http({
method: 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
viewModel.tokenDisplay = response.data;
defer.resolve(); //fullfills the promise
}, function(err) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
defer.reject(); //rejects the promise
});
return $q; //returns a promise
};
// This method contacts the API endpoint the schedule an OR suite
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken().then(function() {
//On fullfillment of the promise from requestAccessToken...
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method: 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data: angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, function() {
//Error occured in requestAccessToken();
})
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
</script>

Using $http.get to retrieve from API(zendesk) not working

I'm trying to make an API call to Zendesk's API and I keep getting a 401 auth code even though the same thing works when I do a cURL in terminal. How can I make this work in Angular?
function dataservice($http) {
var service = {
getMacros: getMacros
};
return service;
/////////////////////
function getMacros() {
var client = {
username: window.btoa('myEmail'),
token: window.btoa('/token:myToken'),
remoteUri: 'https://myCompany.zendesk.com/api/v2/macros.json'
};
console.log('Loading...');
return $http({
method: 'GET',
url: client.remoteUri,
headers: {
'Authorization': client.username + client.token
}
})
.then(getMacrosComplete)
.catch(function (message) {
exception.catcher('Failed to getMacros')(message);
});
function getMacrosComplete(response) {
console.log('Done');
var data = response.data;
return data;
};
};
The code above always returns a 401 while this works:
curl myEmail/token:myToken https://myCompany.zendesk.com/api/v2/macros.json
Seems to work well. Probably something obvious.
The thing is you need to set Authorization headers properly, they should be Base64 encoded and you have to state "Basic" authentication (this is the main part most people miss).
So this should work:
function dataservice($http) {
var service = {
getMacros: getMacros
};
return service;
/////////////////////
function getMacros() {
var client = {
username: 'myEmail',
token: 'myToken',
remoteUri: 'https://myCompany.zendesk.com/api/v2/macros.json'
};
console.log('Loading...');
return $http({
method: 'GET',
url: client.remoteUri,
headers: {
'Authorization': 'Basic ' + window.btoa(client.username + '/token:' + client.token)
}
})
.then(getMacrosComplete)
.catch(function (message) {
exception.catcher('Failed to getMacros')(message);
});
function getMacrosComplete(response) {
console.log('Done');
var data = response.data;
return data;
};
};
Of course you have to have token authentication enabled in your Zendesk account, otherwise you can authenticate via user + password by setting up a password instead and doing:
'Authorization': 'Basic ' + window.btoa(client.username + ':' + client.password)

Categories

Resources