This is part of my controller:
mbpMod.controller("bookController", function($scope,api) {
...
$scope.bookTable=new BookTable();
$scope.bookLabel="Book";
...
}
in my HTML page it works until it is like this:
<md-tab>
<md-tab-label class="mbpPanel">Book</md-tab-label>
<md-tab-body>
<div flex ag-grid="bookTable.table" class="ag-mbp lowtable" ng-controller="bookController"></div>
</md-tab-body>
</md-tab>
But it doesn't work when I do this:
<md-tab>
<div ng-controller="bookController">
<md-tab-label class="mbpPanel">{{bookLabel}}</md-tab-label>
<md-tab-body>
<div flex ag-grid="bookTable.table" class="ag-mbp lowtable" ></div>
</md-tab-body>
</div>
</md-tab>
I cannot put ng-controller directive in md-tab tag, as it will result in a double directive.
Any ideas?
The md-tab-directive is used to specify information about a tab and how the tab should look like.
When the directive is being compiled, the controller of the md-tabdirective is executed. If you have a look at the source code on Github, you will see that the controller checks the direct children of the md-tab directive to retrieve the md-tab-label and md-tab-body contents.
The working example you provided us has md-tab-label and md-tab-body as a child of the md-tab. In the broken example, only the div is a child of md-tab, so the controller is not able to find a label and the body for the tab.
If you move the ng-controller declaration outside of your md-tab definition, it should work.
Related
I'm trying to use an ng-click function to get the data-target attribute of a clicked target angular material md-button, so that when a topic is clicked in the sidenav, the submenu for it appears.
I've structured the navigation using md-list with md-items as I've seen suggested, but can't figure out a way to get this behaviour, especially with the .sidenav-submenu elements not being direct children of the md-button that's clicked on.
Not sure this would even be the best approach for achieving something like this, but I'm limited by angular material's lack of toggled sidenav submenu directive.
HTML:
<md-item>
<md-button id="sidenav-paymentsButton" data-ng-click="toggleSubmenu($event)" data-target="#paymentsSubmenu">
<md-content class="sidenav-link" md-ink-ripple="#3a455f" layout="row" layout-align="space-between center">
<div layout="row" layout-align="start center"><span class="sidenav-link-icon material-icons">money_off</span>
Payments
</div>
<div><span class="expandSubmenu material-icons">keyboard_arrow_down</span></div>
</md-content>
</md-button>
<md-list id="paymentsSubmenu" class="sidenav-submenu">
<md-item>
<md-button ui-sref="newPayment">
<md-content class="sidenav-link" md-ink-ripple="#3a455f" layout="row" layout-align="start center">
<span class="sidenav-link-icon material-icons">create</span>
New Payment
</md-content>
</md-button>
</md-item>
navController JS:
app.controller('navController', function($scope, $state, $document) {
angular.element('.sidenav-submenu').hide();
$scope.toggleSubmenu = function($event) {
var target = $event.target;
// Not sure what to do next
}
})
You shouldn't be doing DOM manipulation in your controller. You use directives for DOM manipulation. That being said, what you want doesn't require any sort of custom directive that is not already built into angularjs.
Consider the following unstyled markup:
<div data-ng-click="nav.selected = 'A'">
Your toggle for the "A" side nav.
</div>
<div data-ng-click="nav.selected= 'B'">
Your toggle for the "B" side nav.
</div>
<div ng-if="nav.selected === 'A'>
The "A" side nav.
</div>
<div ng-if="nav.selected === 'B'>
The "B" side nav.
</div>
Used in conjunction with the following controller:
app.controller('navController', function($scope) {
$scope.nav = {
selected: 'A'
};
});
You technically don't even need the controller for this example if you change the markup slightly, but it will be helpful in getting around the "dot problem" in case it pops up when moving this to your own example.
This works:
<div ng-include="'login.html'" flex ng-if="!loggedIn" ng-controller="LoginController"></div>
However, this doesn't ({{test}} outputs nothing):
<ng-include src="'login.html'" flex ng-if="!loggedIn" ng-controller="LoginController"></ng-include>
Is there any reason? Or is it a bug?
login.html:
<p>{{test}}</p>
LoginController:
function LoginController($scope){
$scope.test = 'login';
}
I'm not exactly sure where "loggedIn" is defined, but when I define it on a parent controller, both syntaxes work as expected.
Plunkr
<div ng-controller="PrntCtrl">
<div ng-include="'test.html'" flex ng-if="!loggedIn" ng-controller="TestCtrl"></div>
<ng-include src="'test.html'" flex ng-if="!loggedIn" ng-controller="TestCtrl"></ng-include>
</div>
Some questions to consider:
What version of angular are you using?
How is your app defined and how is the controller registered with the app?
Where is "loggedIn" defined?
Because this directive accepts only 3 arguments:
ngInclude | src = string
onload (optional) = string
autoscroll (optional) = string
...according to the ngInclude Docs
EDIT:
you can solve simply wrap it in another element...
<div ng-if="!loggedIn" ng-controller="LoginController">
<div ng-include="'login.html'" flex></div>
</div>
I have 3 different code fragments which I'd like to swap out depending on the selection in a select menu.
It works if I include the code inline, but when I try to use ng-includes like this, I get an Angular error and the app fails:
<div ng-switch on="pFilter">
<div ng-include="'includes/parcel_details_incoming.html'" ng-switch-when="Incoming Parcels"></div>
<div ng-include="'includes/parcel_details_forward.html'" ng-switch-when="Exception Parcels"></div>
<div ng-include="'includes/parcel_details_exception.html'" ng-switch-default></div>
</div>
What am I doing wrong here? Does ng-switch not work with ng-includes?
The reason is both the directives ng-include and ng-switch-x use transclusion and you are specifying both on the same element and it is not allowed. Move nginclude to the child of ng-switch element.
<div ng-switch on="pFilter">
<div ng-switch-when="Incoming Parcels"><div ng-include="'includes/parcel_details_incoming.html'"></div></div>
<div ng-switch-when="Exception Parcels"><div ng-include="'includes/parcel_details_forward.html'"></div></div>
<div ng-switch-default><div ng-include="'includes/parcel_details_exception.html'"></div></div>
</div>
This used to work until angular 1.x version but compound transclusion will result in multidir error starting 1.2.x version of angular. Take a look at the change log and this commit.
Due to the structure of an existing project I'm working on, I'm stuck with a template that looks like this:
<div ng-app="example">
<div ng-controller="MainCtrl" id="inner">
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl" id="outer">
{{ outside }}
</div>
#outer is supposed to be using the same controller as #inner, but as it's located outside of ngApp's scope, {{ outside }} will not be evaluated. Unfortunately I can't change the template structure, so I tried to compile #outer's content like this:
app.run(function($rootScope, $compile){
$rootScope.$apply($compile(document.getElementById('outer'))($rootScope));
});
This works, but the controller function will be executed twice, which is not desired. Is there a better way to achieve my goal?
Working example on Plunker
what you could do instead, is NOT define ng-app at all in the html, and instead bootstrap angular via javascript.
for example you can do angular.bootstrap(document, ['example']); where 'example' is the angular module for the app for example angular.module('example', [
'ngResource', 'ui.router', ....
]);
you probably defined that yourself already.
This way, you define the ng-app on the entire document scope.
That is normal, you're initializing twice the controller. You could simply create another div, wrapping all the divs you want and use alias. But this will still initialize twice, but each div will have different values, like, {{inside}} on first div will not have the same as the second one has.
<div ng-app="example">
<div>
<div ng-controller="MainCtrl as FirstCtrl" id="inner"> // alias FirstCtrl
{{ inside }}
</div>
</div>
<div ng-controller="MainCtrl as SecondCtrl" id="outer"> // alias SecondCtrl
{{ outside }}
</div>
</div>
But if you intend to use just once the same controller, as far as I'm concerned, you'll have to wrap all divs you want to use the same controller, in just one div, like:
<div ng-app="example" ng-controller="MainCtrl">
<div id="inner">
{{inside}}
</div>
<div id="outer">
{{outside}}
</div>
</div>
This will initialize just once.
Other way, could be attaching ng-app and ng-controller in your html/body tags.
From what I read, the most common cause of this problem is when the controller is included in the template and in the route provider. In my case, only the parent template containing this html is being included in the router, and has its own controller. The sub-templates are being included as a result of a menu selection
So, whenever the menu item is selected, the template gets loaded in, and everything in the controller executes twice. Can it be a product of the the ng-switch or ng-include?
<span ng-switch on="selection">
<div ng-switch-when="0">
<div ng-include="'partials/one.html'" ng-controller="oneController"></div>
</div>
<div ng-switch-when="1">
<div ng-include="'partials/two.html'" ng-controller="twoController"></div>
</div>
<div ng-switch-when="2">
<div ng-include="'partials/three.html'" ng-controller="threeController"></div>
</div>
</span>
Edit:
The included partials do not include the controller again. I've triple checked that these controllers are not mentioned anywhere other than this piece of code. The contents of the one/two/three partials look like this, and the controller still runs twice.
<div>Nothing to see here.</div>
I am making an educated guess here... but does your "'partials/one.html'" also have a ng-controller="oneController" in it? If so, you either need to remove the ng-controller declaration from your include div or from your partial.