AngularJS coupling between view and controller - javascript

I have an AngularJS application in which I started off with my view files having the controller defined using the ng-controller directive.
myview.html
<div ng-controller="MyController">
<ul>
<li class="thumb" ng-repeat="item in items">
<span profile ng-click="getItem(item.id)"></span>
</li>
</ul>
</div>
However, I am now using routing and my controller is defined as part of my routeProvider configuration.
myview.html
<div>
<ul>
<li class="thumb" ng-repeat="item in items">
<span profile ng-click="getItem(item.id)"></span>
</li>
</ul>
</div>
router.js
.when('/homepage', {
templateUrl: 'templates/myview.html',
controller: 'MyController'
})
This works, but although at first it seemed like this was helping me to decouple my view from my controller, something feels off as I still have references to scope member variables in my view and these are tied to my controller.
Am I missing something here? What have I gained from specifying MyController in my routeProvider and not in my template?

For all practical purposes I don't believe you gained anything, except from conforming to the standard way of defining routes, views and controllers in AngularJS.
If we're thinking programming principles and MVC, your view now doesn't know anything about the controller, it is only dependent on the model (that'd be $scope in angular), which is fine and perfectly normal in a MVC-architecture.

By defining the controller in your route, you can use the same view (template) in multiple controller (and pass different scoped data)
For example:
.when('/homepage', {
templateUrl: 'templates/myview.html',
controller: 'MyController'
})
.when('/list', {
templateUrl: 'templates/myview.html',
controller: 'MyListController'
})

Related

Problem with ng-if in ng-include html template from root controller

I come from Angular9 and am really used to it, and I have been asked to work a bit on an AngularJS project, which I have never experienced. So I am really struggling with the whole app structure.
My issue is simple: I have a sub-navbar.html template directly injected in my root.html template using ng-include, and I would like to condition the display of one section of this sub-navbar with 'ng-if' (not just hide the section, I don't want it there at all).
I have a backend call which sends me a boolean according to whether the connected user can see the section or not.
The problem I have is that my section is actually never active even when the boolean is 'true'.
Things I tried:
Change the priority of the ng-if and 'ng-controller' directives ---> Broke the app
Add a new 'subnavbar-controller' and declare it as a .state in the app.js ---> Didn't work
Create a custom directive ---> Can't figure out hw the work apparently, didn't work
I unfortunately can't copy all my code, but here are the main pieces I'm working on:
app.js: (I wrote nothing concerning this '$rootScope.adminSection' in the '.run()' function and also tried the same approach directly calling the service without the '$onInit')
$urlRouterProvider.otherwise("/orders");
$stateProvider
.state('root', {
abstract: true,
url: '',
views: {
'': {
templateUrl: "view/root.html",
controller: ['$rootScope', 'AdministratorService', function ($rootScope, AdministratorService) {
const vm = this;
vm.$onInit = function() {
AdministratorService.getAdminSection().then(function (result) {
$rootScope.adminSection = result;
}
)
};
}]
}
}])
root.html:
<div ui-view="root_header"></div>
<div class="row" style="min-height: 600px">
<div class="col-md-2">
<br/>
<div ng-include="'view/subnavbar.html'"></div>
</div>
<div class="col-md-10">
<div ui-view></div>
</div>
</div>
<div ng-include="'view/footer.html'"></div>
subnavbar.html:
<ul class="nav nav-pills nav-stacked" role="tablist">
<li></li>
<li ui-sref-active="active"><a ui-sref="root.contracts"></a><div class='arrow' aria-hidden='true'></div>
</li>
<li ng-if="$rootScope.adminSection" ui-sref-active="active"><a ui-sref="root.administrator">
</a><div class='arrow' aria-hidden='true'></div></li>
<li ui-sref-active="active"><a ui-sref="root.users"></a><div class='arrow' aria-hidden='true'>
</div></li>
</ul>
Any help welcome, thanks in advance !
There are several ways this can work. The reason it is not working now is that $rootScope in the template is not defined. Try, in your template, to replace $rootScope.adminSection with just adminSection.
ngInclude directive creates a new scope which inherits from $rootScope. Therefore, variables in $rootScope should be directly accessible from the template.

Multiple views with angular

So I am trying to display multiple views in angular to help fix the footer problem I am having with this site I am building. I want to make sure that what I have been reading about and trying to mimic is making sense. This is what I have so far.
index.html
<!--Do not code below this line-->
<main ng-view="header"></main>
<main ng-view="body"></main>
<main ng-view="footer"></main>
routes.js file
angular.module('appRoutes', ['ngRoute'])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
views: {
'header': {
temmplateUrl: 'app/views/header.html'
},
'body': {
templateUrl: 'app/views/body.html'
},
'footer': {
templateUrl: 'app/views/footer.html'
}
}
})
I have it working where I have just one view and have my header and footer inside the index.html file but I saw that you can have multiple views and really just switch out the "body" view with other pages.
Any advice would be much appreciated. Thank you
To display multiple views you could use only ng-include.
See https://docs.angularjs.org/api/ng/directive/ngInclude for more ngInclude details.
Here is a example: (notice the wrap in single quotes)
<div id="header">
<div ng-include="'header.html'"></div>
</div>
<div id="content" ng-view></div>
<div id="footer">
<div ng-include="'footer.html'"></div>
</div>
Use ngRoute with ng-view to define a region (e.g div#content) where will be changed the dynamic content (as partial html).
See https://docs.angularjs.org/api/ngRoute/directive/ngView for more ngRoute details.
Good luck!
You can have just one ng-view.
You can change its content in several ways: ng-include, ng-switch or mapping different controllers and templates through the routeProvider.
Alternatively, use ui-router

Angular.js routing: how do I reach endpoint routes?

After trying all I can imagine, and reading several posts here, I think I need your help!
I have a webapp based on node and express on the server and Angular on the client. I am using angular routing.
BASIC INFO
I have the routing set up like the following:
mainApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: 'initial.ejs',
controller: 'controllerInitialView'
})
.when('/home/post', {
templateUrl: 'post.ejs',
controller: 'controllerAddPost'
})
.... other /home/something routes ..
.otherwise({
redirectTo: '/home'
});
}
]);
The html template is organized as follows:
<div class="container-fluid">
<div class="row">
<!-- Left Columns: With links to views -->
<div class="col-xs-2 home-bd-dx">
<ul>
<li>
Post
</li>
...
<li>
Logout
</li>
</ul>
</div>
<!-- Central Columns: Here the views are inserted -->
<div class="col-xs-10">
<div ng-view></div>
</div>
</div>
</div>
The issue is with the Logout link. I have a server serverapp.get('/logout') link which uses passport.js to logout the user. However, I cannot manage to reach that link. Whatever I try transforms my /logout, into /home/logout, and it is handled by Angular rather than by the server.
QUESTION
So here is the question: how can I create links to endpoint routes in Angular without Angular router intercepting them?
ADDITIONAL INFO IF NEEDED
The express server is has a route serverapp.get('/home/*') which delegates these routes to Angular.js by returning the template I sketched above.
I tried with and without a <base href="/home"> tag in the <head> with no luck
I tried creating a route '/home/logout', and then having the angular $window.location.href="/logout"; in the controller of /home/logout. No luck also in this case.
If I understand you correctly, what you're trying to do is disabling deep linking for certain URLs. You can do that by adding target="_self" to the <a> tag.
Try this:
Logout
Now the URL the link is pointing to will be handled by the server instead of Angular.

