md-tabs not showing scroll or pagination - angularjs

I have recently upgraded my angularjs material version from 1.0.9 to 1.1.10. After the change my scroll bars have stopped showing up in the sides of my tab menu panels when there is an overflow. This used to work fine earlier.
Now I only see the following in the Devtools, for some reason the this flag is not becoming true for the pagination to work. Please let me know what could be the issue here.
<!-- ngIf: $mdTabsCtrl.shouldPaginate -->
This is the code that I have.
<div class="mainContentWrapper md-whiteframe-2dp" id="mainContentWrapper" style="overflow:auto;">
<div class="tab-panel">
<md-content class="md-padding">
<md-tabs md-selected="selectedIndex" md-border-bottom md-autoselect>
<md-tab>
<img class="dashboard" width="20" src="../../images/dashboard-icon1.png" />
<md-tooltip md-direction="right" ng-click="backToDashboard()">
Dashboard
</md-tooltip>
</md-tab>
<md-tab ng-repeat="tab in tabs"
ng-disabled="tab.disabled"
title="{{tab.desc}}" ng-if="$index>0">
{{tab.title}}
<md-tooltip>
{{tab.desc}}
</md-tooltip>
</md-tab>
</md-tabs>
</md-content>
</div>

There has been a change in implementation from 1.0.9 to 1.1.10. in the new version its using MutationObserver to detect any change to decide if it needs to show pagination.
var mutationCallback = function() {
ctrl.updatePagination();
ctrl.updateInkBarStyles();
};
if('MutationObserver' in $window) {
var config = {
childList: true,
subtree: true,
// Per https://bugzilla.mozilla.org/show_bug.cgi?id=1138368, browsers will not fire
// the childList mutation, once a <span> element's innerText changes.
// The characterData of the <span> element will change.
characterData: true
};
observer = new MutationObserver(mutationCallback);
observer.observe(element[0], config);
disconnect = observer.disconnect.bind(observer);
} else {
var debounced = $mdUtil.debounce(mutationCallback, 15, null, false);
element.on('DOMSubtreeModified', debounced);
disconnect = element.off.bind(element, 'DOMSubtreeModified', debounced);
}
Previously it was using only $mdUtil.debounce(mutationCallback, 100) which means it was updating the flags every 100ms. for some reason when I resize my window the mutation is not triggered. So I had to manually mutate the contents of the tab on resizing the tabs. I dont like this fix. Am I missing something?

Related

changing md-selected with md-tabs and using md-button (prev, next)

I am experiencing a strange behavior when switching tabs using different methods of changing the tab index. I can change md-selected using the $scope.changeQuestion function with ng-click. I can also use the built in clicking of the md-tab to change md-selected. The issue lies when I click the md-tab and then try to click my prev or next buttons that utilize the $scope.changeQuestion function. If I click the tabs and then try to use my buttons to change the index, the buttons don't change the tab index anymore. They do log the appropriate index I want to switch to, however.
controller
$scope.changeQuestion = function(index){
$scope.selectedQuestion = index;
};
html
<md-tabs md-selected='selectedQuestion' md-stretch-tabs md-dynamic-height md-border-bottom>
<md-tab ng-repeat='question in assessment.questions | toArrayKeepKeys | orderBy: "order"'>
<md-tab-label>
{{question.order}} <i class="fas fa-fire fire" ng-if='question.bonus'></i>
</md-tab-label>
<md-tab-body>
<div class='question-tab-content'>
<question class='margin-top-1em' details='question' answer='answers[question.key]'></question>
<div>
<md-button ng-click='changeQuestion($index - 1)' ng-hide='question.order === 1' class='md-primary md-raised no-left-margin'>Previous</md-button>
<md-button ng-click='changeQuestion($index + 1)' ng-hide='question.order === _.size(assessment.questions)' class='md-primary md-raised no-left-margin'>Next</md-button>
</div>
</div>
</md-tab-body>
</md-tab>
</md-tabs>
Here is the example of the behavior:
I was able to get a working example in codepen but can't seem to get it to work in my project.
Update
Tried putting a $watch on $scope.selectedQuestion and it doesn't fire if I click the tabs. It's like the md-selected='selectedQuestion' and $scope.selectedQuestion are different but only after I click a tab.
Found Solution: scope inheritance
Changing $scope.selectedQuestion = 0; to $scope.selectedQuestion = { selected: 0 }; and updating other references did the trick.
Unexplained: why the codepen example works without the modifications from the solution

Load and call content of md-tab when it's clicked or selected from md-tabs (angular 1.5)

