I'm developing an application using Laravel and AngularJS. For AngularJS pretty URL , i have set $locationProvider.html5Mode(true) and it's working fine. But suppose my url is http://localhost:8000/demo and if i refresh the page, I'm getting NotFoundHttpException in compiled.php line 7693:
Here is my angular's routes.
function($routeProvider,$locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.
when('/', {
templateUrl: 'partials/index.html',
controller: 'indexController'
}).
when('/dom',{
templateUrl:'partials/dom.html',
controller:'DomController'
}).
when('/demo',{
templateUrl:'partials/demo.html',
controller:'DemoController'
});
}]);
And here's my laravel's route.
Route::get('/', function(){
return view('index');
});
I'd appreciate a little help.
Thanks!
The problem here is that the web server will pick up http://localhost:8000/demo when you refresh the page, and try to handle the request. It's not aware that you wish to use html5 routing. So it will parse the request, say "oh, I should pass this to public/index.php and be done with it". And then public/index.php will receive it and throw an error since the route doesn't exist in Laravel.
What you need to do is to make a catch all type of route in Laravel, and then let Angular's routing take over. You then render your index view on every single request. There's a great answer here on SO on how you do that in Laravel 5: How do I catch exceptions / missing pages in Laravel 5?
This is pseudo code and will not work, just to show an example:
Route::get('*', function() {
return view('index');
});
So, render the index view on every request and then let Angular handle the routing from there.
Related
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.
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.
So I built an SPA for the company I work for and it can't go online until I have incorporated authentication due to the VERY sensitive nature of the data it displays. For this reason, I am attempting to build a static express page for login as opposed to handling this in the SPA.
Currently I'm doing it like this:
Serve my login page.
Call the API route used for authentication.
If successful serve the SPA.
If unsuccessful display an appropriate error message and re-render the login page.
I have built an authentication scheme with JWTs before, so I am not worried about that part. Right now I simply want to serve my SPA with the click of a button. If I remove the routes below and go to the home page my applications loads as normal. My problem is I'm trying to route to the angular app's homepage ('/#/') and express renders the login page.
The button on my homepage makes a get request to login. I want this to redirect to the SPA I've already built. Seems like it should be simple but I can't figure out how to do it for the life of me.
//Login routes, success delivers angular SPA
app.get('/', function (req, res) {
res.render('index.jade', {
title : "n562d",
strapline : "Please Log In"
})
});
app.get('/login', function (req, res) {
res.redirect('/#/')
});
I think you are bit confused. Use express as the REST engine when it comes to routes. Angular routes will take care of the display logic and view routing on the client side.
I would suggest you to pass JSON data to front end angular and let it do the job for you.
For example:
app.get('/', function (req, res) {
res.json({
title : "n562d",
strapline : "Please Log In"
})
});
You can access the API at the endpoint: http://localhost:3000/
Use $resource services to access the express endpoint:
example:
var MyResource = $resource('/');
var myResource = new MyResource();
myResource.$get(function(result){
//result holds -->{title : "n562d", strapline : "Please Log In"}
//use $location to change the uri, which is handled by Angular route config
$location.path('/')
});
For angular routing,i would suggest you to use ui-router
example:
function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state('index', {
url: "/",
templateUrl: 'app/authorization/index.tpl.html',
controller: 'AuthController'
})
.state('login', {
url: "/login/",
templateUrl: 'app/authorization/login.tpl.html',
controller: 'AuthController'
})
.state('signup',{
url: "/signup/",
templateUrl : 'app/authorization/signup.tpl.html',
controller: 'AuthController'
});
}
]);
Please note: I just named my controller as AuthController, you can replace it with name of your controller, same with views to.
Let me know if you need more detailed answer then i will update it. I hope it helps.
I'm trying to use angular ngResource module to fetch data from json file but I get an error 404 on the console - the URL is being concatenated with code following the call to get function.
Here is the error:
localhost prefix/test_data/data.json/function%20(data)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20console.log(data);%20%20%20%20%20%20%20%20%7D
here is the code I'm using:
the json service -
angular.module('jsonServices',['ngResource']).factory('JsonService',
function ($resource) {
return $resource('/test_data/data.json');
});
the controller using the service:
angular.module('myApp.controllers')
.controller('mainController', function ($scope, JsonService) {
JsonService.get(function (data) {
console.log(data);
});
});
the app js that starts it all:
angular.module('myApp',['myApp.controllers','jsonServices','ui.router'])
.config(function($stateProvider, $urlRouterProvider){
$stateProvider.state('home',{
url:'/home',
template:'some template path goes here',
controller:'mainController'
};
});
As you can see the "function(data)" is being added to the url as a string. one more thing is when I try to access the json file browsing to its location I can see the content of the json file OK.
Does anyone got this problem before and find a way to solve it? Is there something I'm doing wrong or missing here?
Thanks,
Eran
Found the problem, it seems that I used a bower package call ng-resource instead of angular-resource.
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.