Is it possible to load a template from a other application (like a express app) via $http?
Or from an other external source?
Not with ui-router alone, though the following lazy loading module for ui-router exists which may help you achieve your goal: ocLazyLoad - https://github.com/ocombe/ocLazyLoad
An example of how it works (taken from http://plnkr.co/edit/6CLDsz)
define([
'angular',
'uiRouter',
'ocLazyLoad',
'ocLazyLoad-uiRouterDecorator'
], function (angular) {
var app = angular.module('app', ['ui.router', 'oc.lazyLoad', 'oc.lazyLoad.uiRouterDecorator']);
app.config(function($stateProvider, $locationProvider, $ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
loadedModules: ['app'],
asyncLoader: require
});
$stateProvider
.state('home', {
url: "/",
template: "<p>Hello {{name}}. Would you like to... <a href='#lazy'>load lazy</a>?</p>",
controller: 'mainCtrl'
})
.state('lazy', {
url: "/lazy",
lazyModule: 'app.lazy',
lazyFiles: 'lazy',
lazyTemplateUrl: 'lazy.html',
controller: 'lazyCtrl'
});
$locationProvider.html5Mode(true);
});
app.controller('mainCtrl', function($scope) {
$scope.name = 'World';
});
});
It is possible but you'll have to use a templateProvider. More clear explanation using an example:
$stateProvider.state('state', {
url: '/state',
//templateUrl: 'templates/stateTemplate.html',
templateProvider: function ($http, $templateCache) {
var tplUrl = 'http://another.accesible.domain/stateTemplate.html',
tpl = $templateCache.get(tplUrl);
return (!!tpl) ? tpl :
$http
.get(tplUrl)
.then(function (response) {
tpl = response.data
$templateCache.put(tplUrl, tpl);
return tpl;
});
},
controller: 'stateController as sCtrl',
params: {
target: null
},
resolve: {
loadCtrl: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load(['stateController', 'appDataProvider', 'appDataService', 'stateFactory', 'stateService']);
}],
resolveObject: function ($window) {
var result = $window.localStorage.getItem('resolveObj');
return result;
}
}
})
Hope it helps (late answer I know, but just found this question looking for something else). ocLazyLoad is needed if you don't want to load everything at once when your app starts, but load what is required when it's required. Quite useful if your app's memory footprint is an issue.
Best regards.
Related
I have an angular app that needs to do a quick http request to get some config information before the rest of the application is initiated, at least before the controllers. Looked into using $UrlRouterProvider, but I did not figure out how to make the app wait for the http be done.
What I need to be finished:
$http({method: 'GET', url: '/config'}).then(function(res) {
configProvider.setConfig(res.data.config);
}
You can create a separate js file where you can make http request and then initialize/bootstrap your app via js code instead of ng-app in html code.
Refer the below code:
(function() {
var application, bootstrapApplication, fetchData;
application = angular.module('app');
fetchData = function() {
var $http, initInjector;
initInjector = angular.injector(['ng']);
$http = initInjector.get('$http');
$http.get('<url>');
};
bootstrapApplication = function() {
angular.element(document).ready(function() {
angular.bootstrap(document, ['app']);
});
};
fetchData().then(bootstrapApplication);
})();
I hope it helps.
Resolve must be declared on state, not on the view
change
.state('app', {
abstract: true,
url:'/',
views: {
"content": {
templateUrl: "myurl.html"
},
resolve {
myVar: ['$http', 'myService', function($http, myService) {
return $http({method: 'GET', url:'url'})
.then(function(res) { //do stuff })
to
.state('app', {
abstract: true,
url:'/',
views: {
"content": {
templateUrl: "myurl.html"
}
},
resolve {
myVar: ['$http', 'myService', function($http, myService) {
return $http({method: 'GET', url:'url'})
.then(function(res) { //do stuff })...
When I uglify webpack bundle, routing stops work without any error message or log message. I am using oclazyload to lazy load.
Route.js
module.exports = function(app) {
var routeConfig = function($stateProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/dashboard/dashboard.min.html',
title: 'Home',
ncyBreadcrumb: {
label: 'Home'
}
})
.state('organizationStructure', {
url: '/organizationStructure',
templateUrl: 'app/admin/organizationStructure/manageHierarchy/manageHierarchyShell.min.html',
'abstract': true,
ncyBreadcrumb: {
skip: true
},
resolve: ['$q', '$ocLazyLoad', function($q, $ocLazyLoad) {
var deferred = $q.defer();
require.ensure([], function() {
var mod = require('./organizationStructure.module.js');
$ocLazyLoad.load({
name: 'app.organizationStructure'
});
deferred.resolve(mod.controller);
});
return deferred.promise;
}]
})
.state('organizationStructure.organization', {
url: '/organization',
templateUrl: 'app/admin/organizationStructure/manageHierarchy/organization/index.min.html',
controller: 'ManageOrganization',
controllerAs: 'vm',
title: 'Manage Organization',
ncyBreadcrumb: {
label: 'Manage Organization',
parent: 'home'
}
});
}
app.config(routeConfig);
return routeConfig;
};
Module.js
var app = angular.module('app', [
'ui.router',
'restangular',
'ui.bootstrap',
'ncy-angular-breadcrumb',
'oc.lazyLoad'
]);
Base Route
require('./app.route.js')(app);
When I minify the bundle, app routing stops working. Otherwise it works fine. Please provide me a solution. Also I am using ngAnnotate. Dependencies are injected safely in minified file.
While doing minification you should for array annotation of DI.
You are not using angular di array notation inside you app.js, you need to do below changes.
From
app.config(routeConfig);
To
app.config(['$stateProvider', routeConfig]);
For more Information Refer this SO Answer
You're using the latest version of ui-router, which has a newer and slightly different way of handling the resolve block. It takes an object map.
Try this:
resolve: {
foo: ['$q', '$ocLazyLoad', function($q, $ocLazyLoad) {
var deferred = $q.defer();
require.ensure([], function() {
var mod = require('./organizationStructure.module.js');
$ocLazyLoad.load({
name: 'app.organizationStructure'
});
deferred.resolve(mod.controller);
});
return deferred.promise;
}]
}
Here is the ui-router API doc for this: https://github.com/angular-ui/ui-router/wiki#resolve
I am currently defining my global module in my routes.js, but for some reason the other controllers are not being created and I keep getting errors that say that my main app module 'LiveAPP' is not available. Here is my code:
routes.js
angular.module('LiveAPP', ['ngRoute'])
.config(function($routeProvider, $httpProvider) {
$routeProvider
.when('/', {
templateUrl : '/home.html',
controller : 'mainCtrl'
})
.when('/signup',{
templateUrl : '/signup.html',
controller : 'signUpCtrl'
})
.when('/artist',{
templateUrl : '/artistpage.html',
controller : 'artistCtrl'
})
})
mainCtrl.js
angular.module('LiveAPP')
.controller('mainCtrl', ['$scope','$http', '$location',mainCtrl]);
function mainCtrl($scope,$http,$location){
$scope.somefunc = function(artistname){
dataFactory.ArtistfromSpotify()
.success(function(data, status, headers, config){
console.log(data)
})
}
};
signUpCtrl
angular.module('LiveAPP')
.controller('signUpCtrl', ['$scope','$http',signUpCtrl]);
function signUpCtrl($scope,$http){
$scope.user = {
email:'',
password:''
}
$scope.postreq = function(user){
$http({
method: "post",
url: "/signup",
data:{
user_username:user.email,
user_password:user.password
}
}).success(function(data){
console.log("User posted to the database")
});
};
}
artistCtrl
angular.module('LiveAPP')
.controller('artistCtrl', ['$scope',function($scope){
$scope.myRating =
{number:3}
}])
.directive("rateYo", function() {
return {
restrict: "A",
scope: {
rating: "="
},
template: "<div id='rateYo'></div>",
link: function( scope, ele, attrs ) {
console.log(scope.rating.number)
$(ele).rateYo({
rating: scope.rating.number
});
}
};
});
I was under the impression that I could retrieve the main liveAPP module and add controllers in other files by using angular.model('liveAPP').controller(...) For some reason it's not working. Anyone have any idea?
To elaborate on my comment above, when you re-use the same module across files, you need to load the files in the right order to satisfy dependencies as well as ensure the module is created before being used.
An easy way to avoid this problem is to specify one module per file. For example
mainCtrl.js
(function() {
angular.module('LiveAPP.main', [])
.controller('mainCtrl', ...);
})();
and in your routes.js
(function() {
angular.module('LiveAPP', [
'ngRoute',
'LiveAPP.main'
])
.config(function($routeProvider, $httpProvider) {
$routeProvider.when('/', {
templateUrl: '/home.html',
controller: 'mainCtrl'
})...
});
})();
It's likely that your html file is including the js files in the wrong order. You need to make sure that routes.js appears first in the html.
You need to change signUpCtrl.js to
angular.module('LiveAPP.controller', [])
.controller('signUpCtrl', ['$scope','$http',signUpCtrl]);
and inject LiveAPP.controller to your global module
angular.module('LiveAPP', ['ngRoute', 'LiveAPP.controller'])
You cannot have LiveAPP in more than one module. Make the same updates on all of your controllers and inject that module names in routes.js
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 am trying to do an asynchronous http request to load some data before my app loads and so I am using a resolve in $routeProvider which is an http request in my MainController. For some reason, I keep getting Error: [$injector:unpr] Unknown provider: appDataProvider <- appData where appData is where I do my http request. I am using AngularJS v 1.2.5.
Here is the code and two methods that I tried that both give the same error:
Method #1
MainController.js
var MainController = ['$scope','$location','appData',
function($scope, $location, appData){
console.log(appData.data);
}
];
MainController.loadData = {
appData: function($http, $location, MainFactory){
var aid = MainFactory.extractAid($location);
return $http({method: 'GET', url: URL_CONST + aid});
}
};
app.js
var app = angular.module('HAY', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/pages/alerts'
})
.when('/pages/:pageName', {
templateUrl: function(params) {
return 'views/pages/' + params.pageName + '.html';
},
controller: MainController,
resolve: MainController.loadData
})
.otherwise({
redirectTo: '/pages/alerts'
});
});
I tried changing the name in case it was a conflicting system reserved keyword but with no luck. For some reason, appData is never recognized
Method #2
I also tried changing it around like so:
app.js
var app = angular.module('HEY', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
redirectTo: '/pages/alerts'
})
.when('/pages/:pageName', {
templateUrl: function(params) {
return 'views/pages/' + params.pageName + '.html';
},
controller: MainController,
resolve: {
appData: ['$http', '$location','MainFactory', function($http, $location, MainFactory) {
var aid = MainFactory.extractAid($location);
return $http({method: 'GET', url: URL_CONST + aid});
}]
}
})
.otherwise({
redirectTo: '/pages/alerts'
});
});
MainController.js
var MainController = ['$scope','$location','appData',
function($scope, $location, appData){
console.log(resolvedData);
}
];
However, the result was exactly the same. Does this have something to do with angular 1.2.5 ?
Here is a working version from someone else
http://mhevery.github.io/angular-phonecat/app/#/phones
And here is the code:
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function(Phone) {
return Phone.query();
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl, resolve: PhoneListCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
Here's an example of the code I've used in the application I'm working on, not sure it will help much because its not much different than how you have it already.
Routing
.when('/view/proposal/:id',{
controller : 'viewProposalCtrl',
templateURL : 'tmpls/get/proposal/view',
resolve : viewProposalCtrl.resolveViewProposal
})
Controller
var viewProposalCtrl = angular.module('proposal.controllers')
.controller('viewProposalCtrl',['$scope','contacts','details','rationale',
function($scope,contacts,details,rationale){
$scope.contacts = contacts;
$scope.details = details;
$scope.rationale = rationale;
// [ REST OF CONTROLLER CODE ]
});
// proposalSrv is a factory service
viewProposalCtrl.resolveViewProposal = {
contacts : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Contacts',$route.current.params.id)
.then(function(data){
return data.data.contacts;
},function(){
return [];
});
}],
details : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Details',$route.current.params.id)
.then(function(data){
return data.data.details;
},function(){
return {};
});
}],
rationale : ['$route','proposalSrv',function($route,proposalSrv){
return proposalSrv.get('Rationale',$route.current.params.id)
.then(function(data){
return data.data.rationale;
},function(){
return {};
]
}]
};
Now that I think about it, when I was developing my application I did have a problem and not sure why when I named my resolve function "resolve." This gave me a problem:
.when('/path',{
// stuff here
resolve : myCtrlr.resolve
})
but this did not:
.when('/path',{
//stuff here
resolve : myCtrlr.myResolveFn
})
Another Possibility
The only other thing I can think of, is that you're returning the promise from the $http call and then trying to use appData.data Try using the .then function or one of the other functions (.success,.error) to retrieve the information from the promise.
The problem was NOT due to previously using different version of AngularJS.
Here are the fixes using the code that I have above.
In app.js, you need to declare the controller as controller: 'MainController' and NOT as controller: MainController even though you have var MainController = app.controller('MainController', ....).
Second and biggest thing was that in my index.html I declared my controller already like so:
index.html
body ng-app="HEY" controller="MainController" /body
This was causing the whole Unknown provider error Apparently angular wont tell you that you have already declared the controller that you are using to do the resolve it and that that will cause a weird error that have nothing to do with the resolve.
I hope this helps someone who may have the same problem.
One thing I noticed in angular 1x docs is that YOU DO NOT SPECIFY THE RESOLVED PARAMETER AS AN ANNOTATED DEPENDENCY
So this:
.when('/somewhere', {
template: '<some-component></some-component>',
resolve: {
resolvedFromRouter: () => someService.fetch()
}
})
export default [
'$scope',
'someService',
'resolvedFromRouter'
Controller
]
function Controller($scope, someService, resolvedFromRouter) {
// <= unknown provider "resolvedFromRouter"
}
is wrong. You don't specify the resolved parameter as a dependency, in the docs:
For easier access to the resolved dependencies from the template, the resolve map will be available on the scope of the route, under $resolve (by default) or a custom name specified by the resolveAs property (see below). This can be particularly useful, when working with components as route templates.
So just do this instead:
.when('/somewhere', {
template: '<some-component></some-component>',
resolve: {
resolvedFromRouter: () => someService.fetch()
}
})
export default [
'$scope',
'someService',
Controller
]
function Controller($scope, someService) {
$scope.$resolve.resolvedFromRouter; // <= injected here
}