Angular get request - javascript

I have a working angular form sitting inside an app (rails app). It sends a get request to a rails server.
The problem is that if this app receives a normal get request, it refreshes the page. However, when the request is sent via angular, I can see the request on the server, but the page is never refreshed. (I can use these get requests to get data back as well).
The question is how do I pass a get request in angular form, so that the server processes it normally, and refreshes the page?
html:
<form ng-submit="submitForm()" style="margin-top:30px;">
<h3>get request</h3>
<button type="submit" class="btn btn-primary">Get</button>
</form>
app.js controller:
$scope.submitForm = function(){
posts.factorySubmit();
};
app.js factory get function:
o.factorySubmit = function() {
$http.get('http://localhost:8080/clients');
};
--Side note - if I create a get request, with regular java script in the app, outside of the angular context, I get expected behavior, the page refreshes.

You've wrapped your $http in a factory which is great practice. What you're not doing is capturing the response.
o.factorySubmit = function() {
// Add a return here
return $http.get('http://localhost:8080/clients'); // This call returns a promise
};
Then when you call this function...
$scope.submitForm = function(){
posts.factorySubmit().then(function(response) {
$scope.requests = response.data; // This is where you get your response
},
function(response) {
// This is your error handling
});
};
The cool thing about angular is that it will detect changes and update the page automatically. It has a digest cycle that is called internally in response to changes. Since you're using the built-in $http provider, it'll refresh when you update the $scope variables.

Angular is by design supposed to not refresh the page as it is built for Single Page Applications. If you want to manually refresh the page, use
$scope.submitForm = function(){
posts.factorySubmit().success(function(){
$route.refresh();
});
};
In the success function of your $get request. Remember to inject $route into your controller.

Related

form's get method vs angular $http.get request

I want to make a get request to a specific url through my angular frontend to the expressjs backend, now in my frontend if I do :-
<li>
<a ng-click="givequiz()">GiveQuiz</a>
</li>
and my angular code is:-
$scope.givequiz=function(){
console.log("give quiz");
$http.get('/home/givequiz').then(function(res){
//request is going fine and all
});
}
The above thing is working but I am getting the response as an object, the complete file and url isn't changing and all.
But if i do the form get thing :-
<li>
<form action="http://localhost:8000/home/givequiz" method="GET">
<button type="submit">Give Quiz</button>
</form>
</li>
this takes me to a new url called "http://localhost:8000/home/givequiz"
but the $http.get doesn't why is this so? Aren't both methods same? And that's how I am handling both the requests.
router.get('/givequiz', function(req, res, next) {
console.log("in getquiz");
//always gets printed ^ means all reqs come here
res.sendFile('/givequiz.html',{ root: client });
});
Any help will be much appreciated.
It sounds like your code is working fine. Angular is making an AJAX type request behind the scenes. If you want to change route when the response comes back successfully you should do:
$http.get('/home/givequiz').then(function(res){
// request is going fine and all
$state.go(nameOfState)
});
You could alternatively set window.location in the then resolve block but that will prob cause a page refresh whereas state.go should not.

Passing data from server to angular