I'm using following HTML structure in parent.html page (and have corresponding Controller for this parent HTML Page)
<md-tabs md-dynamic-height class="report-tabs" layout-align="center stretch" md-no-pagination="true">
<md-tab>
<md-tab-label>
<span class="tab-label">Tab 1</span>
</md-tab-label>
<md-tab-body>
<div ng-include="tab1-page-URL"></div>
</md-tab-body>
</md-tab>
<md-tab>
<md-tab-label>
<span class="tab-label">Tab 2</span>
</md-tab-label>
<md-tab-body>
<div ng-include="tab2-page-URL"></div>
</md-tab-body>
</md-tab>
Currently when I load this parent.html page, All contents of all tabs are getting loaded at beginning.
Don't we have lazy loading where contents of tab are loaded when it's active (when selected/clicked upon) ?
If we don't have such provision, How can I call function of child tab's controller, when particular tab is selected ? Currently all functions of all child tab's controllers are getting called - which is time consuming and not needed where user will see first tab only when page completes compiling and rendering ?
I've tried calling Child-tab controller functions on parent.html page, but unless all md-tab contents are not loaded, nothing from child-controller is accessible. Only accessible part in this page will be parent.html's own controller functions.
Let me know if any other way I can proceed, Or am I missing completely something here ? Thank you.
From the official doc, for using md-tab , there are no lazy loading contents.
If we don't have such provision, How can I call function of child
tab's controller, when particular tab is selected ? Currently all
functions of all child tab's controllers are getting called - which is
time consuming and not needed where user will see first tab only when
page completes compiling and rendering ?
My method is by using the button only tabs, then using dynamic ng-include, and setting the reladed view during selecting the tab, by md-on-select
something like:
<md-tabs>
<md-tab label="Tab #1" md-on-select="onTabSelected(1)"></md-tab>
<md-tab label="Tab #2" md-on-select="onTabSelected(2)"></md-tab>
<md-tab label="Tab #3" md-on-select="onTabSelected(3)"></md-tab>
</md-tabs>
<md-content class="md-padding">
<ng-include src="'templates/tabs/'+ tabId +'.html'"></ng-include>
</md-content>
controller :
$scope.tabId = 1; //default template loaded
$scope.onTabSelected = function(tabId) {
//you can add some loading before rendering
$scope.tabId = tabId;
};
templates directory:
templates/
tabs/
1.html
2.html
3.html
You could try something like:
<md-tabs md-dynamic-height class="report-tabs" layout-align="center stretch" md-no-pagination="true">
<md-tab md-on-select="onSelect(tab)" ng-repeat="tab in tabs">
<md-tab-label>
<span class="{{tab.class}}">{{tab.label}}</span>
</md-tab-label>
<md-tab-body>
<div ng-if="selectedTab === tab.id" ng-include="{{tab.url}}"></div>
</md-tab-body>
</md-tab>
and in controller:
$scope.tabs = [
{id: 1, label: "label for tab 1", url: "url-tab-1.html"},
{id: 2, label: "label for tab 2", url: "url-tab-2.html"}
];
$scope.onSelect = function(tab) {
$scope.selectedTab = tab.id;
};
$scope.onSelect(1);

Bootstrap Tab Clears My Model when Hidden

So I was converting a button group to a Bootstrap Tab and then one of my views stopped appearing. I could not figure out what I had done wrong but I think I've narrowed it down to the Tab resetting my model when the Tabs are hidden. Here's what I have:
controller:
$ctrl.$onInit = function() {
$ctrl.states = [ // for toggling which view to display
'state0', // 0
'state1', // 1
...
];
$ctrl.currentState = $ctrl.states[3]; // this should show my forth view
};
View:
<!-- setting to false for testing -->
<div class="panel-body desktop hidden-xs hidden-sm" ng-show="false">
<!-- here I use currentState to determine which one is active -->
<uib-tabset active="$ctrl.currentState" type="tabs" justified="true">
<uib-tab heading="Some Text" index="'state0'">
<div class="text-center text-primary">Fields Marked With * Are Required.</div>
</uib-tab>
...
</uib-tabset>
</div>
When the tabs are being hidden currentState gets set to "" and my other view doesn't display.
View2:
<div class="panel-body" ng-show="$ctrl.currentState === 'state4'">
...
<div>
How can I disable this behavior? I've done some research but I haven't found anyone with this issue. Thanks in advance.
I guess no one else has encountered this issue. I have found a work around though.
I added a new tab that I don't display.
<uib-tab heading="Some Text" index="'state4'" ng-show="false">
</uib-tab>
Since a tab exists now for this state my currentState variable doesn't get cleared. I'd love a better answer for this but it's at least functional now.