UI Router not working with Angular not matter what

(angularJS 1.2.5 & ui-router 0.2.7)
Please help its 4 in the morning and its been 2-3hrs since i'm stuck with this, flipped the code multiple times but cudn't make it run.
In my index.html, I have the following code:
<div class="well sidebar-nav sidebar-slide">
<ul class="nav nav-list" style="font-size:17px">
<li class="nav-header">Demand Type</li>
<li><a ui-sref="add14" data-toggle="tab">ADD-14</a></li>
<li><a ui-sref="cash_purchase" data-toggle="tab">Cash Purchase</a></li>
<li><a ui-sref="local_purchase" data-toggle="tab">Local Purchase</a></li>
</ul>
</div>
<div class="hero-unit" ui-view></div>
In my app.js, I have the following code:
var ODS = angular.module('ODS', ['ui.router','ngAnimate']);
//Define Routing for app
ODS.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to /state1
$urlRouterProvider
.when('/add14', '/add14/create_order')
.when('/cp', '/cp/create_order')
.when('/lp', '/lp/create_order')
.otherwise("/intro");
$stateProvider
.state('intro', {
url: "/intro",
templateUrl: "templates/core/intro.html"
})
.state("add14", {
url: '/add14',
templateUrl: 'templates/core/add14.html'
})
.state("add14.create_order", {
url: "/create_order",
templateUrl: "templates/ADD14/add14.create_order.html"
})
.state("add14.own_demand", {
url: "/own_demand",
templateUrl: "templates/ADD14/add14.own_demand.html"
})
}]);
In my add14.html, I have following code:
<a ui-sref=".create_order">Create</a></button>
<a ui-sref=".own_demand">Own Demand</a>
<div ui-view></div>
In my add14.create_order.html & add14.own_demand.jsp i have sample code to print.
Thank You for your patience!
Did you ever get this figured out? I'm running into a similar problem - I find that using <a href='#/url'> seems to work, but I can't access my states via ui-sref either. I've also noticed that the rendered html doesn't auto-generate an href corresponding to the state as the documentation said it would. Fairly confused why it's not working myself.
Heads up: try to make sure you add the "ng-app" directive to your body tag (in your main template), otherwise, it seems angular-ui-router stuff, such as the ui-sref directive, will not be called.
Example:
<html ng-app="myApp">...</html><!-- Nope. Don't do this -->
<html>...<body ng-app="myApp"></body></html><!-- Do this instead -->
You are using both $stateProvider and $urlRouterProvider. try just using $stateProvider instead of both as that could be where your error is. And you don't have controllers for each of your states. Hope this helps you.