Sorry, I'm a newbie at this
Let's say i have the following in node express
router.get('/:name', function(req, res, next) {
res.render("test", {test:req.test});
});
how to do I get the angular to pick up the test variable?
i tried doing in the html page
<div ng-controller='UserCtrl'>{{ data }}</div>
<script>
var test=!{JSON.stringify(test)};
</script>
then on the angular page
productApp.controller('UserCtrl',function UserCtrl($scope){
$scope.data=test;
});
the req.test looks like this
[
{
name: 'test'
}
]
the 'data' shows empty everytime.
thank you for your help
If you want Angular to talk to a server, the most common way is through an AJAX request. Angular has a whole service to help you with this communication.
https://docs.angularjs.org/api/ng/service/$http
The first example pretty much does exactly what you are looking for:
$http({
method: 'GET',
url: '/testName'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
It uses promises for the response. Just add your actions in the proper call back function and away you go.
You will need to use ajax call from an angular script or service in order to get the express js backend response.
You can create a service like below -
productApp.service("API", function($http){
this.callAPI = function(name){
return $http({
url : "localhost:3000/"+name,
data : "", // pass data if any here
method: "get"
});
};
});
Then you will need inject this service in your controller and call like below -
productApp.controller('UserCtrl',function UserCtrl($scope, API){
//$scope.data=test;
// call service api here
API.callAPI("some name").then(function(response){
$scope.data = response;
}, function(){
// error goes here
});
});
Also, you can change your express js app to send the JSON data as follows -
res.json({...}); // instead of res.render(..);
Inside your express res.json() is, in my opinion, the best option you have since any object passed to it will be converted to JSON other way you can do it like you've done but render is more suited to html where you have to render a nice little view for the client or there is some sort of manipulation involved before sending the JSON on the wire or the json is too big and you don't want to make you router file dirty and rather delegate that to a view file.. else res.json() is a very neat way to do it.
Modify your controller code like:
productApp.controller('UserCtrl',['$scope', '$http' , function($scope, $http){
$http.get('/test').then(
function(response){
$scope.data = test;
},
function(err){
console.error(err);
}); //'/test' <- this is the url;
//$scope.data=test;
}]);
and remove this from your code
<script>
var test=!{JSON.stringify(test)};
</script>
I would recommend doing an $http service call to receive this variable BUT if you truly want this variable/data rendered directly in to the page and available in the controller, you should consider doing the following:
In the rendered/returned HTML:
<head>
...
<script>
angular.module('myAppConfig', [])
.value('MyTestConfig', !{JSON.stringify(test)});
</script>
</head>
<body ng-app="myApp">
...
<div ng-controller='UserCtrl'>{{ data }}</div>
...
</body>
This will setup an injectable configuration value called 'MyTestConfig'. Ideally, this should be part of a bigger object or service so you could do things like Config.apiPath or Config.getStaticResource('my-resource.png')
Your controller will now look like this:
productApp.controller('UserCtrl', function UserCtrl($scope, MyTestConfig){
$scope.data = MyTestConfig;
});
and your original modal definition will look something like this:
angular.module('myApp', ['myAppConfig']);
You may need to shuffle around where the script tag is depending on how you have configured your views. This will also only work before injection has been finalized, aka, this will not work for partials.

Angular refresh browser on redirect

When running an angularjs application, the user access may be withdrawn from the server side. In this case, every request results in a http 302 redirect and a login html (no partial) page. Since angular does expect whatever it was requesting in case the access would still be given, it breaks as it may expect a json string but gets the html login page.
Is there anything I can do do catch this event (listen to redirects, figure out whether html is returned, etc) and do a "hard" refresh of the redirect url?
Since you can't interfere an ajax 302 response and redirect to an error page, you will need to be a little creative.
You can add a header or a different response code to your relevant responses and add an interceptor on the client end.
The interceptor is a module that every ajax request\response goes throught.
You can add code that will look for that header and simple perform a $window.location.href to the login page.
Read here about interceptors.
Check this example out - It handles 401 responses.
If I get you right you are talking about the $http Service from AngularJS.
If thats the point, you could transform the response by yourself and check if its valide JSON like this:
$http({
url: '...',
method: 'GET',
transformResponse: function (reponse) {
var ret = [];//if the return stays empty, the repsonse may be HTML
try {
ret = JSON.parse(reponse);
} catch (error) {
//here you could check for the error
}
return ret;
}
}).success(function(answer){
if(answer.length === 0){//its empty, so its probably HTML
$window.location.reload();//refresh page here
return;
}
//its JSON with content!
});

AngularJS : Understanding service when using $http.post

I am moving all http calls in my controllers to services, using $q to promise... Everything seems to work till I refresh the page then the content disappears.
Setting: In my login service, I have a function which does an $http.post, it takes username and password. Then the response data is put in the promise.
Problem: Though the service works, It is trying resend the http call when the page is refreshed. The call then fails because the are no login details.
Question: How do I keep/store the original data so when the page is refreshed (and user is still signed in) and when I use the service in other controllers it does not do the http call it just returns the data?
Service:
var app = angular.module('myApp', ['ngRoute']);
app.factory('loginService', function($http, $q) {
var deferResults = $q.defer();
return {
appContent: function(login_username, login_password) {
$http.post('/login',{username: login_username, password: login_password}).success(function(data) {
deferResults.resolve(myData);
});
return deferResults.promise;
}
});
Controllers:
function loginPageCtrl($scope, loginService) {
$scope.login = function (login_username, login_password, login_rememberMe) {
loginService.appContent(login_username, login_username).then(function (data) {
$scope.pageOneContent = data;
});
};
};
function pageTwoCtrl($scope, loginService) {
// Use the same data when page is refreshed
// without having to pass-in login details
loginService.appContent().then(function (data) {
$scope.pageTwoContent = data;
});
};
Of course that happens, your app loses all its state when the page is refreshed. You need to persist that username and password somewhere, like a cookie, and then retrieve that then make your second $http call, even better just keep a token in a cookie and use that for authentication. Use angular's $cookieStore to persist the login details:
var userData={username:login_username,password:login_password};
$cookieStore.put('user_data', userData);
and then when the controller loads, check if the cookie exists:
var userData = $cookieStore.get('user_data');
return userData
Check the source in this answer to see this in action.
To recap, every time the controller loads check the cookie, if its undefined then redirect the user to a login page, if it's not then extract the toke/username/password and make your $http call.

angular - $http first call is super slow

A controller has $http that calls an api backend on Flask. I have some basic authentication and crossdomain is set. The first time it enters the cpuListCtrl controller the $http calls takes cca. ~14sec. The next time i visited the controller in angular it takes just 23ms. But every time i press the browsers refresh, back to ~14sec. Direct api call from browser also takes just 23ms. So my question is my does it takes so long, did i miss something, or where specific should i look?
EDIT: updated the code to reflect recent changes:
var app = angular.module('RecycleApp', ['ngRoute', 'appControllers']);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when("/cpu", {
templateUrl:'static/js/partials/cpu.html',
controller:'cpuCtrl'
})
}]);
var appControllers = angular.module('appControllers', []);
appControllers.controller('cpuCtrl', ['$scope','$http',
function($scope,$http){
$http({
url: 'http://SOME_IP/api/v1/cpus',
method: 'POST',
data: JSON.stringify({"latitude":46.1948436, "longitude":15.2000873}),
headers: {"Content-Type":"application/json"}
})
.success(function(data,status,headers,config){
console.log(data.list);
$scope.cpus = data.list;
})
.error(function(data,status,headers,config){
console.log("something went wrong.");
})
}]);
Server side:
#app.route('/api/v1/cpus', methods=["GET"])
#cross_origin(origins='*', headers=("Content-Type"))
def get_cpu_list():
result = session.query(RecycleReUseCenter)\
.options(load_only("Id", "CpuName"))\
.all()
return list_json(result)
#app.route("/api/v1/cpus", methods=["POST"])
#cross_origin(origins='*', headers=("Content-Type"))
def get_cpu_list_with_locations():
content = request.get_json(force=True)
given_latitude = content['latitude']
given_longitude = content['longitude']
result = RecycleReUseCenter.get_all_with_distance(given_latitude, given_longitude)
return list_json(result)
Do you know for sure when does the http call starts? The angular app may be stuck somewhere else, and getting to the http call only in the last second. For example - in the config you are using a "token" where do you get it from? in many angular app this is fetched from some oauth service, in a seperete call. Your slow call won't start until http is configured. After token is there, the next calls would be faster since we got the token already.
To limit some guessing you can use a proxy tool like charles - or deflect.io chrome extension to watch all the out going http calls and figure this out
I have recently had the same problem, and found that the delay oddly enough actually seems to be on the Flask end, but only happens when using an Angular app running in Chrome. This answer from the python stackexchange forum is the best one I have seen - https://stackoverflow.com/a/25835028/1521331 - it provides a 'solution' of sorts, if not an explanation for this mystery!
I was having the same problem, and none of the above worked for me. Here's what did:
Slow Requests on Local Flask Server
Effectively, certain browsers will attempt to access IPv6 sockets before IPv4. After commenting out the offending lines in /etc/hosts and restarting apache the problem was fixed.

Categories