In my Angular application I want to use $httpBackend to fake the data while development(and not while testing). The problem with using it while development is that all the requests initiated to fetch the static resources like template html or css fails with it.
angular.js:14516 Error: [$compile:tpload] Failed to load template: views/login.html (HTTP status: undefined undefined)(…)
As shown above after including the $httpBackend service to application it starts to complain about the http templates.
angular
.module('myApp', ['ngResource','ui.router','ngMockE2E'])
.config(function ($urlRouterProvider, $stateProvider) {
$stateProvider.state('dashboard.contacts',{
url: '/contacts/:id',
views:{
'mainWrapper':{
templateUrl: 'views/contacts.html',
controller:'ContactsCtrl as contactsctl'
}
},
});
})
.run(function ($state, $rootScope, AuthenticationService, $httpBackend) {
var contacts = [{'id':1,'name':'ABC','phone':1234},
{'id':2,'name':'DEF','phone':3456},
{'id':3,'name':'GHI','phone':5678}];
$rootScope.$state = $state;
if(!AuthenticationService.isAuthenticated()) {
$state.transitionTo('login');
}
$httpBackend.whenGET('/contacts').respond(contacts);
})
.controller('ContactsCtrl', function(){
var contactsctl = this;
});
What is best way to generate some fake data in angular application in BackendLess way while development ?
Related
I have an Angular app which makes some calls (POST and GET for now) to a backend service (powered by node.js with a REST interface). While developing the app itself I noticed it makes two requests to the backend each time a button is pressed or a page is loaded. Curiously everything works but each time I press some button the backend gets two requests. I am not using any fancy package only ngRoute, ngResource and routeStyles for css partials. Anybody has an idea of what could be the reason why the app behaves like that?
I actually found another question similar to this one but the OP there was using express aside of Angular and there is no answer...
EDIT added some code.
in app.js:
'use strict';
var cacheBustSuffix = Date.now();
angular.module('myApp', ['myApp.controllers', 'myApp.services', 'myApp.filters', 'ngRoute', 'ngResource', 'routeStyles'])
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$locationProvider
.html5Mode({enabled: true,
requireBase: false})
.hashPrefix('!');
$routeProvider
.when('/', {redirectTo: '/myApp'})
.when('/myApp', {
templateUrl: '/partials/home.html?cache-bust=' + cacheBustSuffix,
controller: 'ctrlHome'
})
.when('/myApp/search', {
templateUrl: '/partials/search.html?cache-bust=' + cacheBustSuffix,
controller: 'ctrlSearch'
})
.when('/myApp/list/', {
templateUrl: '/partials/list.html?cache-bust=' + cacheBustSuffix,
controller: 'ctrlList'
})
// a bunch of other redirections
.otherwise({
templateUrl: '/partials/404.html?cache-bust=' + cacheBustSuffix,
controller: 'ctrl404'});
}]);
from services.js:
'use strict';
var app = angular.module('myApp.services', ['ngResource']).
factory('List', function ($resource) {
return $resource(WSROOT + '/search', {}, {get: {method: 'GET', isArray: false}});
});
from controllers.js, one controller that makes multiple requests
var controllers = angular.module('myApp.controllers', []);
var ctrlList = controllers.controller('ctrlList', function ($scope, $window, List) {
$window.document.title = 'myApp - List';
List.get({}, function (data) {
// $scope.res is an array of objects
$scope.res = data.response;
$scope.nitems = data.response.length;
});
});
ctrlList.$inject = ['$scope', 'List'];
And the network call when loading the index+home and navigating to some other page. As you can see, it first loads the index page, the scripts and styles listed there (not shown), then the home where I have a controller similar to the one above and suddenly two wild request to my web server:
Can we see your HTML files? I had this problem a while back. My solution was that by declaring a controller in the routing, and in the pages, a double post was created as each controller was loaded twice.
//Home
.state('tab.home', {
url: '/home',
views: {
'tab-home': {
templateUrl: 'templates/tab-home.html',
controller: 'HomeCtrl' // <-- This goes away
}
}
})
I'm having issues using oclazyload with $stateProvider.
I have specified that the controller .js should be loaded in the router config, and it does,' but it's not available to use as an ng-controller attribute in the file loaded in templateURL.
ui-route config:
core
.run(
[ '$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}
]
)
.config(
[ '$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
console.info('Routing ...');
$urlRouterProvider
.otherwise('/app/dashboard');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
templateUrl: 'templates/app.html',
})
.state('app.orders', {
abstract: true,
url: '/orders',
templateUrl: 'templates/orders/orders.html',
})
.state('app.orders.index', {
url: '/index',
templateUrl: 'templates/orders/index.html',
resolve: {
deps: ['$ocLazyLoad',
function( $ocLazyLoad ){
console.info('Path ot order controller in route config',Momento.paths.js + 'controllers/orders/index.js');
return $ocLazyLoad.load([
Momento.paths.js + 'controllers/orders/index.js'
])
}
]
}
})
}
]
)
;
And my templateURL file starts:
<div class="" id="" ng-controller="OrdersIndexController">...</div>
But when it loads, console throws the error:
<info>orders/index controller loaded controllers/orders/index.js:3
<info>Now I've finished loading the controller/order/index.js config/ui-router.js:69
<info>orders template loaded VM30437:1 (<-- this is the app.orders abstract template with ui-view directive ready for app.orders.index view)
<error>Error: [ng:areq] Argument 'OrdersIndexController' is not a function, got undefined
... <trace>
So the file is loaded correctly by lazyload, confirmed by console output above and network tab in developer tools, but it's not available in the templateURL to use as controller? Does it need to be aliased either in router config using controller:'' key or in template? Does it need to be specifically attached to the (only) module in this app?
What am I missing?
PS: confirming that the name of the controller is in fact OrdersIndexController:
core
.controller('OrdersIndexController', [
'Model', '$scope', '$window',
function( Model, $scope, $window){
console.info("OrdersIndexController fired");
}
]);
You have to register your controller with
angular.module("myApp").controller
Working
angular.module("myApp").controller('HomePageController', ['$scope', function ($scope) {
console.log("HomePageController loaded");
}]);
Not working
var myApp = angular.module("myApp")
myApp.controller('HomePageController', ['$scope', function ($scope) {
console.log("HomePageController loaded");
}]);
Inside the function function($ocLazyLoad){} you must to declare the name of module that contains the controller and the name of file "to lazy load"
function( $ocLazyLoad ){
return $ocLazyLoad.load(
{
name: 'module.name',
files: ['files']
}
);
}
If you use the current documented way for ocLazyLoad 1.0 -> With your router
...
resolve: { // Any property in resolve should return a promise and is executed before the view is loaded
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('js/AppCtrl.js');
}]
}
then in js/AppCtrl.js
You have something like this:
angular.module("myApp").controller('DynamicNew1Ctrl', ['$scope', function($scope) {
$scope.name = "Scoped variable";
console.log("Controller Initialized");
}]);
Note that with angular.module("myApp") you are attaching the new controller to an existing module, in this case the mainApp, so any of new dynamic controllers can use the app dependencies.
but you can define a new module an inject your dependencies, as described here, the later is used commonly when you estructure your app with a plugin architecture and you want to isolate the dynamic modules so they only have access to some especific dependencies
I'm setting up an access control system in angular. This is how it looks so far.
It's doing the ajax to return the current user's role, then checking that role with the access array to see if the user has permission. If not it redirects.
That all works fine, but the view is still being shown for a split second before the redirect.
It may also be important to note that the ajax request is necessary because the user auth is being handled with Laravel, so I made an API for Angular to talk to get information about the user's session.
var app = angular.module('application', ['ngResource']);
app.config(function($routeProvider){
$routeProvider
.when('/admin', {
controller: 'showAdmin',
templateUrl: 'admin.html',
access: ['Admin', 'Manager'],
resolve: AppCtrl.resolve
});
});
function AppCtrl ($scope, getUser, $location, $rootScope) {
}
AppCtrl.resolve = {
getUser : function($q, $http, $location, $rootScope) {
return $http({
method: 'GET',
url: '/api/getUser'
})
.success(function(data, status) {
$rootScope.user = data;
if($rootScope.access.indexOf(data.permissions[0].role_name) < 0) $location.path('/');
});
}
};
app.run(function ($rootScope, sessionFactory, $location){
$rootScope.$on('$routeChangeStart', function (event, next) {
$rootScope.access = next.access;
});
});
Use an ng-cloak directive on the containing element to eliminate the flicker. See this page for an example along with some CSS/browser-specific gotchas.
I'm learning Angularjs and i'm trying to create a service to do common tasks that need to be done for all my controllers.
I'm currently getting the error:
TypeError: Cannot call method 'getAuthHeader' of undefined
app.js
var token = "mytoken"
var baseUrl = "mybaseUrl";
var myezteam = angular.module('myezteam', ['ui.bootstrap']);
myapp.config(function($routeProvider) {
$routeProvider
.when('/profile',
{
controller: 'ProfileController',
templateUrl: 'template.html'
})
.otherwise({redirectTo: '/profile'});
});
// This gets the basic information that is needed for every page
myapp.service('base', function() {
this.getAuthHeader = function($http) {
// Set authorization token so we know the user has logged in.
return $http.defaults.headers.common.Authorization = 'Bearer ' + token;
}
});
profile.js
myapp.controller('ProfileController', ['$scope', '$http', function($scope, $http, base) {
base.getAuthHeader($http); // <-- THIS LINE IS THROWING THE ERROR
}]);
Why is the error occurring and how can I fix it? Also, is there a way to setup a config on my app so that I don't need to call base.getAuthHeader($http); in every controller, but it will automatically get called when every controller is loaded?
You're not injecting your service base into your controller. You need to inject it in the same way you did with $scope and $http
myapp.controller('ProfileController', ['$scope', '$http', 'base',
function($scope, $http, base) { ... });
This subject has been already asked but I couldn't figure out what to do in my case.
Using AngularJS 1.0.5:
Before showing the view "login", I want to get some data and delay the view rendering while the data isn't loaded from an AJAX request.
Here is the main code. Is it the good way?
angular.module('tfc', ['tfc.config', 'tfc.services', 'tfc.controllers']).config([
'$routeProvider', '$locationProvider', '$httpProvider',
function($routeProvider, $locationProvider, $httpProvider) {
$routeProvider.when('/login', {
templateUrl: 'views/login.html',
controller: "RouteController",
resolve: {
data: function(DataResolver) {
return DataResolver();
}
}
});
}
]);
module_services = angular.module("tfc.services", []);
module_services.factory("DataResolver", [
"$route", function($route) {
console.log("init");
return function() {
// Tabletop is a lib to get data from google spreadsheets
// basically this is an ajax request
return Tabletop.init({
key: "xxxxx",
callback: function(data, tabletop) {
console.log("[Debug][DataResolver] Data received!");
return data;
}
});
};
}
]);
The point of AngularJS is that you can load up the templates and everything and then wait for the data to load, it's meant to be asynchronous.
Your view should be using ng-hide, ng-show to check the scope of the controller so that when the data in the scope is updated, the view will display. You can also display a spinner so that the user doesn't feel like the website has crashed.
Answering the question, the way you are loading data explicitly before the view is rendered seems right. Remember that it may not give the best experience as there will be some time to resolve that, maybe giving an impression that your app stopped for some moments.
See an example from John Pappa's blog to load some data before the route is resolved using angular's default router:
// route-config.js
angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm',
resolve: {
moviesPrepService: function(movieService) {
return movieService.getMovies();
}
}
});
}
// avengers.js
angular
.module('app')
.controller('Avengers', Avengers);
Avengers.$inject = ['moviesPrepService'];
function Avengers(moviesPrepService) {
var vm = this;
vm.movies = moviesPrepService.movies;
}
You basically use the resolve parameters on the route, so that routeProvider waits for all promises to be resolved before instantiating the controller. See the docs for extra info.