In AngularJS, can I use current route in ngSwitch outside of ngView

I am trying to change the page header depending on current view. The header is outside of ngView. Is that possible or do I need to put the header inside the view?
My code looks similar to this:
<div id="header">
<div ng-switch on="pagename">
<div ng-switch-when="home">Welcome!</div>
<div ng-switch-when="product-list">Our products</div>
<div ng-switch-when="contact">Contact us</div>
</div>
(a lot of unrelated code goes here)
</div>
<div id="content>
<div ng-view></div>
</div>
Give each route a name when you are defining it. Then inject $route into the controller, then have the controller publish it into the current scope. You can then bind the ng-switch to $route.current.name
You could inject the $location service and check $location.path(). http://docs.angularjs.org/api/ng.$location
JS:
function Ctrl($scope, $location) {
$scope.pagename = function() { return $location.path(); };
};
HTML:
<div id="header">
<div ng-switch on="pagename()">
<div ng-switch-when="/home">Welcome!</div>
<div ng-switch-when="/product-list">Our products</div>
<div ng-switch-when="/contact">Contact us</div>
</div>
</div>
Seems as it will be different controllers for header and content. Best way for communication between controllers is service. Another way - events. See Vojta answer.
A nice aproach for solving this is maybe to inject $route in your controller and then use it to grab the current route name.
app.controller('YourController', function($scope, $route){
$scope.pagename = $route.current.$$route.name;
});
And you have to name your routes like the following:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/product-list', {
templateUrl: 'views/product-list.html',
controller: 'ProductsController',
name: 'product-list'
}).
when('/home', {
templateUrl: 'views/home.html',
controller: 'HomeController',
name: 'home'
}).
otherwise({
redirectTo: '/'
});
}]);
So when you load a route,the controller will read the current route name and pass it to the view in your pagename variable. Then the view will pick it up and display the correct view as you need.
Hope it helps :)

Categories