Angular ui-router reloading ng-include outside ui-view - angularjs

Probably it's the entire layout wrong but here is my situation, I'm using a Meanjs.org stack with Angular ui-router.
I have a layout like this:
<div data-ng-include="'/modules/core/views/header.client.view.html'"></div>
<div id="page-content" class="clearfix" fit-height>
<div id="wrap" data-ui-view="" class="mainview-animation"></div>
</div>
Now I need to reload the controller inside the header.client.view.html when I change the $state.
For example when I'm in the sign-in page and I login I need to reload the header controller, but having this it's not possible because the ui-router change only the ui-view part with the relative template:
// this change only ui-view, doesn't care about the ng-include before
state('home', {
url: '/',
templateUrl: 'modules/core/views/home.client.view.html',
});
I found the possibility to add more ui-view to the state so I could add a ui-view2 for the header instead using the ng-include but this means having the ui-view2 on each state.
Any suggest?

You might not need to "reload the controller" every time the state changes, instead make your controller react to the state change on the fly and update its properties.
Check out the ui-router $stateChangeSuccess event.

First at all you need to listen #Matti Virkkunen
It's better to listen the state in your header's controller with "$stateChangeSuccess"
So you just have to declare a controller for your header. And inside your header controller add something like this.
$scope.$on('$stateChangeSuccess', function () {
// Do what you want for example check if the current state is home with $state.is('home');
});
Do not forget to declare your controller in your template
<div data-ng-controller="HeaderController" data-ng-include="'/modules/core/views/header.client.view.html'"></div>
<div id="page-content" class="clearfix" fit-height>
<div id="wrap" data-ui-view="" class="mainview-animation"></div>
</div>

Related

Use ui-view as the template for state inside ui-router instead of an external template

I have an app that is currently using the angular ui-router module dependency. The only aspect of the ui-router that I'm currently employing is the ability to apply/modify $stateParams to $scope and vice versa so the URL can change the way data is displayed in the controller to a user on arrival (i.e. url?param=something will filter the data by something).
I have the following in my app.config to set the state:
$stateProvider
.state('root', {
url: '/?param',
templateUrl: 'template.html',
controller: 'listController',
params: {
param: {
value: 'something',
squash: true
}
}
});
On my homepage, template.html successfully loads when the app is instantiated as such:
<div ng-app="myApp">
<div ui-view>
</div>
</div>
However, I have reached a roadblock and realize that calling the template from within templateUrl isn't going to work, as this app is being built inside another framework and therefore needs to be called from within the homepage itself to access its full capabilities.
Being a noob at AngualrJS, I was wondering if anyone can tell me what the best way is to accomplish this while still keeping the logic of $stateParams and other ui-router capabilities intact for the future.
For instance, could I just remove the templateUrl parameter from my state and call the controller directly inside the ui-view like this:
<div ng-app="myApp">
<div ui-view>
<div ng-controller="listController">
do something
</div>
</div>
</div>
I also looked into changing the entire logic from using ui-router to simply using the $location service but I'm wondering if there is a way to accomplish this without needing to over-do everything.

How to update variables in ng-include view

I have a form and a view that shows data from that form. I want to separate form and view (which will be more that one).
Here is my code:
<div data-ng-controller="dataController" class="container">
<div data-ng-view></div>
<div ng-include="templates.simple" scope="data"></div>
</div>
And the included view shows initial data good, but does not react on any data change. How do I fix it?
data is and object with some fields.
templates.simple is a scope variable with template url
Code example: http://plnkr.co/edit/ibrsBaq8osYuEODGiM6O
The reason why binding is not working is you are reinitalizing an createDataController which is again creating data object for that ng-view template. This could be solve by removing createDataController controller from route.
Code
$routeProvider
.when('/', {
templateUrl: 'form.html',
//controller: 'createDataController'
})
Plunkr Here
Update
Other way would be if you want to load your controller twice still it doen't make any sense though. You could do this by writing ng-init on outside div, Instead of declaring that variable from controller.
<div data-ng-controller="createDataController" ng-init="data = {name: 'texy'}">
<div data-ng-view></div>
<div data-ng-include="'template.html'"></div>
</div>
Updated Plunkr

Changing attributes of enclosing containers based on current view

This is rather a conceptual than a strictly technical question.
I have the following index.html:
<div class="container"><div ng-view=""></div></div>
In my app.js, I have the following route configuration:
$routeProvider
.when('/questions', {
templateUrl: 'views/questions.html',
controller: 'QuestionsCtrl'
})
.when('/result', {
templateUrl: 'views/result.html',
controller: 'ResultCtrl'
})
.otherwise({
redirectTo: '/questions'
});
Which means that, based on the URL, different views are loaded in <div ng-view="">. Now, in order to have those views correctly rendered, I need to set style attributes on the enclosing <div class="container"> (I use Leaflet.js in one of those views and thus I need to temporarily set the width and height of the container to 100%, for a full screen map).
How would I do this best, i.e. "The Angular Way"? I looked at the $viewContentLoaded event of the ngView directive, but it doesn't seem to be the right thing as it seems to be only fired when the respective view is completely loaded and not at the initialization of the view (and thus the map, which needs a correctly styled container from beginning on). Should I use a controller that is defined on the body tag, for example? Or a service? I am completely clueless and want to make it right.
Use a controller that listens to $routeChangeSuccess on the $rootScope.
<body ng-app="X" ng-controller="app">
<div class="container" ng-class="containerClass">
<div ng-view=""></div>
</div>
</body>
angular.module('X').controller('app', function($rootScope, $route) {
$rootScope.$on('$routeChangeSuccess', function(){
$rootScope.containerClass = angular.lowercase(($route.current.controller || '').replace(/Ctrl$/, ''));
});
});

