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

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

Related

md-tabs not showing scroll or pagination

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?

"Previous" / "Next" tab navigation system (AngularJS / AngularJS Material)

I am developing some content display in various tabs, using Angular.js 1.5.x and AngularJS Material 1.1.0.
I first used the Angular Material md-tabs system like this : https://material.angularjs.org/latest/demo/tabs.
Unfortunately, our users do not use them as they do not seem to understand they are tabs. I am now working on a new, more obvious, tabs system :
I haven't found any Angular material way to create this "previous/next"-based tab navigation system.
Do you know where I could look ? It does not need to be Angular Material, any help or lead is welcome :) I want to avoid complexity or custom code if possible, so I want to capitalize on existing frameworks.
You can still use mdTabs. You can create a custom button and make them to command the tab by changing the selected tab with: md-selected
Then hide the tab navigation by md-no-pagination , or by adding display:none to .md-tab css.
eg, for 3 tabs:
<div>
<md-tabs md-selected="tabIndex">
<md-tab label="tab1">
tab1 content
</md-tab>
<md-tab label="tab2">
tab 2 content
</md-tab>
<md-tab label="tab3">
tab 3 content
</md-tab>
</md-tabs>
<md-button ng-click="back()" class="md-raised">
Previous
</md-button>
<md-button ng-click="next()" class="md-raised">
Next
</md-button>
</div>
and controller:
$scope.back = function() {
if ($scope.tabIndex > 0) {
$scope.tabIndex--;
}
};
$scope.next = function() {
if ($scope.tabIndex < 2) {
$scope.tabIndex++;
}
}
plunkr: http://plnkr.co/edit/NWSRBb?p=preview

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);

Variable showing as undefined

I am having trouble with passing the results of checkboxes from my view to the controller and just get "undefined" in the console log.
FYI - I have my controller as "camp".
In my view I have the following:
<div style="padding:20px;">
<h5>Add a Business</h5>
<md-content style="padding:20px;">
<md-checkbox
ng-repeat="business in camp.businesses"
ng-model="business.selected"
aria-label="Checkbox"
>
{{business.business_name}}
</md-checkbox>
</md-content>
<md-button class="md-raised" ng-click="camp.addBusinesses(business)">
<i class="fa fa-plus"></i> Add
</md-button>
</div>
In my controller I have the following function in an "angular.extend()"
addBusinesses: function(val){
console.log('Display Results: ', val);
}
If I just use the function to log the click event, it's fine. But when I try to pass the "business" object, it says "undefined".
What am I missing here???
The issue is your <md-button> is outside the ng-repeat. Your ng-repeat ends with the </md-checkbox> so when it gets to the button, business is indeed undefined.
Try reformatting your code so that the button is still within the scope of the ng-repeat. Maybe you want the repeat on the md-content instead? I'm not sure what the page is supposed to look like so I can't advise more than that.

AngularMaterial Tabs showing only 1st tab

Why are md-tabs showing only the first tab? The rest of them appears after I click in the tabs area.
First tab looks like this:
After clicking in the tab area:
My code looks like this:
<md-tabs md-dynamic-height md-border-bottom>
<md-tab label="Home"></md-tab>
<md-tab label="Profile"></md-tab>
<md-tab label="Messages"></md-tab>
</md-tabs>
On purpose I left the content of tabs empty because I want to get rid of the transition animation as described here.
One of the problems could be that the tabs are in bootstrap dropdown menu.
Thank you for your ideas!
EDIT
I have just found out that the tabs has troubles even without bootstrap when using them in md-menu.
Have you solved it yet?
I'm having the same problem except that my angular tabs is in bootstrap's modal.
When I click on a button to toggle the modal it only show the first tab until I click on it.
After doing some testing it appears that I could work around by hiding the angular tabs with ng-show and show it after a small amount of delay.
<button ng-click="controller.showTabs()">Show Tab</button>
<md-tabs md-dynamic-height md-border-bottom ng-show="show_tab">
<md-tab label="Home"></md-tab>
<md-tab label="Profile"></md-tab>
<md-tab label="Messages"></md-tab>
</md-tabs>
Controller's function when user clicks on the drop down / button to toggle the modal:
this.showTabs =
function()
{
//250ms delay
$timeout(function()
{
$scope.show_tab = true;
},250);
}

Resources