Angular ui router controlleras syntax not working - angularjs

I an trying to develop an angular app using ui router, however I am stuck trying to get the controllerAs syntax working correctly.
my stateProvider looks like this
$stateProvider
.state('microsite', {
url: "/",
templateUrl: "microsite.tmpl.html",
abstract: true
})
.state('microsite.home', {
url: "",
templateUrl: "home.tmpl.html",
controller: 'MicrositeController as vm',
data: {
page_name: 'Introduction'
}
})
.state('microsite.features', {
url: "/features",
templateUrl: "features.tmpl.html",
controller: 'MicrositeController as vm',
data: {
page_name: 'Features'
}
})
.state('microsite.about', {
url: "/about",
templateUrl: "about.tmpl.html",
controller: 'MicrositeController as vm',
data: {
page_name: 'About'
}
});
As you can see I setup an abstract default view, and three pages.
I have also assigned a data object with a page_name for each page. This feeds into my controller
myapp.controller('MicrositeController', ['$state', function($state) {
var vm = this;
vm.page_name = $state.current.data.page_name;
vm.sidenav_locked_open = false;
vm.toggleSideNav = function() {
if ($mdMedia('gt-sm')) {
vm.sidenav_locked_open = !vm.sidenav_locked_open;
} else {
$mdSidenav('left').toggle();
}
}
}]);
and then delivers the name to the page via the vm.page_name variable.
However this is not happening. The variable never makes it to the page.
Also I have a vm.toggleSideNav function that is suppose to open and close the sidenav, but that never gets called.
the toolbar with the sidenav button is this
<md-toolbar layout="row" class="md-whiteframe-glow-z1 site-content-toolbar">
<div class="md-toolbar-tools docs-toolbar-tools" tabIndex="-1">
<md-button class="md-icon-button" ng-click="vm.toggleSideNav()" aria-label="Toggle Menu">
XXX
</md-button>
<h1>{{vm.page_name}}</h1>
</div>
</md-toolbar>
here is a plnkr example http://plnkr.co/edit/Na5zkF?p=preview
I am looking for someone to help me figure out the last piece on how to get the toggleSideNav function to get called when I click on the xxx button, and how to get the title to display in the toolbar.

From the Docs:
controller
(optional)
string
function
Controller fn that should be associated with newly related scope or the name of a registered controller if passed as a string. Optionally, the ControllerAs may be declared here.
controller: "MyRegisteredController"
controller:
"MyRegisteredController as fooCtrl"
controller: function($scope, MyService) {
$scope.data = MyService.getData(); }
— UI Router $stateProvider API Reference.
According to the Docs, your controller declaration is correct.
controller: 'MicrositeController as vm'
You need to look for your problem elsewhere.
UPDATE
Put the controller in the root state:
$stateProvider
.state('microsite', {
url: "/",
templateUrl: "microsite.tmpl.html",
//IMPORTANT == Put controller on root state
controller: 'MicrositeController as vm',
abstract: true
})
.state('microsite.home', {
url: "",
templateUrl: "home.tmpl.html",
̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶:̶ ̶'̶M̶i̶c̶r̶o̶s̶i̶t̶e̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶ ̶a̶s̶ ̶v̶m̶'̶,̶
data: {
page_name: 'Introduction'
}
})
.state('microsite.features', {
url: "/features",
templateUrl: "features.tmpl.html",
̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶:̶ ̶'̶M̶i̶c̶r̶o̶s̶i̶t̶e̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶ ̶a̶s̶ ̶v̶m̶'̶,̶
data: {
page_name: 'Features'
}
})
.state('microsite.about', {
url: "/about",
templateUrl: "about.tmpl.html",
̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶:̶ ̶'̶M̶i̶c̶r̶o̶s̶i̶t̶e̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶ ̶a̶s̶ ̶v̶m̶'̶,̶
data: {
page_name: 'About'
}
});
})
The DEMO on PLNKR

Try adding the option controllerAs: 'vm' to the state params instead defining the controller as in the controller option.

