I've got a small angulaerjs app that uses angularjs resource in one of it's controllers. Here is the code for resource usage
$scope.getFilteredTasks = function (filter) {
var resource = $resource('{0}/api/orderTasks/filterTasks'.format($scope.baseUrl), { status: '#status', type: '#type', createdDate: '#createdDate', agentType: '#agentType', page: '#page', pageSize: '#pageSize' }, {
'response': { method: 'GET', isArray: false }
});
$('#loading').show();
resource.response({
status: filter.status,
type: filter.type,
createdDate: filter.createdDate,
agentType: filter.agentType,
page: $scope.currentPage,
pageSize: $scope.pageSize
},
function (result) {
$scope.resultTasks = result.Items;
if ($scope.totalItems != result.TotalCount)
$scope.totalItems = result.TotalCount;
$('#loading').hide();
},
function (result) {
$('#loading').hide();
alert('Error in request!')
});
};
When the page first load everything is fine and i get all data that i need. But when I make second request (for example push the button on page that calls getFilteredTask(filter) function). I've got an result.status = -1. According to Fiddler and Chrome Network tab in dev tools request has status 200 but was cancelled. I've also checked the backend and found no problems, request was succsessfully handled and server returned all data that I need but I get cannceled request on client side.
UPDATE
It loooks like this problem appears only in Chrome. In IE 11 for example everything is ok
the issue might be that you were making the ajax request from a link, and not preventing the link from being followed. So if you are doing this in an onclick attribute, make sure to return false; as well.
Related
We've got this rather large'ish and old'ish asp web application, that started to behave poorly because of (as i understand) XHR requests in beforeunload event handler. There is quite a logic tied to this, so i cannot just throw it away.
The code in beforeunload was like this:
$(window).on('beforeunload', function () {
$.ajax('/site/$hdr/unload', { async: true, cache: false });
});
and in server side something like this:
private class HttpModule : IHttpModule
{
private static void PostAcquireRequestState(object sender, EventArgs e)
{
var context = HttpContext.Current;
var path = context.Request.AppRelativeCurrentExecutionFilePath;
if (path.StartsWith("~/$hdr/unload"))
{
//do things
}
}
I'm trying to use the fetch api instead of synchronous ajax request used before. In chrome everything works fine, but FireFox 89.0 behaves strangely.
Code in beforeunload is like this:
let i;
let data = new Headers();
if (window.FMS && window.FMS.HttpHeaders) {
for (i in window.FMS.HttpHeaders) {
if (FMS.HttpHeaders.hasOwnProperty(i)) {
data.append('X-FMS-' + i, FMS.HttpHeaders[i]);
}
}
}
fetch(FMS.UnloadUrl + '?_=' + jQuery.now(), {
method: 'GET',
keepalive: true,
cache: 'no-cache',
headers: data }
).then(response => response.ok)
.then(IsOk => console.debug(IsOk.toString()))
.catch((error) => {console.error('Error:', error)});
If my understanding is correct - the server side now have to receive OPTIONS preflight request first? I never receive this. Sometimes i receive the GET request, but usually in the FireFox console i can see TypeError: NetworkError when attempting to fetch resource error or notification that the XHR request has been blocked by DevTools.
I am trying to stub out a route using cypress 5.2. I have a simple function to do that:
function mockAlertsResponses(){
cy.route({
method: "GET",
url: "/api/polling/alerts/statistics*",
response: {
total: 2,
...
}
});
}
In one set of tests, this works just fine:
describe("admin and read only permissions", () => {
it ("all action bar items are enabled with admin permissions", () => {
cy.login("user", "password");
mockAlertsResponses();
// Click alert to enable all buttons
cy.get("#1-checkbox").click()
cy.get("#mark-alert-button").should("be.enabled");
cy.get("#delete-alert-button").should("be.enabled");
});
// ... a few more similar tests
});
However, in another set of tests, I use the same function:
it("Logs in and out", () => {
cy.login("username", "password");
mockAlertsResponses()
cy.get("#vine-appbar").should("be.visible");
cy.get("#info-button").click();
cy.get("#info-menu-logout").click();
cy.get("#login-button");
cy.get("#vine-appbar").should("not.be.visible");
});
In this second set of tests, the routes are not stubbing properly, leading to errors and test failures. Here, you can see the route is not stubbed, but rather throws a 500 error:
I'm not sure what could be interfering here. I'm a bit new to cypress and I'm not even sure where to begin debugging this. Might the cy.server calls be interfering? Please let me know what more information we'd need to figure out why one set of stubs works and another doesn't.
If you're wondering, the login function has a call to cy.server and has its own cy.route as well:
Cypress.Commands.add("login", (username, password, admin = true) => {
const response = admin ? <jwt1> : <jwt2>
cy.server();
cy.route({
method: "POST",
url: "/api/login",
response
});
cy.visit("/logout");
cy.visit("/");
cy.wait(100);
cy.get("#login-error").should("not.be.visible");
cy.get("#login-username").type(username);
cy.get("#login-password").type(password);
cy.get("#login-button").click();
});
I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.
I have a problem with my angular app- after a user signs in, if he hits the refresh button, the signin info is lost and the app redirects to the log in page. I found a SO answer for something similar here using $cookieStore but I don't think it can work for me as I'm not using cookies. Can anyone suggest a solution? Here's my authorization service-
var app = angular.module('myApp.services');
app.factory('SignIn', ['$resource', '$q', function($resource, $q) {
var signInUrl = 'https://example.com'
var API = $resource(signInUrl, {}, {
signIn: {
withCredentials: true,
url: signInUrl + '/session',
method: 'POST'
},
signOut: {
url: authApiUrl + '/session',
method: 'DELETE'
},
currentUser: {
url: signInUrl + '/users/#me',
method: 'GET'
}
});
var _currentUser = undefined;
return {
isAuthenticated: function() {
return !!_currentUser;
},
getUser: function(){
var d = $q.defer();
// If _currentUser is undefined then we should get current user
if (_currentUser === undefined) {
API.currentUser(function(userData) {
_currentUser = userData;
d.resolve(userData);
}, function(response) {
if (response.statusCode === 401) {
_currentUser = null;
d.resolve(_currentUser);
} else {
d.reject(response);
}
});
} else {
d.resolve(_currentUser);
}
return d.promise;
},
signIn: function(username, password){
var d = $q.defer();
API.signIn({email: username, password: password}, function(data, headers){
_currentUser = data;
d.resolve(_currentUser);
}, d.reject);
return d.promise;
},
signOut: function(){
var d = $q.defer();
API.signOut(function(){
_currentUser = null;
d.resolve();
}, d.reject);
return d.promise;
}
};
}]);
If you just need to keep track of the _currentUser data past a refresh then you could use sessionStorage within the browser. That extends all the way back to IE 8 and we really shouldn't be supporting any browsers before that anyway.
Usually these things are done with cookies though. When the client first makes a connection to the server (even before the first API call in some cases) a cookie is sent to the client so the server can maintain a session associated with that particular client. That's because the cookie is automatically sent back to the server with each request and the server can check its local session and say, "Oh, I'm talking to this user. Now I can use that additional piece of context to know if I can satisfy their API call or not."
You don't show any of your other API calls here but I'm guessing that you're sending something out of the _currentUser with each API call to identify the user instead? If so, that certainly works, and it avoids the need to synchronize cookies across multiple servers if you're clustering servers, but you're going to have to use something local like sessionStorage or localStorage that won't get dumped like your current in-memory copy of the data does when you refresh the page.
I am using the select2 plugin and I need to to use the transport-function to perform the ajax request on my own, because I need to set API Keys in the request-header. But as soon as I do this, select2 responses the results correctly and also formats and displays it like I want, but the results shown are not selectable. I can neither click at them, nor navigate to them with the arrow-keys, nor is there any mouseover effect when I go over them with the mouse.
Here's some code (I want to show suggestions for usernames):
ajax: {
data: function (term, page) {
return {
Searchtext: term
};
},
transport: function(queryParams){
// Api.Ajax delivers { Ajax: *the $.ajax object*, RequestId: *some requestId* }
var req = Api.Ajax("/api/suggestion/share/" + queryParams.data.Searchtext, "POST", { UserOnly: true }, queryParams.success);
return req.Ajax;
},
// parse the results into the format expected by Select2.
results: function(resp, page) {
return {
results: resp.Data,
more: false
};
}
},
Like I said, as soon as I use my own Ajax-function by implementing the transport-function, the results in the dropdown list are all shown, but not selectable.
Is this a bug, or am I doing something wrong?
#thnew This Answer will show you how to set request headers without requiring the transport function.