Trying to leverage AngularJS UI States and using resolves to set vars.
I currently have this in my app.js --
var stateConfig = ['stateHelperProvider', function(stateHelperProvider) {
stateHelperProvider
.state({
name: 'events',
url: '/' + artistSlug,
templateUrl: "/templates/events/events.html",
controller: "EventsCtrl",
resolve: {
artist: function(artist) {
return artist.getArtist();
}
}
});
Within the EventsCtrl I have the following --
angular.module('artist.events.controllers', []).
controller('EventsCtrl', ['$filter', '$rootScope', '$scope', '$state', '$stateParams', '$location', 'artist', function($filter, $rootScope, $scope, $state, $stateParams, $location, artist) {
$scope.artist = artist;
On my local dev machine, it resolves correctly. Within prod however, $scope.artist returns nothing. I believe it could be related to compiling based on precompiling and minification. Unsure how to fix though. Thoughts?
Unless you're using a build tool like ng-annotate, you will have to provide the DI annotation for the resolve properties, ie
resolve: {
artist: ['artist', function(artist) {
return artist.getArtist();
}]
}
I would consider renaming your resolve property so it is different to your artist service. At least that way, you would have gotten an error about an unresolved provider. Something like eventArtist would be my pick.
Related
What seems to be an issue for me is how to use $state.go(state, params) and have params persist through to the state's controller, regardless of a component. The plunkr I've setup that demonstrates this is linked here: https://plnkr.co/edit/u5VaMZIBtVoBGbAZaQe0?p=preview
Basically what I'm doing is setting up 2 states, one links to the other. I'm using $state.go to go one of those states with passed parameters. It doesn't appear those parameters are passed though and I'm wondering why this is.
I'm using AngularJS version 1.6.6 and ui.router version 0.4.2 if that makes a difference or not.
var app = angular.module("yay", ['ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
var states = [
{
name: 'paramsDontWork',
url: '/doesntwork',
template: '<div>hi{{variable}}</div><a style="color:blue;" ng-click="goto()">goto</a>',
controller: ['$scope', '$state', '$stateParams', function($scope, $state, $stateParams) {
$scope.variable = 'hi';
$scope.goto = function() {
$state.go('newplace', { should: "should"});
};
}],
},
{
name: 'newplace',
url: '/newplace',
template: 'new place {{should}} have params<br><a ui-sref="paramsDontWork">hi</a>',
controller: ['$scope', '$state', '$stateParams', function($scope, $state, $stateParams) {
console.log($stateParams);
$scope.should = $stateParams.should;
}]
}
];
states.forEach(function(state) {
$stateProvider.state(state);
});
$urlRouterProvider.when('', '/doesntwork');
}]);
Routes must explicitly specify any parameters that can be overwritten (e.g. transition from another route) as part of their state configuration.
Relevant guidance from the UI-Router documentation:
Any parameters that are not specified will be inherited from currently defined parameters. Only parameters specified in the state definition can be overridden, new parameters will be ignored.
(Emphasis mine.)
In your example, /newplace doesn't specify a params property to provide the additional non-URL parameter.
All you need to do to ensure value of should from /doesntwork gets passed is to explicitly declare it as part of /newplace as a parameter with some default value:
{
name: 'newplace',
...
params: { should: null },
}
Plunker fork to demonstrate the above.
I'm running into the following issue with my code:
Error: [$injector:strictdi] controller is not using explicit annotation and cannot be invoked in strict mode
I've implemented the explicit annotation as seen below, but still can't get it to work.
var paymentSummaryTemplate = require('./paymentsummary.html');
function PaymentController($scope, $log, $translate) {
...
}
PaymentController.$inject = ['$scope','$log', '$translate'];
p3dng
.controller('PaymentController', PaymentController)
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/paymentsummary', {
templateUrl: paymentSummaryTemplate,
controller: PaymentController,
controllerAs: 'paymentsummary',
resolve: getInitData(['campaign', 'event'])
});
}]);
How do I pass the resolve validToken value to my controller?
Config:
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/recover/:token', {
templateUrl: 'recover.html',
controller: 'recoverCtrl',
resolve: {
validToken : function(){
return "INVALID TOKEN"
}
}
});
}])
Controller:
.controller('recoverCtrl', ['$location','$scope','$http', '$routeParams', '$rootScope',
function($location,$scope,$http,$routeParams,$rootScope,validToken) {
console.log(validToken);
// Rest of controller code.
}
]);
I would like to do this without removing the []'s so the code could eventually be minifed. The below example is working as I expected so I know that all of my code it working, I'm just not sure what I should add to the above code to make it function similarly.
.controller('recoverCtrl', function($location,$scope,$http,$routeParams,$rootScope,validToken) {
console.log(validToken);
//Other code
});
Figured it out thanks to Etsus.
I just needed to add the object key as a string while injecting and it was able to determine that it was a resolve key
.controller('recoverCtrl', ['$location','$scope','$http', '$routeParams', '$rootScope', 'validToken', function ($location, $scope, $http, $routeParams, rootScope, validToken) {
console.log(validToken);
}]);
I'm getting following error if I don't annotate the dependencies for an inline controller function for a route (I'm using strict DI mode and all other codes are annotated so that js-minification doesn't break my code):
https://docs.angularjs.org/error/$injector/strictdi?p0=function(AuthService,%20$state
Here is the logout route code:
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider', '$urlRouterProvider) {
$stateProvider.state('logout', {
url: '/logout',
controller: function(AuthService, $state) {
AuthService.logout();
$state.go('login');
}
}
}]);
Is there any technique to declare inline annotation for the above two dependent services (AuthService, $state) of the inline controller ?
I know the bellow work-around :
.state('logout', {
url: '/logout',
controller: LogoutController
});
function LogoutController (AuthService, $state) {
AuthService.logout();
$state.go('login');
}
LogoutController.$inject = ['AuthService', '$state'];
this works but just wanted to checkout if anyone knows any smart short-cut ?
Try
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider.state('logout', {
url: '/logout',
controller: ['AuthService', '$state', function(AuthService, $state) {
AuthService.logout();
$state.go('login');
}]
}
}]);
Not sure if that will work. Usually we separate our controllers into files for ease of use, rather than writing them inline in the config.route.js file.
Just to add more details here, this is expected for inline controllers.
See https://github.com/olov/ng-annotate/issues/50.
Either not inline them or add apply controller: /* #ngInject */ function(service1){ ... }.
The /* #ngInject */ tells ngannotate to apply annotation here.
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