I use Typescript 1.4 with angularjs 1.3.6.
Using VS 2015 RC with webessentials, with no module system (no --module flag)
I have a working code like this:
demoModule.ts
module Demo.Test {
'use strict';
(() => {
var app = angular.module('Demo.Test', []);
// Routes.
app.config([
'$stateProvider', $stateProvider => {
$stateProvider
.state('demo', {
url: '/demo',
templateUrl: '/views/test/demo.html',
controller: 'demoController as vm'
});
}
]);
})();
demoController.ts
module Demo.Test {
'use strict';
export class DemoController {
constructor(/* ... */) { /* ... */}
}
angular.module('Demo.Test').controller('demoController', Demo.Test.DemoController);
}
But when I move this line:
angular.module('Demo.Test').controller('demoController', Demo.Test.DemoController);
to the demoModule.ts file(see below) it will compile, but getting JS error when run:
Error: [ng:areq] Argument 'demoController' is not a function, got undefined
Any idea how can I make it work? I mean like this:
module Demo.Test {
'use strict';
(() => {
var app = angular.module('Demo.Test', []);
angular.module('Demo.Test').controller('demoController', Demo.Test.DemoController);
// Routes.
app.config([
'$stateProvider', $stateProvider => {
$stateProvider
.state('demo', {
url: '/demo',
templateUrl: '/views/test/demo.html',
controller: 'demoController as vm'
});
}
]);
})();
If you used the script reference not in the right order, then you are going to get the runtime error.
as: Error: [ng:areq] Argument 'demoController' is not a function, got undefined
Add demoController.ts before demoModule.ts in your html file.
<script src="demoController.js"></script>
<script src="demoModule.js"></script>
Its got to do with ordering of files. One of the well known errors caused by using --out in TypeScript : https://github.com/TypeStrong/atom-typescript/blob/master/docs/out.md#runtime-errors
Related
how to write different modules with their own routing?
i have an angular app and it has different modules.i am going to write for each of them, specific route file, but i got this error
Uncaught Error: [$injector:unpr] http://errors.angularjs.org/1.6.4/$injector/unpr?p0=routeServiceProvider%20%3C-%20routeService
it is my code :
sample.module.js
angular.module('app.sample', []);
sample.route.js
angular
.module('app.sample')
.run(appRun);
/* #ngInject */
function appRun (routeService) {
routeService.configureRoutes(getRoutes());
}
function getRoutes () {
return [ {
url: '/sample',
config: {
templateUrl: 'sample.html'
}
}
];
}
i already add ngRoute and inject these files in index.html file
To achieve such project structure, ui-router is the best way to go. It is a separate library so you have to include into your project as a dependency.
Here are the snippets that will be useful for your case
dashboard.module.js
angular.module('app.dashboard', ['ui.router']);
dashboard.router.js
angular.module('app.dashboard')
.config(routerConfig);
routerConfig.$inject = ['$stateProvider'];
function routerConfig($stateProvider) {
$stateProvider
.state('state1', {
url: '/state1',
templateUrl: 'url/to/state1.html',
controller: function () {
// controller code here
}
})
.state('state2', {
url: '/state2',
templateUrl: 'url/to/state2.html',
controller: function () {
// controller code here
}
});
}
sample.module.js
angular.module('app.sample', ['ui.router']);
sample.router.js
angular.module('app.sample')
.config(routerConfig);
routerConfig.$inject = ['$stateProvider'];
function routerConfig($stateProvider) {
$stateProvider
.state('state3', {
url: '/state3',
templateUrl: 'url/to/state3.html',
controller: function () {
// controller code here
}
})
.state('state4', {
url: '/state4',
templateUrl: 'url/to/state4.html',
controller: function () {
// controller code here
}
});
}
Lastly, app.module that connects all these modules
app.module.js
angular.module('app', [
/*
* sub-modules
*/
'app.dashboard',
'app.sample'
]);
To sum up, you have two independent sub-modules (app.dashboard and app.sample) with their own routing logic and one module (app) that wraps them into one angular application.
$stateProvider, service provided by ui.router, is used for registering states.
Additional info
Since your application is modular, you are probably going to need nested routing which is greatly supported by ui.router. Read docs to get more information on nested states.
Update
However, if you still want to stick with ngRoute, this and this clearly explain how to achieve the same result.
That's a bad title. I'm aware. That's because I'm not entirely sure how to ask this question. I've got two essentially identical classes, behaving just a little bit differently, a corresponding controllerAs: 'vm' in the state config for each of them also behaving differently and a perplexing "this method can be static" warning from Webstorm in one of them and not the other.
index.html:
<div ui-view="main"></div>
<div ui-view="portfolio"></div>
app.js
// this file contains only the module setter with all the
// dependencies, as well as the $stateProvider config and
// any actions that occur when the app runs
'use strict';
angular.module('necApp', ['dep1', 'dep2', 'etc'])
.config(['$urlRouterProvider', '$locationProvider', '$animateProvider', Config])
.run(['$rootScope', '$state', Run]);
function Config(params) { /* do stuff */ }
function Run(params) { /* do stuff */ }
main.js
use strict';
import { MainController } from './main.controller';
angular.module('myApp')
.controller('MainController', MainController)
.config(['$stateProvider', Config]);
function Config($stateProvider)
{
$stateProvider
.state('main',
{
url: '/',
views: {
'main': {
templateUrl: 'app/main/main.html',
// OF NOTE: I have access to the controller as 'vm' in the view
// regardless of whether I include the next two lines
controller: MainController,
controllerAs: 'vm'
}
}
});
}
main.html
<!--
again, this expression is evaluated whether or not I include
the `controller` and `controllerAs` properties in my $state config
-->
<h1> {{ vm.result }} </h1>
main.controller.js
// OF NOTE: when I DO include the `controller` property in the $state config
// for the main route, this controller is registered and instantiated twice
'use strict';
export class MainController
{
constructor($http)
{
/* #ngInject */
angular.extend(this, {
$http: $http,
result: ''
});
this.Init();
}
Init()
{
this.$http.get('/endpoint').then(res =>
{
this.result = res.data;
});
}
}
portfolio.js
use strict';
import { PortfolioController } from './portfolio.controller';
angular.module('necApp')
.controller('PortfolioController', PortfolioController)
.config(['$stateProvider', Config]);
function Config($stateProvider)
{
$stateProvider
.state('portfolio',
{
url: '/portfolio',
views: {
'portfolio': {
templateUrl: 'app/portfolio/views/portfolio.html',
// OF NOTE: I do NOT have access to the controller as 'vm'
// in the view in this case without the next two lines
controller: PortfolioController,
controllerAs: 'vm'
}
}
});
}
portfolio.html
<!-- this is NOT evaluated without the `controller` and `controllerAs` properties in the $state config -->
<h1> {{ someExpression }} </h1>
portfolio.controller.js
'use strict';
export class PortfolioController
{
constructor()
{
angular.extend(this, {
someExpression: 'Testing . . .'
});
this.Init();
}
// OF NOTE: Webstorm warns me that this method can be static, even though
// 1) that breaks it and 2) I do NOT get that warning in MainController
Init()
{
// works as expected
console.log('initializing PortfolioController.');
}
}
As always, I very much look forward to your thoughts and comments.
Okay, before anybody else wastes their own valuable time with this, it turns out I'm just dumb. Or forgetful. I found a forgotten and unused directive I wrote that was for some reason using the MainController as 'vm'. Geez.
Although: I still have Webstorm warning me that PortfolioController.Init() can be static, while I do not get that warning on MainController.Init(). So that's still a mystery, I guess.
This page: https://docs.angularjs.org/guide/providers has a table at the bottom which states that both constants and providers are available in config phase.
When I try to use some constant in my config I get this error:
Uncaught Error: [$injector:modulerr] Failed to instantiate module testApp due to:
TypeError: undefined is not a function
The constant is set up as follows:
'use strict';
angular.module('services.config', [])
.constant('configuration', {
key: 'value';
});
then the configuration is:
angular
.module('testApp', ['services.config', 'ngRoute'])
.config(function ($routeProvider, configuration) {
$routeProvider.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
});
// do something with configuration.key - causes error
});
Does anyone know what I'm doing wrong?
Thanks in advance.
var app = angular.module('TestApp', []);
app.constant('configuration', {
key: 'value'
});
app.config(function (configuration) {
console.log(configuration.key); //value
});
app.constant('configuration', {
key: 'value'
});
here is the jsFiddle: http://jsfiddle.net/gopinathshiva/0701k7ke/8/
I'm trying to get to work angular.js, ui-router, and require.js and feel quite confused. I tried to follow this tutorial http://ify.io/lazy-loading-in-angularjs/. First, let me show you my code:
app.js =>
var app = angular.module('myApp', []);
app.config(function ($stateProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
$stateProvider.state('home',
{
templateUrl: 'tmpl/home-template.html',
url: '/',
controller: 'registration'
resolve: {
deps: function ($q, $rootScope) {
var deferred = $q.defer(),
dependencies = ["registration"];
require(dependencies, function () {
$rootScope.$apply(function () {
deferred.resolve();
});
})
return deferred.$promise;
}
}
}
);
app.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
});
Now in my registration.js I have following code:
define(["app"], function (app) {
app.lazy.controller("registration" , ["$scope", function ($scope) {
// The code here never runs
$scope.message = "hello world!";
}]);
});
everything works well, even the code in registration.js is run. but the problem is code inside controller function is never run and I get the error
Error: [ng:areq] http://errors.angularjs.org/1.2.23/ng/areq?p0=registration&p1=not a function, got undefined
Which seems my code does not register controller function successfully. Any Ideas?
P.s. In ui-router docs it is said "If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $routeChangeSuccess event is fired." But if I put the deferred.resolve(); from mentioned code inside a timeOut and run it after say 5 seconds, my controller code is run and my view is rendered before resolve, Strange.
Seems like I ran into the exact same problem, following the exact same tutorial that you did, but using ui-router. The solution for me was to:
Make sure the app.controllerProvider was available to lazy controller script. It looked like you did this using app.lazy {...}, which a really nice touch BTW :)
Make sure the lazy ctrl script uses define() and not require() I couldn't tell from your code if you had done this.
Here is my ui-router setup with the public app.controllerProvider method:
app.config(function ($stateProvider, $controllerProvider, $filterProvider, $provide, $urlRouterProvider) {
app.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
$urlRouterProvider.otherwise('/');
$stateProvider
.state('app', {
url:'/',
})
.state('app.view-a', {
views: {
'page#': {
templateUrl: 'view-a.tmpl.html',
controller: 'ViewACtrl',
resolve: {
deps: function ($q, $rootScope) {
var deferred = $q.defer();
var dependencies = [
'view-a.ctrl',
];
require(dependencies, function() {
$rootScope.$apply(function() {
deferred.resolve();
});
});
return deferred.promise;
}
}
}
}
});
});
Then in my lazy loaded controller I noticed that I had to use require(['app']), like this:
define(['app'], function (app) {
return app.lazy.controller('ViewACtrl', function($scope){
$scope.somethingcool = 'Cool!';
});
});
Source on GitHub: https://github.com/F1LT3R/angular-lazy-load
Demo on Plunker: http://plnkr.co/edit/XU7MIXGAnU3kd6CITWE7
Changing you're state's url to '' should do the trick. '' is root example.com/, '/' is example.com/#/.
I came to give my 2 cents. I saw you already resolved it, I just want to add a comment if someone else have a similar problem.
I was having a very similar issue, but I had part of my code waiting for the DOM to load, so I just called it directly (not using the "$(document).ready") and it worked.
$(document).ready(function() { /*function was being called here*/ });
And that solved my issue. Probably a different situation tho but I was having the same error.
I'd like to implement a setup where i can define a "root state" in the main module, and then add child states in other modules. This, because i need the root state to resolve before i can go to the child state.
Apparently, this should be possible according to this FAQ:
How to: Configure ui-router from multiple modules
For me it doesn't work:
Error Uncaught Error: No such state 'app' from ngBoilerplate.foo
Here is what i have:
app.js
angular.module( 'ngBoilerplate', [
'templates-app',
'templates-common',
'ui.state',
'ui.route',
'ui.bootstrap',
'ngBoilerplate.library'
])
.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) {
$stateProvider
.state('app', {
views:{
"main":{
controller:"AppCtrl"
}
},
resolve:{
Auth:function(Auth){
return new Auth();
}
}
});
$urlRouterProvider.when('/foo','/foo/tile');
$urlRouterProvider.otherwise( '/foo' );
})
.factory('Auth', ['$timeout','$q', function ($timeout,$q) {
return function () {
var deferred = $q.defer();
console.log('before resolve');
$timeout(function () {
console.log('at resolve');
deferred.resolve();
}, 2000);
return deferred.promise;
};
}])
.run(function run( $rootScope, $state, $stateParams ) {
console.log('greetings from run');
$state.transitionTo('app');
})
.controller( 'AppCtrl', function AppCtrl ( $scope, Auth ) {
console.log('greetings from AppCtrl');
});
foo.js
angular.module( 'ngBoilerplate.foo', ['ui.state'])
.config(function config( $stateProvider ) {
$stateProvider
.state( 'app.foo', {
url: '/foo/:type',
views: {
"main": {
controller:'FooCtrl',
templateUrl: function(stateParams) { /* stuff is going on in here*/ }
}
}
});
})
.controller( 'FooCtrl', function FooCtrl( $scope ) {
console.log('deferred foo');
});
How do i make this work or what other approaches could i take to have something global resolved before every state (without defining a resolve on each state)?
I finally chose this approach which does the job for me:
// add all your dependencies here and configure a root state e.g. "app"
angular.module( 'ngBoilerplate', ['ui.router','templates-app',
'templates-common','etc','etc']);
// configure your child states in here, such as app.foo, app.bar etc.
angular.module( 'ngBoilerplate.foo', ['ngBoilerplate']);
angular.module( 'ngBoilerplate.bar', ['ngBoilerplate']);
// tie everything together so you have a static module name
// that can be used with ng-app. this module doesn't do anything more than that.
angular.module( 'app', ['ngBoilerplate.foo','ngBoilerplate.bar']);
and then in your app index.html
<html ng-app="app">
In the documentation the feature1 module depends on the application module. Try
angular.module( 'ngBoilerplate.foo', ['ngBoilerplate'])
I would of just commented but i do not have the rep. I know this is old but i had the same problem and came across this. One thing i am confused about is in app.js you do not import "ngBoilerplate.foo" but ngBoilerplate.library instead. I had the same problem and my solution was to inject sub modules into the top module instead of their parent.
My structure was module('ngBoilerplate'), module('ngBoilerplate.foo') and module('ngBoilerplate.foo.bar')'. I was injecting ngBoilerplate.foo.bar into ngBoilerplate.foo and the $stateProvider was failing. I needed to inject ngBoilerplate.foo.bar into top level ngBoilerplate.
I thought i would put this here in case anyone else sees this. The error i had was Uncaught TypeError: Cannot read property 'navigable' of undefined from ngBoilerplate.foo