Is it possible to use a function to insert the template path for ng-include?

I have tried to use a function to load the path to a template into an ng-include directive. I hoped that the argument to my function would render due to its insertion in ng-include. But it doesn't work. Here is what I have so far:
HTML:
<div ng-include="'{{content}}'"></div>
...
<div ng-click="showContent('views/my_content.html')">
Angular:
$scope.showContent = function(attrs){
$scope.content = attrs;
};
When I click on the div that has ng-click I can see that {{content}} has been replaced with the template path, but the template itself is not included (i.e., it is not rendered on the page). Is there a way that I can force the template to render?
Instead of this
<div ng-include="'{{content}}'"></div>
use this
<div ng-include="content"></div>
and the template would get rendered.
ng-include does not work like this.
What you need to do is either write another directive that will fetch and show content for you. You could also use $routeProvider to change the url and have it include a template URL.

Master Page Concept in AngularJS?

I would like to create master page, that is main page which will be used in all views of the application.
For example, Left navigation and top men navigation. This navigation should be displayed in all the views, whenever url changes in application.
As per ng-view, it only renders given partial view and replace previous view. In the image above all my left and top navigation should be displayed by using angular Controller.
Controller code
angular.module('modelDemo').controller("authCtrl", ['$scope', function($scope) {
$scope.list;
}]);
Please let me know, how can i achieve this
You can use angular-route or Angular-ui-router, and setting your master, following this steps:
Step 1. Make your index.html your master page.
Step 2. Add the <header>, <footer>, <aside>, <div>, etc. referencing your templates by using ng-include
NOTE: your left and top navigation will be part of it
Step 3. The content of the view will be rendered using the directive attribute ng-view or ui-view
Step 4. Use your module app.config() to configure the children pages
Source:
using Angular Route: https://docs.angularjs.org/tutorial/step_07
template for a brand-new app: https://github.com/angular/angular-seed
using Angular UI Router: Angular Tutorial 30 mins
ng view should be able to do that just fine. Keep your top navigation / left navigation html intact and use ng view for the various display area. http://docs.angularjs.org/api/ng.directive:ngView
To use the controller from the top navigation inside ng-view you can use $parent to get access to that scope : https://stackoverflow.com/a/14700326/390330
Fiddle for parent scope : http://jsfiddle.net/ezhrw/2/
<button ng:click="$parent.letter = greek">Assignment expression {{ greek }}</button>
I was trying to create the same concept, but needed a way to define placeholders. I started experimenting in Plnkr.co and thus far, I resorted to using a LayoutManager that drives itself from settings within the routeProvider object.
Here is an example: http://embed.plnkr.co/4GPDfTSQCuqukJE7AniZ/
You'll see an example of how multiple routes use the same header and footer, I did not include an example with a sidebar.
Let me explain the LayoutManager.
I wanted to have placeholders that could be overridden. In this example, I have a toolbar that contains a title and provides a space to the right of the title for additional toolbar items. This gives views an opportunity to throw in additional functionality.
All of this is driven by the LayoutManager. The LayoutManager is a service that reads layout properties set on the $routeProvider. I wanted to implement this in a way keep things clean and self contained, per route. The LayoutManager is injected into the toolbar directive. The toolbar directive drives it's scope properties of the LayoutManager.
In turn, the LayoutManager has a dependency on the routeProvider as well as the rootScope $routeChange event.
I'm very new to Angular, open to suggestions.
I could not see any problem, if you are using bootstrap then use can easily divide your screen as you want
<div class="row">
<div class="col-lg-3">
Left panel
</div>
<div class="col-lg-9" style="border:1px solid #999; overflow-y:auto">
<div> Top Banner </div>
<!-- Main view to render all the page -->
<div ui-view> </div>
</div>
</div>
If you want complete demo and code on then see this link
Edited: 3 Nov. 2016:
If you are using ui-router then we can user abstract state to create different master pages.
You don't need to play show/hide, ng-if but just define the routing properly with you master pages and child pages
Better to see the detail
I know this is an old thread, but thought it should be noted that as of Angular 1.5+ we have been introduced to components. Instead of dealing with routes with named views and all that nonsense or using ngInclude you should be using a header component and footer component. Simply add these to your index.html (or whatever you call your master html template) and voila.
For example (this is using Angular Material and is missing the layout module but hopefully you get the point)
1. Added to index.html
<layout-header></layout-header>
2. header.component.js (you don't need all of this but I think it's helpful)
(function () {
'use strict';
angular
.module('layout')
.component('layoutHeader', {
templateUrl: 'layout/header.html',
bindings: {},
controller: Controller
});
Controller.$inject = [];
function Controller() {
var ctrl = this;
initialize();
////////////////////
function initialize(){
}
}
}());
3. header.html
<md-toolbar>
<div class="md-toolbar-tools">
<h2>
<span>Really Awesome Title!!!!</span>
</h2>
<span flex></span>
<md-button class="md-icon-button" aria-label="More">
<md-icon class="material-icons">more_vert</md-icon>
</md-button>
</div>
</md-toolbar>

Resources