I'm writing an Ionic app, which uses AngularUI's Router. I'd like to query localstorage using a factory I wrote, so I can determine whether to show a first-run screen or not.
My index.html loads scripts in this order:
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
<script src="js/routes.js"></script>
<script src="js/directives.js"></script>
<script src="js/filters.js"></script>
And my routes config looks like this (truncated for brevity):
angular.module('app.routes', [])
.config(function($stateProvider, $urlRouterProvider, storageFactory) {
$stateProvider
.state('myApp.mainscreen', {
url: '/main',
views: {
'side-menu21': {
templateUrl: 'templates/main.html',
controller: 'mainCtrl'
}
}
})
// ...
$urlRouterProvider.otherwise('/menu/main')
Now I have a module called app.services, which contains my factory, storageFactory (I know, I'm going to move it out of the services module ;)). When I attempt to inject storageFactory like so:
angular.module('app.routes', ['app.services', 'storageFactory'])
.config(function($stateProvider, $urlRouterProvider, storageFactory) {
I get an error similar to this:
Error: [$injector:nomod] Module 'storageFactory' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
I'm certain that my app has loaded app.services and storageFactory prior to loading, but I just can't seem to get it to work correctly.
How can I resolve this?
You can inject factories in UI router resolve blocks, without injecting them in the config block since it can only be injected with providers. For example:
$stateProvider
.state('myApp.mainscreen', {
url: '/main',
views: {
'side-menu21': {
templateUrl: 'templates/main.html',
controller: 'mainCtrl'
}
},
resolve: {
firstRun: ['storageFactory', function(storageFactory) {
// Do what you want with storageFactory here!
// Full infos here: https://github.com/angular-ui/ui-router/wiki#resolve
}]
}
})
you cant inject services in config only provides but you can do it in app.run Here's the calling order:
app.config() //only provides can be injected
app.run()
directive's compile functions (if they are found in the dom)
app.controller()
directive's link functions (again, if found)
in your case you can also use route resolve property
Related
I have
<base href="/!#/">
at the top of my index.html file. When I go to URL http://localhost:5000/ everything works fine, it instantly add #!/ so the URL is http://localhost:5000/#!/ and page display as expected.
At the server side I have following code which should allow me to use my files
app.use(express.static(path.join(__dirname, 'public')));
Structure of my files is something like:
bookApp(folder)
server.js
public(folder)
index.html
app.js(ngRoute)
views(folder)
css(folder)
controllers(folder)
and my AngularJS routing is:
(function () {
'use strict';
angular
.module('app', [
'ngRoute'
])
.config(config);
function config ($routeProvider) {
$routeProvider
.when('/', {
controller: 'PostsCtrl',
templateUrl: 'views/posts.html'
})
.when('/register', {
controller: 'registerCtrl',
templateUrl: 'views/register.html'
})
.when('/login', {
controller: 'loginCtrl',
templateUrl: 'views/login.html'
})
.otherwise('/');
}
})();
The very first page (views/posts.html) load as expected but when I click
<li>Sign in</li>
the URL is http://localhost:5000/login not as like I thought http://localhost:5000/!#/login.
and it display:
Cannot GET /login
when I manually change URL to http://localhost:5000/#!/login it works fine.
How to fix this behavior?
The only solution I see is to get rid of <base> tag and in every link manually in href directive add !# before slash.
It looks like you are forgetting the ng-view directive: <div ng-view></div> which is the container for the content that is provided by your routing. Place this above your script if you have everything contained in one file.
You can also try:
<ng-view></ng-view>
<div class="ng-view"></div>
Is there any particular reason you are still using Angular 1? I know this isn't technically answering your question, but I would highly recommend that you start using the latest Angular. You can still keep legacy code but it will make a lot of what you are doing a lot cleaner and clear.
I am really struggling with Angular since it is very fragile i think and I have a very simple case (probably the simplest case ever) which does not work yet.
Here is my module (so i do inject the library):
angular.module(
'module', ['ui.router']
My index.html:
<html data-ng-app="module">
<head>
... several libraries and my js files including ui-router library js + my app.js where the state definitions are located.
</head>
<body>
<div ui-view></div>
</body>
And why is not my template injected in ui-view?
EDIT: Sorry, i was in a hurry, forgot to add some details.. I have updated the app.js section like this:
.state('default',
{
url: '/',
template: '<h1>default</h1>'
})
.state('x',
{
url: '/x',
template: '<h1>X</h1>'
});
Now default state works as expected. But i call the url "host/x" i get a "Cannot GET /x".. when i call the url like "host/#x", it works.
But i have also this section for html5 mode in my app.js:
$locationProvider.html5Mode({
enabled: true,
requireBase: true
});
I have also this in the head section of my index.html:
<base href="/">
I thought, html5 should already handle the hash(#) part of the url? How can i get rid of that # in URL, so i can call directly "host/x"?
You need to specify the url property and go to this url to see this page. State should be something like:
.state("yourStateName", {
template: "<h1>My Contacts</h1>",
url: "/stateURL"
})
This is working example of url provider form my project:
angular.module("app")
.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
$locationProvider
.html5Mode(true);
$urlRouterProvider.when('/', '/url1');
$urlRouterProvider.when('', '/url2');
$urlRouterProvider.when('/url3', 'url4');
$urlRouterProvider.otherwise('/url5');
});
I started my first angular application, and am running into an issue where my "home" module isn't working because of a dependency issue. I don't see any dependency missing that I would need. I am using $stateProvider, and $urlProvider, but I am injecting that into the configuration for the home module, so I'm not sure where the problem would lie ?
Config.$inject = ["$stateProvider", "$urlRouterProvider"];
angular.module('home', []).config(Config)
function Config($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/login',
templateUrl: './views/login.html'
})
}
angular.module('home').controller('loginCtrl', function($scope){
$scope.helloWorld = function(){
console.log("This works!")
}
})
The consoled error:
[$injector:modulerr] http://errors.angularjs.org/1.5.5/$injector/modulerr?p0=home&p1=Error%3A%20…
Since "$stateProvider" and "$urlRouterProvider" providers are not part of the core AngularJS module, you need to inject modules, that have this provides into your home module definition. As far as I know, $stateProvider is from ui router module, so
angular.module('home', ['ui.router']).
...
Keep in mind that you also need to include this Javascript in your HTML file. It is in the angular-ui-router file
<script src="js/angular-ui-router.min.js"></script>
This is my app.js:
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'partials/home.html',
controller: 'homeController',
resolve: {
loggedUser: getLoggedUser
}
}]);
The function getLoggedUser() returns a promise which is resolved in userService when it has found the logged in user. In my index.html I include a navigation bar:
<ng-include src="'partials/navbar.html'" ng-controller="homeController"></ng-include> // Navbar
<div ng-view></div> // Angular views
The problems are:
ng-controller cannot be used with resolve since it creates an AngularJs error of 'unknown provider'. Therefore, the ng-include creates trouble for the '/' route.
I cannot/do not know how to specify a resolve for the navbar since it has no route, but is included in every view in index.html. And the navbar needs to show the name of the logged in user.
EDIT1:
I tried an ugly solution, by returning myPromise.$$state.value in homeController and removing the resolve {...}. However, it feels like I shouldn't use the $q promises like this. Any other suggestions?
EDIT2:
What I mean is that the loggedUser is unknown because of ng-controller="". Here is an explanation: AngularJS, resolve and unknown provider.
I think the reason why you get an error about 'unknown provider' is that you need to inject the service userService into the resolve function :
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'partials/home.html',
controller: 'homeController',
resolve: {
loggedUser: function(userService) {
return userService.getLoggedUser();
}
}
}]);
You can separate the navbar from the rest of your app.
Use something like
<body>
<div ng-controller = "navbarController as nav">
<div ng-show=" userIsLoggedIn"> <!-- show navbar only if true -->
<!-- navbar markup-->
</div>
</div>
<div ng-view> <!-- display other templates here --> </div>
</body>
You can then use a service in which us store the login status and credentials of the user. As services can be accessed app wide, you can access its data (like the username) in your navbarController.
I realise there are a few answers to this question on here, but I just can't seem to get them working with my set up. This is a Plunker of what I am trying achieve (not my own work): http://plnkr.co/edit/Ofq7Md8udEnIhAPF1NgL?p=preview
Currently, I have this for my index.html file:
<body ng-app="HomeCourtArenaApp">
<div class="container" ng-view></div>
<script src="components/angular/angular.js"></script>
<script src="components/require/require.js"></script>
<script src="components/angular/angular-resource.js"></script>
<script src="scripts/services/data.js"></script>
<script src="scripts/app.js"></script>
</body>
To register the components, I have defined them in the karma.conf.js file:
files = [
JASMINE,
JASMINE_ADAPTER,
'app/components/angular/angular.js',
'app/components/angular/angular-resource.js',
'app/components/angular-mocks/angular-mocks.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
];
To then create the service, I use the same technique that seems to be documented online in most examples:
'use strict';
angular.module('jsonData', ['ngResource'])
.factory('jsonData', function($resource) {
return $resource('data/shoe3Dconfig.js');
});
Where an error seems to be triggered is when I try to define the service in my 'app' variable, where adding the service name stops the content loading ['jsonData']:
'use strict';
var app = angular.module('HomeCourtArenaApp', ['jsonData']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
});
I would share my views and controllers also, but before I can even use the JSON data in my template, there are an unearthly amount of errors to deal with:
Uncaught Error: Module name "path" has not been loaded yet for context: _. Use require([])
Uncaught Error: Mismatched anonymous define() module: function () {
return getStyleProperty;
}
Uncaught Error: No module: ngResource
There are some other errors also, but these seem to be mainly because the scripts further up the DOM are stopping them loading correctly. Any help would be great!
you could try this :
the app.js:
angular.module('HomeCourtArenaApp', ['HomeCourtArenaApp.services', 'HomeCourtArenaApp.controllers']).
config(['$routeProvider', ($routeProvider) {
$routeProvider.when('/', { templateUrl: 'views/main.html', controller: 'MainCtrl' });
$routeProvider.otherwise({ redirectTo: '/'});
}]);
angular.module('HomeCourtArenaApp.services', ['ngResource']).
factory('JsonData', function($resource){
return $resource('data/shoe3Dconfig.js');
});
angular.module('HomeCourtArenaApp.controllers', []).
controller('MainCtrl', ['$scope', 'JsonData', function($scope, JsonData) {
$scope.objs = JsonData.query();
console.log(objs);
}
}]);
and this is not necessary to load the datas in the html
<script src="scripts/services/data.js"></script>
This edited plunker http://plnkr.co/edit/33qW5VRnQVrHWFlp16kz?p=preview should get you further along the way.
You need to specify the module (jsonData) that you want in your app as a dependency. There is currently no name displayed since your data does not have a name property.
Your JSON service module definition named as 'jsonData'
angular.module('jsonData', ['ngResource'])
This module defines a service provider (factory) 'jsonService'
.factory('jsonService', function($resource) {
You list the 'jsonData' module as a dependency for your module so that you can access anything defined in there
var app = angular.module('plunker', ['jsonData']);
You then use Angular's Dependency Injection to request an instance of jsonService
app.controller('MainCtrl', function($scope, jsonService) {
Note that if you "production-ise" this and minify your JS, you will need to configure the DI code. I will leave that to you to find in the Angular docs.
Does this explain things a bit more?
And you can get the console in plunker by opening the developer tools in your browser.