Try adding the option controllerAs: 'vm' to the state params instead defining the controller as in the controller option.
or, if I'm not mistaken, you can add
myapp.controller('MicrositeController as vm' ...

Related

Show in url previous state after the next

I have 3 level routing, in url it looks like site.com/Jonny/2. But now I need this looks site.com/2/Jonny or site.com/10/Kelly. But index.name.page it's next page, after index.name, so I can't understand how to swap 3rd and 2nd state. Is it possible?
$stateProvider
.state('index', {
url: '',
controller: 'MainCtrl'
})
.state('index.name', {
url: '#:name',
views: {
'#': {
templateUrl: 'app/names/name.html',
controller: 'NameCtrl'
}
}
})
.state('index.name.page', {
url: '/:number',
templateUrl: 'app/pages/page.html',
controller: 'PageCtrl'
})
inject $state service to your controller, then in your controller...
CONTROLLER
$scope.changeState = function () {
$state.go('where.ever.you.want.to.go', {stateParamKey: exampleParam});
};
and add ng-click to your button
HTML
<button ng-click="changeState()">Change State</button>

controller undefined in named views

Following works perfect.
In my application file app.js, i have states like
.state('nna.home',
{
url: '/home',
views: {
templateUrl: 'views/home.html'
}
})
//home.html is like
<script src="../controllers/home.js"></script>
<div class="container cf" ng-controller="home">
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // works
});
But as soon as I try to use named views like following. It stops routing
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'home.html',
controller: 'home',
resolve: {
deps: function ($ocLazyLoad) {
return $ocLazyLoad.load('homecontroller.js');
}
}
},
}
// my home.js is included correctly in all cases have code like
alert(2); // works
app.controller('home', function ($scope) {
alert(2); // Does not work
});
Plunker
I can use them fine as long as i load all controller files in index but i want to load controllers only with views not all the way in index
Probably the issue is with my understanding about named views, but i am stuck to know the reason that why the home is undefined even when i can show with alert that file had been successfully added
Try this:
.state('nna.home',
{
url: '/home',
views: {
'v1': {
templateUrl: 'views/home.html',
controller: 'home'
}
}
})
There is a working plunker
These could be the states:
.state('nna', {
template: '<div ui-view="v1"></div>',
})
.state('nna.home', {
url: '/home',
views: {
'v1' : {
templateUrl: 'views/home.html',
controller: 'home',
},
}
});
And these links are working now:
<a href="#/home">
<a ui-sref="nna.home">
Check it in action here

Relative sibling URL in angularJS HTML template

Say i am on a page http://localhost/#/edit/10/step2 and i want to have a link (anchor tag) that takes me to http://localhost/#/edit/10/step1.
What shall one put in ng-href="" and could this be achieved without specifying id (10) in the link?
<a ng-href="step1">Previous</a>
edit (routing):
.config(["$stateProvider", "$urlRouterProvider", "$httpProvider", ($stateProvider: ng.ui.IStateProvider, $urlRouterProvider: ng.ui.IUrlRouterProvider, $httpProvider: ng.IHttpProvider) => {
$urlRouterProvider.otherwise("/home");
$stateProvider
.state("MyModule", {
template: "<div ui-view></div>"
})
.state("home", {
url: "/home",
templateUrl: "App/home.html",
controller: "homeController as ctrl"
});
$httpProvider.interceptors.push("busyHttpInterceptor");
}]);
state (edit):
.state("edit", {
url: "/edit/:id",
templateUrl: "App/edit.html",
controller: "editController",
controllerAs: "ctrl",
resolve: {
}
})
I think you can do the redirection by a ng-click function :
//for the 'state', you can add a new one or edit the existing one depending on your requirement and restirctions
//Add a new one:
.state("edit.action", {
url: "/edit/:id/:action",
templateUrl: "App/edit.html",
controller: "editController",
controllerAs: "ctrl",
resolve: {
}
})
//in the html
<a ng-click=goToAction("step1")>Previous</a>
//in the controller 'editController', inject the service '$stateParams' and '$state'
$scope.goToAction = function(action) {
//get the ':id' from the url
var currentId = $stateParams['id'];
$state.go('edit.action', {
id: currentId,
action: action
});
}
If you want you can also apply regex to the parameter part of the url:
url: "/edit/{id:[a-zA-Z0-9]*}/:action

Ionic controllers alias not working when using sidebar

