I had a working prototype of state views with hardcoded values, but when I tried to include a controller, it breaks the ui-sref links, and they don't seem to point to anything. I can remove the ng-controller attribute and they work again though, and display just fine.
I've also tried attaching ng-controller to a div in the template as well, foregoing a controller in index.html altogether, and while that doesn't break the link, I can't get any expressions in the template to work, and having a controller would be sub-optimal for the purposes of my app if I could avoid it.
What limitations of controllers and views am I misunderstanding?
index.html snippet
<div class="main" ng-controller="MainCtrl">
<a ui-sref="StateA">AAAAA</a>
<div ui-view></div>
</div>
app.js
var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('StateA', {
url: "/a",
templateUrl: "views/a.html",
controller: "MainCtrl"
})
});
MainCtrl.js
app.controller("MainCtrl", [$scope, function($scope, paramGroups) {//empty controller//}]);
Apart from some of the syntax errors you have going on your fundamental problem is understanding of how ui-router works.
When you define something like:
.state('StateA', {
url: "/a",
templateUrl: "views/a.html",
controller: "MainCtrl"
})
It means, that when you go to route /a the partial a.html that will get rendered in your ui-view will get the scope for MainCtrl.
There's no point defining ng-controller='MainCtrl' on the element that is parent of ui-view because, ui-view will automatically get the scope for MainCtrl when the route resolves.
Route breaks when you declare that ng-controller because you are trying to nest same controller inside itself.
Related
When I use ngView and call a controller inside another one, this makes any process twice :
$routeProvider
.when('/', {
templateUrl: '/main.html',
controller: 'main'
})
.when('/user', {
templateUrl: '/user.html',
controller: 'user'
})
});
<body ng-controller="main">
<div ng-view><!--here is another controller --></div>
</body>
When using ngInclude there is not this problem. What is wrong with using ngView?
It looks like if you are using your main controller twice:
By referencing it in the template as ng-controller
In the routing config of the "/" route
Probably you want remove the ng-controller from your index page?
Developing a POC for an application.
Technologies being used : ASP.Net MVC4 and AngularJs.
Initialy while getting started i was using ngRoute and $routeProvider. The links used to redirect to the server to the required controller action and pages used to load in the div marked with ng-view directive. But my requirement was to laod multiple and nested views. So, had to switch to $stateProvider which supports such requirements.
Now i am facing the issue of the links not getting redirected. The "Project" link redirects but the "Opportunity" does not. My requirement is to load a view inside the first div and then one more view into AddOpportunityContainer
Following below is the code which i had written. Can anyone help me what wrong i have been doing. Had already spent quite an amount of tme on it.
Referred Libraries:
angular.js and angular-ui-router.js
The Code:
var GuidanceApp = angular.module('GuidanceApp', ['ui.router']);
var configFunction = function ($stateProvider, $httpProvider, $locationProvider) {
$stateProvider
.state('Projects', {
url: '/Projects',
templateUrl: 'Projects/Index'
})
.state('Opportunity', {
url: '/Opportunity',
templateUrl: '/Opportunity/Index',
views:{
"AddOportunityContainer": {
templateUrl: '/Opportunity/Create'
}
}
});
}
configFunction.$inject = ['$stateProvider', '$httpProvider', '$locationProvider'];
GuidanceApp.config(configFunction);
Following is the HTML of home page. And as you can see, the last div is marked with ui-view now instead of ng-view as in case of ngRoute and $routeProvider
<div>
<ul>
<li>Projects</li>
<li>Opportunity</li>
<li>Adjustments</li>
<li>Summary</li>
</ul>
</div>
<div ui-view></div>
Different partial view to be loaded on click of Opportunity link.
<h2>Opportunity-Index</h2>
<div ui-view="AddOportunityContainer"></div>
Your link for anchor element should be corrected as below without leading '/':
<li>Projects</li>
[EDITED] My app has the following structure:
index.html
<body ng-app = "myApp" ng-controller ="mainController">
<ng-view></ng-view>
</body>
mainView.html (loaded into ng-view through routeProvider in app.js)
<div ng-include src="subview1">
<div ng-include src="subview2">
subview1 and subview2 are set within mainController (mainView's controller) as scope variables:
$scope.subview1= "templates/subview1.html";
$scope.subview2= "templates/subview2.html";
controller1 and controller2 are subview1 and subview2's controllers.
subview1.html (loaded in first div of mainView)
<div ng-controller="controller1">
<button ng-click="loadNewView()"></button>
</div>
controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$scope.$parent.subview1 = "templates/view3.html";
}
}
scope.loadNewView should load a different view (and relative controller) within the div with src="subview1" in mainView.html). Basically it's about refreshing the view itself by raplacing it with another view (and related controller).
I use $parent to update the view in subview1's parent view (i.e. mainView).
however nothing happens and if I try to use $scope.$apply() I get error (digest already in progress).
Any clue?
you can try something like this...
In your stateProvider or in your routeProvider if you using.
var mod = angular.module('example.states', ['ui.router']);
mod.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('exampleState', {
url: '/main',
templateUrl: 'mainView.html',
controller: mainController
});
}
]);
return mod;
So here you have associated your parent controller(let's say the mainController which will be the parent of all others) with its template mainView.html.
Then in your mainView.html,Load all the subview templates.
<div ng-repeat="template in templates">
<ng-include src="template.url"></ng-include>
</div>
templates is an array in your mainController which has the url or path of all your subtemplates.When you use ng-include inside the main template then all subTemplates will automaticlly become the child of the mainTemplate and its Controllers too.In a way it will inherit from the parent Controller.
So suppose if subView1.html is one of the template url you had given in ng-include.Then it will look like
<div ng-controller="subView1Controller">
//Here your code
</div>
And subview2 as
<div ng-controller="subView2Controller">
//Here your code
</div>
This way you will have multiple views on the same page with one url and different controllers with its associated templates and each will inherit from the parent controller which is mainController here.
There, might be better approach than this.
This is what i had used in my project,and its simple to keep your code simple manage.
Okay,so using routeProvider,you can use it like this
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
});
app.controller("mainController",function($scope){
});
app.controller("subView1Controller",function($scope){
});
app.controller("subView1Controller",function($scope){
});
Then in your mainView.html,Load all the subview templates.
<ng-include src="yoursubtemplate1path"></ng-include>
<ng-include src="yoursubtemplate2path"></ng-include>
And then in yoursubtemplate1 use
<div ng-controller="subView1Controller">
//Here your code
</div>
Same for the other templates.
You can set the template src of the subtemplates from your mainController.
app.controller("mainController",function($scope){
$scope.templatesrc="/app/template1.html";
});
And then use it in your template,where you are using ng-include directive.
<ng-include src="templatesrc"></ng-include>
Its better to store template url's in an array and use ng-repeat directive like i had stated before,if you are loading more templates.
And if you want to show the div on some button click lets say in parent controller then use ng-if in the sub-view main and make it true on button click.
This answer is regarding your updated question.
The solution which you had used before,will load all temlplate and once in ng-include and its associated controller making the mainController as parent.
But if you want to load a different view with its newController then you can try something like this.
Just add one more route and call on your event click,but remember this newView's Controller will have no parent-child relation with the mainView's controller.
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
.when('/anyName',{
templateUrl:"templates/view3.html",
controller:temp3Controller
})
});
And in your controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$location.path('/anyName');
}
}
Inject location service in controller1.
I finally found the solution.
The tricks is using
$scope.$parent.$parent.subview1 = "templates/view3.html";
instead of
$scope.$parent.subview1 = "templates/view3.html";
since, basically:
ng-include is the child of mainView
subview1 is the child of ng-include
I'm trying to get ui-router to properly work with nested ui-view elements but I'm having trouble getting the nested view to actually render. Here's my code:
app.js
'use strict';
var lunchrApp = angular.module('lunchr', ['ui.router', 'lunchrControllers']);
lunchrApp.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.
state('mainPage', {
url: '/',
templateUrl: '/partials/main.jade',
controller: 'MainPageController'
})
.state('users', {
url: '/users',
templateUrl: '/partials/users.jade',
controller: 'UserController'
})
.state('users.matching', {
url: '/matching',
templateUrl: '/partials/users.matching.jade'
})
.state('users.matched', {
url: '/matched',
templateUrl: '/partials/users.matched.jade'
})
.state('register', {
url:'/register',
templateUrl: 'partials/register.jade',
controller: 'RegisterController'
});
$locationProvider.html5Mode(true);
}]);
Here's /partials/users.jade (which gets properly displayed in the div(ui-view) in the body tag)
div(class='container')
h1 Welcome
p(ng-repeat='user in users').
Username: {{user.email}}
Firstname: {{user.firstname}}
Lastname {{user.lastname}}
a(ui-sref='users.matching', class='btn btn-default') Start matching me!
a(ui-sref='users.matched', class='btn btn-default') Simulate a match!
div(ui-view)
Here are partials/users.matching.jade
div
h1 We're matching you!
and partials/user.matched.jade
div
h1 You've been matched!
I can successfully navigate to http://localhost:3000/users/matched but when I do, the html is identical to when I go to http://localhost:3000/users.
Why isn't the nested ui-view being correctly populated?
TL;DR
Just put
doctype html
at the top of the jade file that contains <div ui-view>.
If you want more info, there are a number of pretty easy solutions.
More details
The issue basically comes down to the fact that jade is outputting
<div ui-view="ui-view">
which angular can't understand. So you have to make some changes to the output so it's something angular can consume.
Option 1
IMHO, the simplest option would be to put
doctype html
at the top of the jade file that contains <div ui-view>. You must do this even if your jade file is contained within another file that already has doctype html.
Option 2
You can write
.div(ui-view="")
instead of
div(ui-view)
This forces jade to output <div ui-view>.
Option 3
Angular will be fine if you specify a class named ui-view on your div:
<div class="ui-view">
Option 4
Maybe the hackiest way would be to write the raw HTML like this:
<div ui-view>
That makes jade output it exactly the way you typed it.
I have an angular page that has an ng-controller directive and an ng-view directive.
<body ng-controller="MainController">
<h1>Welcome to my main template</h1
<ng-view></ng-view>
</body>
I also have routes configured.
angular.module('app', []).
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider.
when('/', {templateUrl: '/templates/home.html', controller: HomeController}).
when('/start', {templateUrl: '/templates/start.html', controller: StartController});
$locationProvider.html5Mode(true);
}]);
When I click a URL that routes me to /start for example, only StartController runs, not MainController. I guess this kind of makes sense since the main layout has already loaded, and then the template only needs to be loaded now, but there is logic in my MainController that controls part of the template view I need to run.
However, if I refresh the entire page, both controllers run.
Is there any way to make both controllers run? Is this the wrong pattern to follow?
Listen for $routeChangeSuccess on your main controller to get notified when route changes.
app.controller('MainController', function($scope) {
$scope.$on('$routeChangeSuccess', function(event, current, previous, rejection) {
if (current == 'someRoute') {
//execute some route logic
}
});
})
Move the logic from MainController into a service, depend on that service in the individual view-controllers. Then call the service from the view-controllers to get your logic executed.