AngularJs - Opening a Bootstrap dropdown menu on page load by programmatically triggering the "click" event (NO jQuery)

May I ask if it's possible to trigger the click event of a dropdown menu programmatically on page load using AngularJS?
What I want to happen is that after loading the page, my navigation menu gets displayed automatically.
This is what I have so far:
<li class="menu-item" style="margin-top:15px">
<!-- Single button -->
<div class="btn-group open" uib-dropdown is-open="status.isopen">
<!-- Hamburger menu -->
<img ng-init="displayMainMenu()" id="nav-burger" uib-dropdown-toggle ng-disabled="disabled" ng-click="sMainMenu=true; isSubMenu=resetMenu(); getLinks(); bStopPropagation=true;" src="img/burger.png">
<!-- Main menu -->
<ul uib-dropdown-menu role="menu" aria-labelledby="single-button" ng-click="bStopPropagation && $event.stopPropagation()">
<!-- Main Menu -->
<li role="menuitem" class="main-menu-item" ng-repeat="link in links" ng-click="whatMenu(link.name); isSubMenu=false;" ng-show="isMainMenu">
<img id="{{link.icon}}">{{link.name}}<img class="navi-expand-icon">
</li>
<!-- End Main Menu -->
</ul>
</div>
</li>
And this is my Angular JS code:
$scope.displayMainMenu = function () {
var domElement = document.getElementById('nav-burger');
alert('before timeout'); // <-- This gets triggered
$timeout(function () {
angular.element(domElement).triggerHandler('click');
}, 0);
alert('after timeout'); // <-- This doesn't get triggered...
}
I have a feeling that I'm really close, however I couldn't figure out why it's not working.
Thank you in advance for your replies.
The ng-click on your image triggers this: ng-click="sMainMenu=true;"
However, to show your list items you have used isMainMenu ng-show="isMainMenu"
So I guess you made a typo.
Thank you for the clue Matheno! I did some more research about $timeout and finally got it to work by declaring $timeout in the controller:
app.controller('ctrlDropdown', function ($scope, $timeout) {
$scope.isMainMenu = true;
$scope.isSubMenu = false;
$scope.links = "";
$scope.subLinks = "";
$scope.selectedLink = "";
$scope.bStopPropagation = true;
...
}

ionic scroll: Prevent translate3d on parent element

I have template in my ionic app that looks something like this:
<ion-view>
<ion-content>
<div class="nav">
<span class="ion-chevron-left" ng-click="goToMonth('thisMonth', $event)"></span>
<span>{{ monthName }}</span>
<span class="ion-chevron-right" ng-click="goToMonth('nextMonth', $event)"></span>
</div>
<ion-scroll on-scroll="onScroll()" class="wide-as-needed" delegate-handle="calendarScroll" direction="x" paging="true" scrollbar-x="false" style="min-height: 215px" ng-style="scrollStyle">
...
the div with the class 'nav' contains two buttons that let the user switch between two months. The months are in the <ion-scroll> element.
This works as it should. The buttons scroll the <ion-scrol> element horizontally. But every time the buttons are used, the entire <ion-view> is scrolled vertically down by 20px - thus hiding the buttons.
I've tried changing the <ion-scroll>s inline css (with angular.element) to not include 3d transforms, but they just get re-added.
This is the function that gets called upon click - and my attempt to prevent the transform3d on the parent element
$scope.goToMonth = function(id, event){
$location.hash(id);
if(id == 'thisMonth'){
$scope.monthName = monthLabels[thisMonth];
}
else{
$scope.monthName = monthLabels[nextMonth];
}
var elm = angular.element(document.querySelector('.nav'));
var parent = angular.element(elm.parent());
console.log(parent[0].style.transform);
parent[0].style.transform = 'none';
$ionicScrollDelegate.anchorScroll(true);
};
EDIT: I've also tried using event.stopPropagation - this breaks the functionality of the <ion-scroll> element
Can anyone tell me how to prevent this behaviour?
Silly me. It turns out this was very simple to solve. I simply just needed to add scroll="false" to the <ion-content> element. No additional controller logic was needed.
So the html code above now looks like this:
<ion-view>
<ion-content scroll="false">// <-- Here I altered the html
<div class="nav">
<span class="ion-chevron-left" ng-click="goToMonth('thisMonth', $event)"></span>
<span>{{ monthName }}</span>
<span class="ion-chevron-right" ng-click="goToMonth('nextMonth', $event)"></span>
</div>
<ion-scroll on-scroll="onScroll()" class="wide-as-needed" delegate-handle="calendarScroll" direction="x" paging="true" scrollbar-x="false" style="min-height: 215px" ng-style="scrollStyle">
...

Resources