I have an app built using ionic framework, I follow the instructions on ionicframework learn page and now I am using the native sidemenu. The problem is, I can't use controller alias. Here is a snipet of my app.js with the route config:
angular.module('checklist-atendimento', [
'ionic',
'oc.lazyLoad',
'ngStorage',
'ngCordova',
'ngMask'
])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider.otherwise('/app/atendimento/1');
$httpProvider.interceptors.push('TratamentoDeErrosService');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
views: {
'conteudo': {
templateUrl: 'app/templates/menu.html'
}
}
})
.state('app.inicio', {
url: '/inicio',
views: {
'menuContent': {
templateUrl: 'app/views/inicio.html',
controller: 'InicioController',
}
}
})
.state('app.atendimento', {
url: '/atendimento/:codMenu',
views: {
'menuContent': {
templateUrl: 'app/views/atendimento.html',
controller: 'AtendimentoController',
controllerAs: 'atendimentoCrl'
}
}
})
});
As you can see, I have 2 states, one without controllerAs (InicioController) and the other using controllerAs (AtendimentoController).
In controller I put
$scope.test ="TEST!!!"
and in the view I put
<b>{{atendimentoCtrl.test}}<b>
Nothing happens, if I use just {{test}}, but the text is shown.
Anyone knows how to do it ?
EDIT:
HERE there is a example of what a talking about:
http://plnkr.co/ohL5HE
Look inside ItemCtrl and inside index.html, on item.html.
I tried use an alias to controller but it don't works.
You need to change
$scope.test ="TEST!!!"
to:
this.test ="TEST!!!"
The issue here is just a typo... This is a controller state
.state('app.atendimento', {
url: '/atendimento/:codMenu',
views: {
'menuContent': {
templateUrl: 'app/views/atendimento.html',
controller: 'AtendimentoController',
controllerAs: 'atendimentoCrl'
}
}
})
where we can see 'atendimentoCrl'. And here is a view statement
<b>{{atendimentoCtrl.test}}<b>
where we can see atendimentoCtrl (compare Ctrl suffix and Crl above)
So, there is missing t in the controllerAs

How To Autoload ui-view on nested views?

I have code like this
<a ui-sref="nested.something">something</a>
<div ui-view="nested.something"></div>
how to load ui-view without click ui-sref ?
EXTEND - related to this plunker provided by OP in the comments above
The state definition is:
.state('store', {
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
Then in this updated plunker we can see that this would do the job
//$urlRouterProvider.otherwise('/store');
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('store.detail');
return $location.path();
});
Reason? states do not have defined url. Which is a bit weird. So, I would honestly rather suggested to do it like this (the link to such plunker):
$urlRouterProvider.otherwise('/store/detail');
//$urlRouterProvider.otherwise(function($injector, $location){
// var state = $injector.get('$state');
// state.go('store.detail');
// return $location.path();
//});
$stateProvider
.state('store', {
url: '/store',
views: {
'store': {
templateUrl: 'store.html'
}
}
})
.state('store.detail', {
url: '/detail',
views: {
'store_detail': {
templateUrl: 'store_detail.html'
}
}
})
There is a working plunker
ORIGINAL
We can use the .otherwise(rule) of $urlRouterProvider, documented here
$urlRouterProvider.otherwise('/parent/child');
As the doc says:
otherwise(rule)
Defines a path that is used when an invalid route is requested.
So, this could be used for some default - start up "redirection"
The .otherwise() could be even a function, like shown here:
How not to change url when show 404 error page with ui-router
which takes '$injector', '$location' and can do even much more magic (on invalid or startup path)
$urlRouterProvider.otherwise(function($injector, $location){
var state = $injector.get('$state');
state.go('404');
return $location.path();
});
ALSO, if we want to fill in some more details into some nested viesw, we can do it by defining multi-named views:
.state('parent.child', {
url: "/child",
views: {
'' : {
templateUrl: 'tpl.child.html',
controller: 'ChildCtrl',
},
'nested.something#parent.child' : {
templateUrl: 'tpl.something.html',
},
}
})
So, if the tpl.child.html will have this anchor/target:
<i>place for nested something:</i>
<div ui-view="nested.something"></div>
it will be filled with the tpl.something.html content
Check it in action here

Resources