【问题标题】:how to establish a two-way binding between a text input and a parent scope model如何在文本输入和父范围模型之间建立双向绑定
【发布时间】:2015-05-27 16:16:30
【问题描述】:

在我的 Angular 应用程序中,我有一个视图,它显示为一个选项卡式 UI,默认情况下会创建多个选项卡。 每个选项卡都包含许多表单元素,其中一个是名为“tabName”的文本输入。 每个选项卡的目的是允许用户上传 Excel 文件,并能够使用位于同一页面上的几个表单字段来描述文件内容。 每个选项卡中的所有表单元素都绑定到名为“FileUploadController”的控制器,但选项卡本身(特别是其名称)绑定到名为“TabController”的不同控制器。

我需要能够在每个选项卡中的“tabName”文本输入和实际选项卡的名称属性(最初来自 TabController 中的“$scope.workspaces”)之间进行双向绑定。

目前,我正在尝试通过在 TabController 中创建一个“activeWorkspaceSheetName”函数来处理这个问题,然后将其作为文本输入的 ng-model 引用,但是它不起作用。

这是我的文件:

tabControl.html(视图):

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

这种双向绑定的正确方法是什么,因此,当用户更新每个选项卡中的 tabName 文本输入时,实际选项卡的名称也会更新?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    如果我理解正确,您的每个选项卡都有一个输入 tabName,因此您可以尝试将此模型放在 tabName 输入中:

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

    请记住,每次 angular 无法在范围内找到属性时,如果存在于其父级中,则如果不存在,则检查其父级,依此类推...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 1970-01-01
      • 2020-04-03
      • 2014-04-28
      相关资源
      最近更新 更多