【问题标题】:md-select showing multiple selections after updatingmd-select 更新后显示多个选择
【发布时间】:2016-11-07 22:01:00
【问题描述】:

我创建了一个issue on the material github,但由于他们专注于 material2,我想从这里的专家那里获得一些帮助,以确定这是我正在做的事情,还是 angularjs/material 的问题。所以这是我的问题:

用户可以通过从下拉列表中选择并单击“添加新”来添加认证。这些认证绑定到ng-repeat,它会生成黄色的卡片。这些卡片的列表都绑定到相同的数据类型。正如您在上面看到的,我单击此图标以打开一个对话框,该对话框显示了一个用于将项目添加到列表中的表单,该列表填充了页面上的md-selects。添加到列表后,md-select 的选中标签显示两个相同的项目被选中。 multiple 未在 md-selects 上启用,并且每个选定的 id 只有一个值。单击md-side-nav、标签标题或md-select 本身将更新所选标签以正确显示。检查 DOM,没有重复项。我有attempted to recreate this issue on codepen,但到目前为止我还没有成功。这是我的布局:

<md-tabs md-dynamic-height md-border-bottom>
    <md-tab>
        <md-tab-label>
            Certifications
        </md-tab-label>
        <md-tab-body>
            <div layout="row" layout-padding>
                <div flex="50">
                    <md-input-container>
                        <label>Last Audit</label>
                        <md-datepicker ng-model="addEditSupplierCtrl.supplier.dateLastAudit"></md-datepicker>
                    </md-input-container>
                </div>
                <div>
                    <md-input-container>
                        <label>Next Audit</label>
                        <md-datepicker ng-model="addEditSupplierCtrl.supplier.dateNextAudit"></md-datepicker>
                    </md-input-container>
                </div>
            </div>
            <div layout="row" layout-padding>
                <md-input-container style="min-width: 200px;">
                    <label>Certification Type</label>
                    <md-select ng-model="addEditSupplierCtrl.newSupplierCertification.certificationTypeId">
                        <md-option ng-repeat="certificationType in addEditSupplierCtrl.certificationTypes" value="{{ certificationType.id }}">
                            {{ certificationType.name }}
                        </md-option>
                    </md-select>
                </md-input-container>
                <div>
                    <md-button class="md-primary md-raised" ng-click="addEditSupplierCtrl.addSupplierCertification($event)">Add New</md-button>
                </div>
            </div>
            <div layout="row" layout-wrap>
                <md-card md-theme="{{ certification.requiresAudit ? 'audit' : 'default' }}" ng-repeat="certification in addEditSupplierCtrl.supplier.supplierCertifications | orderBy:'certificationType.name'" flex="100" flex-gt-sm="40" flex-gt-md="30">
                    <md-card-title flex="none">
                        <md-card-title-text>
                            <div style="position: relative">
                                <strong>Selected Id:</strong> {{ certification.certificationTypeId | json }}<br />
                                <md-input-container style="min-width: 150px; max-width: 350px;">
                                    <label>Certification Type</label>
                                    <md-select ng-model="certification.certificationTypeId">
                                        <md-option ng-repeat="certificationType in addEditSupplierCtrl.certificationTypes" value="{{ certificationType.id }}">
                                            {{ certificationType.name }}
                                        </md-option>
                                    </md-select>
                                </md-input-container>
                                <br /><strong>Select List Data:</strong> {{ addEditSupplierCtrl.certificationTypes | json }}
                                <md-button class="md-icon-button md-primary" ng-click="addEditSupplierCtrl.showAddCertificationTypeDialog($event)">
                                    <md-icon>playlist_add</md-icon>
                                </md-button>
                                <div style="position: absolute; right: 0; top: 0">
                                    <md-button class="md-icon-button md-primary" title="Delete Certification" ng-click="addEditSupplierCtrl.deleteCertification($event, certification)">
                                        <md-icon>cancel</md-icon>
                                    </md-button>
                                </div>
                            </div>
                        </md-card-title-text>
                    </md-card-title>
                    <md-card-content>
                        <div class="md-media-sm card-media" flex>
                            <md-checkbox class="md-primary" ng-model="certification.requiresAudit">
                                Requires Audit
                            </md-checkbox>
                            <md-input-container class="md-block">
                                <label>Number</label>
                                <input ng-model="certification.number" />
                            </md-input-container>
                            <md-input-container>
                                <label>Expiration</label>
                                <md-datepicker ng-model="certification.expirationDate"></md-datepicker>
                            </md-input-container>
                            <md-input-container class="md-block">
                                <label>Notes</label>
                                <textarea ng-model="certification.notes"></textarea>
                            </md-input-container>
                        </div>
                    </md-card-content>
                </md-card>
            </div>
        </md-tab-body>
    </md-tab>
</md-tabs>

这是我的逻辑:

