I'm really lost. I use ui-route in my angular app and i'm trying to extend my base controller. My base controller (appCtrl) works but child controller (navigationCtrl) doesn't on URL app/welcome. Do you know why???
index.html
<body>
<div id="wrap">
<!-- View for login and login-choose -->
<div ui-view="login"></div>
<!-- View for app -->
<div ui-view="app"></div>
</div>
<!-- SCRIPTS -->
<script type="text/javascript" src="./js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="./js/jasny-bootstrap.min.js"></script>
<script type="text/javascript" src="./js/angular.min.js"></script>
<script type="text/javascript" src="./js/angular-ui-router.min.js"></script>
<script type="text/javascript" src="./js/angular-touch.min.js"></script>
<script type="text/javascript" src="./js/app.js"></script>
<script type="text/javascript" src="./js/app.navigation.js"></script>
</body>
app.js
var app = angular.module('tvm', ['ui.router', 'ngTouch']);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
// For any unmatched url, redirect to /state1
$urlRouterProvider.otherwise("/");
// Set up the states
$stateProvider
.state('login', {
url: "/",
views: {
"login": { templateUrl: "./pages/login.html" }
}
})
.state('login-choose', {
url: "/login-choose",
views: {
"login": { templateUrl: "./pages/login-choose.html" }
}
})
.state('app', {
url: "/app",
views: {
"app": {
templateUrl: "app.html",
controller: 'appCtrl'
}
}
})
.state('app.welcome', {
url: "/welcome",
templateUrl: './pages/welcome.html'
})
.state('app.profile', {
url: "/profile",
templateUrl: './pages/profile.html'
});
// remove # from URL
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
app.controller('appCtrl', function($scope) {
$scope.parentMethod = function () {
alert('aaa');
};
});
app.navigation.js
app.controller('navigationCtrl', ['$scope', '$controller', function($scope, $controller) {
// extend app controller
angular.extend(this, $controller('appCtrl', {$scope: $scope}));
var nav = $('nav');
var content = $('#content, #bar');
var navWidth = nav.width() + 'px';
var navIcon = $('#bar .nav_icon .circle');
$scope.circleHover = function(e) {
navIcon.addClass('hover');
};
$scope.circleLeave = function(e) {
navIcon.removeClass('hover');
};
// open / close nav
$scope.toggleNav = function(e) {
if(nav.hasClass('visible'))
closeNav();
else
openNav();
};
// when swipe left to right open nav
$scope.openSwipeNav = function(e) {
openNav();
};
// close nav
$scope.closeNav = function(e) {
var elem = angular.element(e.target);
if( (nav.hasClass('visible')) && (!$(elem).is('#bar')) )
closeNav();
};
// when swipe right to left close nav
$scope.closeSwipeNav = function(e) {
closeNav();
};
var openNav = function() {
nav.animate({
left: 0
}, 400, function() {
$(this).addClass('visible');
});
content.animate({
left: navWidth
}, 400, function() {
$(this).removeClass('full');
});
navIcon.addClass('active');
};
var closeNav = function() {
nav.animate({
left: '-' + navWidth
}, 400, function() {
$(this).removeClass('visible');
});
content.animate({
left: 0
}, 400, function() {
$(this).addClass('full');
navIcon.removeClass('active');
navIcon.removeClass('hover');
});
};
}]);
You are providing the states in wrong way should use the below code. It may help you get out of your problem
// Set up the states
$stateProvider
.state('login', {
url: "/",
views: {
"login": { templateUrl: "./pages/login.html" }
}
})
.state('login-choose', {
url: "/login-choose",
views: {
"login": { templateUrl: "./pages/login-choose.html" }
}
})
.state('app', {
url: "/app",
templateUrl: "app.html" //no need to define the controller here. If this route is not usable else define the controller separately for both app and app.welcome
})
.state('app.welcome', {
url: "/welcome",
templateUrl: './pages/welcome.html',
controller: 'appCtrl' // need to mention the controller in which you wantto perform the functionality of app/welcome
})
.state('app.profile', {
url: "/profile",
templateUrl: './pages/profile.html'
});
Ok I managed to solve it by add angular.extend to base controller
app.controller('appCtrl', ['$scope', '$controller', function($scope, $controller) {
angular.extend(this, $controller('navigationCtrl', {$scope: $scope}));
}]);
And I call controller in my first state:
.state('app', {
url: "/app",
views: {
"app": {
templateUrl: "app.html",
controller: 'appCtrl'
}
}
})
Then it also fires navigationCtrl
Related
In my app, I require to attach multiple url with same state - how do i achieve this?
here is my existing state:
.state('createCase', {
url: '/createCase',
templateUrl: null,
controller: null,
data: {
requireLogin: false
},
also I would like to attache another url as like this:
.state('createCase', {
url: '/createCase?sn=12345', //(12345 is dynamic )
templateUrl: null,
controller: null,
data: {
requireLogin: false
},
here is my current function:
function routeConfig($stateProvider, $locationProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/',
templateUrl: function(){
console.log('from 1oauth');
return 'app/login/login.html';
},
controller: 'loginCtrl as ctrl',
data: {
requireLogin: false
}
})
.state('oauth', {
url: '/oauth',
templateUrl: function(){
console.log('from 2oauth');
return 'app/oauth/oauth.template.html';
},
controller: 'OAuthController as ctrl',
data: {
requireLogin: false
}
})
.state('createCase', {
url: '/createCase',
templateUrl: null,
controller: null,
data: {
requireLogin: false
}
}
})
// if (isWeb()){
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
// }
// $urlRouterProvider.otherwise('/');
$urlRouterProvider.otherwise('/');
}
You don't need to define two different states for same url. In your controller, you can use $state.params object that has query parameters as properties.
Your route
.state('createCase', {
url: '/createCase',
templateUrl: null,
controller: 'MyCtrl',
data: {
requireLogin: false
},
params: {
sn: null
}
Your controller
function MyCtrl($state) {
console.log($state.params);
}
Define in your route:
.state('createCase', {
url: '/createCase?sn', // bind your query param to URL
templateUrl: null,
controller: null,
data: {
requireLogin: false
},
In your controller,
inject $stateParams to dependencies and use it with $stateParams.sn whatever you need.
Example:
$state.go('createCase', {sn:1234}); // move to state with a param
$stateParams.sn // get a value of ==> 1234
Looks like you want to create a parent state and sub states. If you just want to have access to $routeParams you can can pass them to the controller or leave them out when using same state.
(function () {
'use strict';
angular.module('app', ['ui.router'])
.config(routeConfig);
routeConfig.$inject = ['$stateProvider'];
function routeConfig($stateProvider) {
$stateProvider
.state('createCase', {
url: '/createCase',
template: '<h3>Create Case</h3><div ui-view="detail"></div>'
})
.state('createCase.detail', {
parent: 'createCase',
url: '/:sn',
views: { 'detail#createCase': {
template: '{{sn}}',
controller: function($scope, $stateParams){
$scope.sn = $stateParams.sn;
}
}
}
})
}
}());
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script data-require="angular.js#1.5.x" src="https://code.angularjs.org/1.5.8/angular.js" data-semver="1.5.8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.js"></script>
</head>
<body ng-app="app">
<ul>
<li><a ui-sref="createCase">createCase</a></li>
<li><a ui-sref="createCase.detail({sn:'123456'})">createCaseDetail 123456</a></li>
<li><a ui-sref="createCase.detail({sn:''})">createCaseDetail None</a></li>
</ul>
<div ui-view=""></div>
</body>
</html>
I have a state in my app.js :
.state('app.kamus', {
url: '/kamus',
views: {
'menuContent': {
templateUrl: 'templates/kamus.html',
controller: 'Kamus1Ctrl'
}
}
})
...
and :
$urlRouterProvider.otherwise('/app/kamus');
controller :
.controller('Kamus1Ctrl', function($scope, $cordovaSQLite, $ionicLoading, $stateParams, $timeout) {
$ionicLoading.show({
content: 'Loading',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
$scope.selectAll = function() {
$scope.datas = [];
var query = "SELECT * FROM data";
$cordovaSQLite.execute(db, query, []).then(function(res) {
$scope.datas = [];
if (res.rows.length > 0) {
for (var i = 0; i < res.rows.length; i++) {
$scope.datas.push(res.rows.item(i));
}
} else {
console.log("No results found");
}
}).finally(function() {
$ionicLoading.hide();
});
}
$scope.selectAll();
})
I direct the $urlRouterProvider.otherwise to /app/kamus to show kamus page in first launch of my application. But it seems $urlRouterProvider.otherwise is failed to execute $cordovaSQLite.execute(db, query, []) in my selectAll() function on Kamus1Ctrl.
But when I use other pages as my $urlRouterProvider.otherwise, i.e : $urlRouterProvider.otherwise('app/other'), then I go to /app/kamus via my side menu(button ui-sref="app.kamus"), it just works.
How to fix this problem?
Do like this
Index.html
<body>
<div>
<h3>Index page</h3>
<div ui-view="main"></div>
</div>
</body>
kamus.html
<div ui-view="view1"></div>
Controller
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('app');
$stateProvider
.state('app', {
abstract: true,
url: '/app',
views: {
'main': {
templateUrl: 'kamus.html',
controller : 'Kamus1Ctrl'
}
}
})
.state('app.kamus', {
url: '',
views: {
'view1#app': {
template: "Im View1"
}
}
});
});
routerApp.controller('Kamus1Ctrl', function($scope, $cordovaSQLite, $ionicLoading, $stateParams, $timeout) {
alert("Inside controller");
$scope.selectAll = function() {
alert("Inside selectAll");
//rest of the code
}
$scope.selectAll();
})
NOTE: In ui-router dot operator is used for inner states.
I have application in angularJs and it will have different modules with different JS files.for js file optimization I am going to implement requireJS.
There is (broken) plunker
My angularJs code is like this in app.js:
var app = angular.module("webapp", ['ngRoute']);
app.run(['$rootScope', '$state','$urlRouterProvider',
function ($rootScope, $state,$urlRouterProvider) {
$urlRouterProvider.otherwise('/index.html');
$stateProvider
.state('root.home',{
url: '/index.html',
views: {
'header': {
templateUrl: 'modules/header/html/header.html',
controller: 'headerController'
},
'content-area': {
templateUrl: 'modules/home/html/home.html',
controller: 'homeController'
},
'footer': {
templateUrl: 'modules/common/html/footer.html',
controller: 'footerController'
}
},
data: {
displayName: 'Home',
}
})
.state('root.about',{
url: '/index.html',
views: {
'header': {
templateUrl: 'modules/header/html/header.html',
controller: 'headerController'
},
'content-area': {
templateUrl: 'modules/home/html/about.html',
controller: 'aboutController'
},
'footer': {
templateUrl: 'modules/common/html/footer.html',
controller: 'footerController'
}
},
data: {
displayName: 'About',
}
})
}]);
I added the following code in my main.js file
require.config({
baseUrl: "",
// alias libraries paths. Must set 'angular'
paths: {
'angular': 'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min',
'angular-route': 'http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-route.min',
'angularAMD': 'http://cdn.jsdelivr.net/angular.amd/0.2.0/angularAMD.min'
},
// Add angular modules that does not support AMD out of the box, put it in a shim
shim: {
'angularAMD': ['angular'],
'angular-route': ['angular']
},
// kick start application
deps: ['app']
});
and also added requirejs in html
<head>
<link rel="stylesheet" href="style.css">
<script data-main="main.js" src="http://marcoslin.github.io/angularAMD/js/lib/requirejs/require.js"> </script>
<script src="js/app.js"></script>
</head>
how can I define requirejs module or implement with my angularjs UI-Rooter?
EXTEND:
In your Example You added the above code in app.js
define([], function() {
var app = angular.module('webapp');
return app;
})
I added above code to script.js.Also In my app.js file contain all the UI router things and I changed the main.js with following code
require.config({
//baseUrl: "js/scripts",
baseUrl: "",
// alias libraries paths
paths: {
// here we define path to NAMES
// to make controllers and their lazy-file-names independent
"testController" : "modules/test/js/controller/testController",
},
deps: ['js/script'] // changed section
});
but in my browser console I am gettnig this error "NetworkError: 404 Not Found .../default/app.js" .how can I solve this issue.I directly added this js file through the html.but I am getting this error.
As discussed in comments and related to this plunker: http://plnkr.co/edit/iV7fuG5mkoTQ2JoKk9e0?p=preview
I followed the Q & A:
angular-ui-router with requirejs, lazy loading of controller
And updated that plunker and make it working.
There are many changes. E.g. we should keep a reference to controller providers:
var app_cached_providers = {};
app.config(['$controllerProvider',
function(controllerProvider) {
app_cached_providers.$controllerProvider = controllerProvider;
}
]);
And inside of our mapped controllers (e.g. controller_home.js) register that:
define(['app'], function (app) {
// the Content Controller
// is added into the 'app' module
// lazily, and only once
app_cached_providers
.$controllerProvider
.register('HomeCtrl', function ($scope) {
$scope.message = "Message from HomeCtrl";
});
});
Also, this would be a helper method to make other stuff a bit simplier
var loadController = function(controllerName) {
return ["$q", function($q) {
var deferred = $q.defer();
require([controllerName], function() {deferred.resolve(); });
return deferred.promise;
}];
}
And here we will use it to extend state definitions. Firstly the root state:
$urlRouterProvider.otherwise('/root');
$stateProvider
.state('root',{
url: '/root',
templateUrl: 'view_root.html'
});
Now states loading controller async way:
var root_home = {
//url: '/index.html',
url: '/home',
views: {
'' : {templateUrl: 'view_home.html', controller: 'HomeCtrl' },
},
data: {
displayName: 'Home',
},
resolve : { }
};
root_home.resolve.loadTopMenuCtrl = loadController("HomeCtrl");
var root_about = {
//url: '/about.html',
url: '/about',
views: {
'' : {templateUrl: 'view_view1.html', controller: 'View1Ctrl' },
},
data: {
displayName: 'About',
},
resolve : { }
};
root_about.resolve.loadContentCtrl = loadController("View1Ctrl");
$stateProvider
.state('root.home', root_home)
.state('root.about', root_about)
Check it all in action here
i'm trying to make an app where the first time you use it I save some information locally. My purpose is that when the next times a person open the app it will be shown another page.
The problem is that I don't know how to load a simple page (not a part like a template) from my controller function.
Here my html
<body ng-app="starter" ng-controller="MainCtrl">
<ion-content class="center" [....]
<button class="button button-calm button-full button-clear button-large" ng-click="saveAll(name, job)">
<span style="font-size: 1.4em;">start</span>
</button>
</ion-content>
</body>
app.js
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('home', {
url: "/home",
controller: "HomeCtrl",
template: "<h1>Home page</h1>"
})
$urlRouterProvider.otherwise('/first')
})
.controller('MainCtrl', function($scope, $localstorage, $location) {
$scope.setName = function(name) {
if (name) {
$localstorage.set('name', name.toLowerCase());
console.log(name);
}
}
$scope.getName = function() {
alert($localstorage.get('name'));
}
$scope.setJob = function(job) {
if (name) {
$localstorage.set('job', job.toLowerCase());
console.log(job);
}
}
$scope.getJob = function() {
alert($localstorage.get('job'));
}
$scope.saveAll = function(name, job) {
if (name) {
$localstorage.set('name', name.toLowerCase());
console.log(name);
}
if (job) {
$localstorage.set('job', job.toLowerCase());
console.log(job);
}
if (name && job) {
$location.path("home");
}
}
})
You can navigate routes using:
$location.path('/home');
or:
$state.go('home');
So.. in your MainCtrl you could put something like this:
$scope.getName = function() {
return $localstorage.get('name');
};
$scope.getJob = function() {
return $localstorage.get('job');
};
var init = function(){
if($scope.getName() && $scope.getJob()){
$location.path('/home');
}
};
init();
UPDATE:
Ionic has ui-router installed by default. ui-router documentation.
Each route accept a templateUrl property. I don't know which is you folder structure so you need to change them to work correctly:
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
controller: 'HomeCtrl',
templateUrl: 'home/home.html'
})
.state('first', {
url: '/first',
controller: 'FirstCtrl',
templateUrl: 'first/first.html'
})
.state('second', {
url: "/second",
controller: "SecondCtrl",
templateUrl: 'second/second.html'
});
$urlRouterProvider.otherwise('/first');
})
the stateProvider of my app have a nested view (base.gallery -> base.gallery.detail) and if i click on a link inside my gallery it should show the detailview, but it doesn't...
the link looks good for me, but it only changes the url in the browser and it logs "get displayed" from the onEnter-function, but it doesn't display the template("modules/album/detail/view/detail.html") in my ui-view...
e.g.: for my link <a ui-sref="base.photos.detail(params(item.id))" class="list-item-link" href="/gallery/21/detail/457">
.state("base", {
abstract: true,
templateUrl: 'modules/base/views/base.html',
controller: function($scope, navigationData){
$scope.navigation.data = navigationData;
},
resolve:{
navigationData:function(navigationSvc){
var response = navigationSvc;
return response;
}
}
})
.state("base.categories", {
url: "/categories",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data){
$scope.settings.data = data;
$scope.settings.type = "categories";
},
resolve:{
data:function(listSvc){
var response = listSvc.load("categories");
return response;
}
}
})
.state("base.category", {
url: "/category/:id",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data){
$scope.settings.data = data;
$scope.settings.type = "galleries";
},
resolve:{
data:function($stateParams, listSvc){
var response = listSvc.load("category/"+$stateParams.id);
return response;
}
},
})
.state("base.gallery", {
url: "/gallery/:id",
templateUrl: "modules/album/list/view/list.html",
controller: function($scope, data, $stateParams){
$scope.settings.data = data;
$scope.settings.type = "photos";
},
resolve:{
data:function($stateParams, listSvc){
var response = listSvc.load("gallery/"+$stateParams.id);
return response;
}
}
})
.state("base.gallery.detail", {
url: "/detail/:photo_id",
templateUrl: "modules/album/detail/view/detail.html",
controller: function($scope, $stateParams){
console.log("doesn't get displayed ");
$scope.settings.type = "photo";
},
onEnter: function(){
console.log("get displayed");
}
})
html of my index where i load all my lists and i als want to display my detail view inside that ui-view...
...
<div class="content" ui-view></div>
...
html of my list view
<li class="list-item" ng-repeat="item in list.data">
<a ui-sref="{{state}}(params(item.id))" class="list-item-link">item.title</a>
</li>
UPDATE
k i got it ;) i need views and then use the # to target it in the same ui-view from my index.html
.state("base.gallery.detail", {
url: "/detail/:photo_id",
views:{
"#" : {
controller: function($scope, $stateParams, listSvc){
$scope.settings = {};
$scope.settings.type = "photos";
$scope.photo = listSvc.data[$stateParams.id_photo-1];
console.log($stateParams);
},
template: "<h2>detail</2><div>{{photo.title}}</div>"
}
});