Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material - Dynamically add tab and change to that tab

Currently working on a chat app here https://playwithfire.firebaseapp.com/ and whenever a user adds a new room I want the new room tab to be entered. Currently you can add a room but need to click it afterwards to enter that room and display its content.

I tried changing the attribute md-selected="selectedIndex" but that makes no tab active so no content appears.

Is it possible to do what I'm asking for? What I've got so far:

index.html

<div layout="column" ng-controller="RoomController">
        <!-- Tabs Container -->
        <md-tabs md-stretch-tabs md-selected="selectedIndex">
            <!-- Individual Tab -->
            <md-tab ng-repeat="room in roomList"
                    label="{{room.roomName}}">

                <div ng-controller="ChatController">
                    <!-- Display messages -->
                    <md-list>
                        <md-item ng-repeat="msg in messages">
                            <md-item-content>
                                <div class="md-tile-content">
                                    <div class="bubble">
                                        <strong>{{msg.from}}</strong><br>
                                        {{msg.body}}
                                    </div>
                                </div>
                            </md-item-content>
                        </md-item>
                    </md-list><!--/DisplayMessages-->

                    <!-- Chat controls -->
                    <div layout="row" layout-margin layout-wrap>
                        <div flex="33">
                            <!-- Assign username -->
                            <label for="nameInput">Username</label>
                            <input ng-model="name" type="text" id="nameInput" placeholder="Enter a username...">
                        </div>
                        <div flex="95">
                            <!-- Post a message -->
                            <label>Message</label>
                            <textarea class="form-control" 
                                      ng-model="msg"
                                      ng-keydown="addMessage($event)" 
                                      id="messageInput"
                                      placeholder="Type a message...">
                            </textarea>
                        </div>

                        <div layout="row" layout-sm="column" layout-margin layout-fill layout-align="start end">
                            <!-- Click to send message -->
                            <div flex>
                                <md-button class="md-raised md-primary pull-left" ng-click="sendMessage()">Send</md-button>
                            </div>
                            <!-- Modal to add or join room -->
                            <div flex ng-controller="ModalController">
                                <md-button class="md-raised md-primary pull-left" ng-click="open()">Add or Join Room</md-button>
                            </div>
                            <!-- Opens helper -->
                            <div flex ng-controller="HelpController">
                                <md-button class="pull-right" ng-click="open()" ng-href="">Need help?</md-button>
                            </div>
                        </div>
                </div><!--/ChatController-->
            </md-tab>
        </md-tabs><!--/tabs container-->
    </div><!--/RoomController-->

room.js

angular.module('myApp')
.controller('RoomController', function($scope, ShareFactory) {
    $scope.roomList = ShareFactory.roomList;

    // use this to default to index 0 in roomList
    $scope.selectedIndex = 0;

    $scope.$on('RoomChange', function(event, data) {
        $scope.selectedIndex = data;
        console.log('Heard the change!');
        console.log('The data is: ' + data);
    });
});

modal.js

angular.module('myApp')
.controller('ModalController', function($rootScope, $scope, $modal, ChatFactory, ShareFactory) {
    $scope.open = function () {
        var modalInstance = $modal.open({
            templateUrl: 'views/modal.html',
            controller: 'ModalInstanceController'
        });

        modalInstance.result.then(function (name) {
            var found = false;
            var length = ShareFactory.roomList.length;
            var index = 0;

            for(var i = 0; i < length; ++i) {
                if(ShareFactory.roomList[i].roomName === name) {
                    found = true;
                    index = i;
                    console.log('index ' + index);
                }
            }

            if(!found) {
                ShareFactory.roomList.push({ roomName : name});
                index = ShareFactory.roomList.length - 1;
            }
            else {
                // don't care about disabled, not a feature i want to use
                //ShareFactory.roomList[index].disabled = false;
            }

            // Broadcast event to all children of rootScope
            // namely want RoomController to listen for this change
            $rootScope.$broadcast('RoomChange', index);
        }, function () {
            console.log('cancel');
        });
    };
});
like image 714
jonwho Avatar asked Apr 10 '15 01:04

jonwho


1 Answers

Ya know, this definitely came up in a Github issue a while ago, but it may have been kicked to the backlog due to other high priority issues.

I just added this feature to master: https://github.com/angular/material/commit/8285e2d0bb6efbc72e311ee85b619cbbe8437072

And it should be viewable shortly on our site in the second demo: https://material.angularjs.org/HEAD/#/demo/material.components.tabs

In the meantime, you should be able to solve this by adding the following code:

if(!found) {
  ShareFactory.roomList.push({ roomName : name});
  index = ShareFactory.roomList.length - 1;
  $timeout(function () {
    ShareFactory.selectedIndex = index;
  });
}

The $timeout is necessary because you must wait until after the render is finished before you can update the selected index to the new one - otherwise, it will think that the valid is out of range.

Hope this helps!

like image 179
Robert Messerle Avatar answered Nov 02 '22 03:11

Robert Messerle