(function () {
angular.module('ASLApp').controller('AddEditSupplierController', AddEditSupplierController);

function AddEditSupplierController(addMode, $scope, $routeParams, $mdDialog, RandomService, SupplierService, CertificationTypeService) {
    var vm = this;

    vm.save = function (evt) {
        vm.loading = true;
        SupplierService.update(vm.supplier).then(function (response) {
            vm.supplier = response.data;
            parseDates();
        }, function (response) {
            if (response.data && response.data.Errors && response.data.Errors.length > 0 && response.data.Errors[0].number === 2627) {
                $mdDialog.show(
                  $mdDialog.alert()
                    .clickOutsideToClose(true)
                    .title('Duplicate Supplier Id Entry Found')
                    .textContent('Another supplier entry was found with the same Id.')
                    .ok('Ok')
                );
            }
        }).finally(function () {
            vm.loading = false;
        });
    };

    vm.addSupplierCertification = function (evt) {
        if (!vm.supplier.supplierCertifications) {
            vm.supplier.supplierCertifications = [];
        }
        vm.supplier.supplierCertifications.push(vm.newSupplierCertification);
        vm.newSupplierCertification = {
            certificationTypeId: vm.certificationTypes[0].id,
            tempId: RandomService.guid()
        };
    };

    vm.generateId = function (evt) {
        SupplierService.generateId(vm.supplier.name).then(function (response) {
            vm.supplier.id = response.data;
        });
    };

    vm.showAddCertificationTypeDialog = function (evt) {
        $mdDialog.show({
            scope: $scope,
            preserveScope: true,
            templateUrl: 'app/views/AddCertificationTypeDialog.html',
            parent: angular.element(document.body),
            targetEvent: evt
        });
    };

    vm.cancelDialog = function (evt) {
        $mdDialog.cancel();
    };

    vm.addCertificationType = function () {
        CertificationTypeService.add(vm.newCertificationType).then(function (response) {
            vm.newCertificationType = {};
            getCertificationTypes();
            $mdDialog.hide();
        });
    };

    function init() {
        vm.addMode = addMode;
        if (!addMode) {
            getSupplier($routeParams.id);
        }
        getCertificationTypes();
    }

    function getSupplier(id) {
        vm.loading = true;
        SupplierService.get(id).then(function (response) {
            vm.supplier = response.data;
            parseDates();
        }).finally(function () {
            vm.loading = false;
        });
    }

    function getCertificationTypes() {
        CertificationTypeService.getAll().then(function (response) {
            if (vm.certificationTypes)
                delete vm.certificationTypes;

            vm.certificationTypes = response.data;

            vm.newSupplierCertification = {
                certificationTypeId: vm.certificationTypes[0].id,
                tempId: RandomService.guid()
            };
        });
    }

    function parseDates() {
        if (vm.supplier.dateLastReview) {
            vm.supplier.dateLastReview = new Date(vm.supplier.dateLastReview);
        }

        if (vm.supplier.dateNextReview) {
            vm.supplier.dateNextReview = new Date(vm.supplier.dateNextReview);
        }

        if (vm.supplier.dateLastAudit) {
            vm.supplier.dateLastAudit = new Date(vm.supplier.dateLastAudit);
        }

        if (vm.supplier.dateNextAudit) {
            vm.supplier.dateNextAudit = new Date(vm.supplier.dateNextAudit);
        }

        if (vm.supplier.supplierCertifications) {
            angular.forEach(vm.supplier.supplierCertifications, function (certification) {
                if (certification.expirationDate) {
                    certification.expirationDate = new Date(certification.expirationDate);
                }
            });
        }
    }

    init();
}

AddEditSupplierController.$inject = ['addMode', '$scope', '$routeParams', '$mdDialog', 'RandomService', 'SupplierService', 'CertificationTypeService'];
}());

在我的故障排除过程中,我删除了其他选项卡,在将新项目添加到列表后,它显示了半秒钟的多项选择,但随后更新以正确显示。这让我想知道是否有某种debounce 发生。能够在我的 codepen 上重现这一点对于缩小我怀疑与事件时间相关的问题非常有帮助。任何帮助将不胜感激!

疑难解答更新: 我尝试将$timeout 调用添加到我的getCertificationTypes 方法但没有结果,因此我将调用加倍getCertificationTypes。它向选定的值标签添加了另一个副本。

    vm.addCertificationType = function () {
        CertificationTypeService.add(vm.newCertificationType).then(function (response) {
            vm.newCertificationType = {};
            $timeout(getCertificationTypes, 1000);
            $timeout(getCertificationTypes, 1000);
            //getCertificationTypes();
            $mdDialog.hide();
        });
    };

【问题讨论】:

  • 你能把你在showAddCertificationTypeDialog中的代码添加到模板中吗?我认为问题就在那里
  • 我更新了你的密码笔。查看 $mdDialog 以添加 certificationType 并尝试像在 codepen 中实现的那样实现。我认为这将解决您的问题。 codepen.io/anon/pen/qqbWdd
  • 为了让我理解您的想法和您所做的更改,您是在建议我在$mdDialog 中创建一个匿名控制器并将返回值传递回原始控制器?
  • 是的。我认为你有参考问题。如果您将 $scope 与模态隔离,我认为您的问题将得到解决
  • 完成。不好意思,朋友。没有变化。

标签: javascript angularjs html angular-material


【解决方案1】:

在cmets和聊天中讨论后,问题出在md-select,当打印md-option的数组的引用发生变化时,模型没有更新,md-select的预览出现异常正如您在问题中看到的那样。那是因为ng-repeat 重新渲染了所有md-option,并且角材料中存在无法正确处理此用例的错误。

解决方案是在ng-repeat 中添加track by 属性,这样整个列表就不会重新渲染

<md-select ng-model="certification.certificationTypeId">
    <md-option ng-repeat="certificationType in addEditSupplierCtrl.certificationTypes track by certificationType.id" value="{{ certificationType.id }}">
           {{ certificationType.name }}
     </md-option>
</md-select>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 2015-08-23
    相关资源
    最近更新 更多