Eugene Goldberg
Eugene Goldberg

Reputation: 15544

how to establish a two-way binding between a text input and a parent scope model

In my Angular app, I have a view, which is presented as a tabbed UI, with multiple tabs created by default. Each tab contains a number of Form elements, one of which is a text input named "tabName". The purpose of each tab is to allow the user to upload an Excel file, and be able to describe the file contents using a few Form fields located on the same page. All of the form elements in each tab are bound to a controller named "FileUploadController", but, the tab itself (specifically its name) is bound to a different controller, named "TabController".

I need to be able to have a two-way binding between the "tabName" text input in each tab, and the name property of the actual tab (which initially comes from "$scope.workspaces" within the TabController.

Currently, I am trying to handle this by creating a "activeWorkspaceSheetName" function within the TabController, and then referencing it as ng-model for the text input, but, it is not working.

Here are my files:

tabControl.html (the view):

<div class="container form-group">
    <br>
    <tabset>
        <tab ng-repeat="workspace in workspaces"
             heading="{{workspace.name}}"
             active=workspace.active>
            <div ng-controller="FileUploadController">
              <hr>
                <!--FILE UPLOAD CONTROL-->

                <div class="container">
                    <div class="row">
                        <div class="col-md-3">
                            <input type="file" nv-file-select="" uploader="uploader" />
                        </div>
                        <div class="col-md-9" style="margin-bottom: 40px">
                            <h3>Upload queue</h3>
                            <p>Queue length: {{ uploader.queue.length }}</p>
                            <table class="table">
                                <thead>
                                <tr>
                                    <th width="50%">Name</th>
                                    <th ng-show="uploader.isHTML5">Size</th>
                                    <th ng-show="uploader.isHTML5">Progress</th>
                                    <th>Status</th>
                                    <th>Actions</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr ng-repeat="item in uploader.queue">
                                    <td><strong>{{ item.file.name }}</strong></td>
                                    <td ng-show="uploader.isHTML5" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
                                    <td ng-show="uploader.isHTML5">
                                        <div class="progress" style="margin-bottom: 0;">
                                            <div class="progress-bar" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div>
                                        </div>
                                    </td>
                                    <td class="text-center">
                                        <span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
                                        <span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
                                        <span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
                                    </td>
                                    <td nowrap>
                                        <button type="button" class="btn btn-success btn-xs" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
                                            <span class="glyphicon glyphicon-upload"></span> Upload
                                        </button>
                                        <button type="button" class="btn btn-warning btn-xs" ng-click="item.cancel()" ng-disabled="!item.isUploading">
                                            <span class="glyphicon glyphicon-ban-circle"></span> Cancel
                                        </button>
                                        <button type="button" class="btn btn-danger btn-xs" ng-click="item.remove()">
                                            <span class="glyphicon glyphicon-trash"></span> Remove
                                        </button>
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>


                <!--END OF FILE UPLOAD CONTROL-->
                <div class="form-group">
                    <fieldset>
                        <legend><strong>Dataset Description</strong> </legend>
                        <div class="col-sm-6">
                            <label for="category">Category name</label>
                            <div id="category">
                                <isteven-multi-select
                                        input-model="inputCategories"
                                        output-model="outputCategories"
                                        button-label="icon name"
                                        item-label="icon name maker"
                                        tick-property="ticked"
                                        selection-mode="single"
                                        >
                                </isteven-multi-select>
                            </div>
                            <label for="documentAuthor">Document author</label>
                            <input id="documentAuthor" name="documentAuthor" type="text" class="form-control" ng-model="documentAuthor"/>
                            <label for="dateDocumentRecieved">Date document recieved</label>
                            <input id="dateDocumentRecieved" name="dateDocumentRecieved" type="text" class="form-control" ng-model="dateDocumentReceived"/>
                            <label for="documentReviewer">Document reviewer</label>
                            <input id="documentReviewer" name="documentReviewer" type="text" class="form-control" ng-model="documentReviewer"/>
                        </div>

                        <div class="col-sm-6">
                            <label for="originalDocumentName">Original document name</label>
                            <input id="originalDocumentName" name="originalDocumentName" type="text" class="form-control" ng-model="originalDocumentName"/>

                            <label for="tabName">Sheet Name</label>
                            <input id="tabName" name="tabName" type="text" class="form-control" ng-model="$scope.$parent.activeWorkspaceSheetName"/>

                            <label for="dateDocumentProduced">Date document produced</label>
                            <input id="dateDocumentProduced" name="dateDocumentProduced" type="text" class="form-control" ng-model="dateDocumentProduced"/>


                            <label for="documentSubmitter">Document submitter</label>
                            <input id="documentSubmitter" name="documentSubmitter" type="text" class="form-control" ng-model="documentSubmitter"/>
                        </div>



                        </fieldset>
                    </div>
            </div>
        </tab>
        <tab select="addWorkspace()">
            <tab-heading> Add Sheet
                <i class="icon-plus-sign"></i>
            </tab-heading>
        </tab>
        <tab select="removeWorkspace()">
            <tab-heading> Remove Selected Sheet
                <i class="icon-plus-sign"></i>
            </tab-heading>
        </tab>
    </tabset>
    <br/>
    <!--<button type="button" class="btn-primary" ng-click="collectValuesFromEachTab()">Submit Dataset</button>-->
    <!--<h3>Workspaces</h3>-->
    <!--<pre>{{workspaces|json}}</pre>-->
</div>

tabController.js:

angular.module('TabCtrl', ['ui.bootstrap'])
    .controller("TabController", ['$scope','$http', function ($scope, $http) {
        console.log("This is TabController");
        var setAllInactive = function() {
            angular.forEach($scope.workspaces, function(workspace) {
                workspace.active = false;
            });
        };

        $scope.activeWorkspaceSheetName = function(){
            $scope.workspaces.forEach(function(workspace) {
                if(workspace.active){
                    return workspace.name;
                }
            });
        };

        var addNewWorkspace = function() {
            var id = $scope.workspaces.length + 1;
            $scope.workspaces.push({
                id: id,
                name: "Sheet " + id,
                active: true
            });
        };

        $scope.workspaces =
            [
                { id: 1, name: "Sheet 1" ,active:true  },
                { id: 2, name: "Sheet 2" ,active:false  }
            ];

        $scope.addWorkspace = function () {
            setAllInactive();
            addNewWorkspace();
        };

        $scope.removeWorkspace = function() {
            angular.forEach($scope.workspaces, function(workspace) {
                if(workspace.active){
                    var index = $scope.workspaces.indexOf(workspace);
                    console.log('Active Workspace id: ' + index);
                    $scope.workspaces.splice(index,1);
                }
            })
        };
    }]);

fileUploadController.js:

angular.module('FileUploadCtrl', [])
    .controller('FileUploadController', ['$scope', 'FileUploader', function($scope, FileUploader) {
        console.log('This is File Upload Controller');

        $scope.inputCategories = [
            {
                name: "Category 1"
            },
            {
                name: "Category 2"
            },
            {
                name: "Category 3"
            }
        ];

        var selectedCategory;



        var uploader = $scope.uploader = new FileUploader({
            url: 'http://10.211.55.25:8080/api/files',
            tabName: 'sheet1'
        });

        // FILTERS

        uploader.filters.push({
            name: 'customFilter',
            fn: function(item /*{File|FileLikeObject}*/, options) {
                return this.queue.length < 10;
            }
        });

        // CALLBACKS

        uploader.onWhenAddingFileFailed = function(item /*{File|FileLikeObject}*/, filter, options) {
            console.info('onWhenAddingFileFailed', item, filter, options);
        };
        uploader.onAfterAddingFile = function(fileItem) {
            console.info('onAfterAddingFile', fileItem);
        };
        uploader.onAfterAddingAll = function(addedFileItems) {
            console.info('onAfterAddingAll', addedFileItems);
        };
        uploader.onBeforeUploadItem = function(item) {

            angular.forEach( $scope.outputCategories, function( value, key ) {
                selectedCategory = value.name;
                item.formData.push({subjectCategory: selectedCategory});
            });

            $scope.tabName = $scope.$parent.activeWorkspaceSheetName;

            item.formData.push({tabName: $scope.tabName,
                                originalDocumentName: $scope.originalDocumentName,

                                subject:    $scope.subject,
                                documentAuthor: $scope.documentAuthor,
                                dateDocumentProduced: $scope.dateDocumentProduced,
                                dateDocumentReceived: $scope.dateDocumentReceived,
                                documentSubmitter: $scope.documentSubmitter,
                                documentReviewer:   $scope.documentReviewer,
                                dataFields: $scope.dataFields});
            console.info('onBeforeUploadItem', item);
        };
        uploader.onProgressItem = function(fileItem, progress) {
            console.info('onProgressItem', fileItem, progress);
        };
        uploader.onProgressAll = function(progress) {
            console.info('onProgressAll', progress);
        };
        uploader.onSuccessItem = function(fileItem, response, status, headers) {
            console.info('onSuccessItem', fileItem, response, status, headers);
        };
        uploader.onErrorItem = function(fileItem, response, status, headers) {
            console.info('onErrorItem', fileItem, response, status, headers);
        };
        uploader.onCancelItem = function(fileItem, response, status, headers) {
            console.info('onCancelItem', fileItem, response, status, headers);
        };
        uploader.onCompleteItem = function(fileItem, response, status, headers) {
            console.info('onCompleteItem', fileItem, response, status, headers);
        };
        uploader.onCompleteAll = function() {
            console.info('onCompleteAll');
        };

        console.info('uploader', uploader);
    }]);

What is the proper way to have this two-way binding, so, when the user updates the tabName text input in each tab, the actual tab's name is also updated?

Upvotes: 0

Views: 306

Answers (1)

Facundo Pedrazzini
Facundo Pedrazzini

Reputation: 1486

If I understood correctly you has an input tabName for each tab so you can try put this model in the tabName input:

<input id="tabName" name="tabName" type="text" class="form-control" ng-model="workspace.name"/>

Remember every time that angular can't find a property in a scope they look if exist in his parent, and if not exist they check in his parent parent and so on...

Upvotes: 1

Related Questions