【问题标题】:ng-model not updated for select drop-down list in angular ui-bootstrap modalng-model 未针对 Angular ui-bootstrap 模式中的选择下拉列表更新
【发布时间】:2017-04-27 04:27:43
【问题描述】:

请查看实际问题:
Working Plunker

我有一个用于添加人员信息的网页。它应该允许为该人添加/编辑/删除多个地址。

  1. 页面上有一个“添加新地址”按钮,可打开一个模式对话框以输入地址信息。

  2. 在模式对话框中单击“添加地址”按钮会将此地址添加到页面中的地址列表中。

  3. 添加地址后,用户可以点击编辑按钮进行编辑。这就是我遇到问题的地方。

由于某种原因,在编辑地址时,地址类型和状态的下拉列表并未使用模型值更新,即使值似乎已设置和提供。

为此,我使用 angular 1.6.2angular-ui-bootstrap 2.5.0

【问题讨论】:

    标签: angularjs modal-dialog angular-ui-bootstrap html-select


    【解决方案1】:

    这是因为您将ng-option 用作ng-options="key as value for (key, value) in $ctrl.statesjson track by key",因此由于此键值对,angular 无法从您的下拉列表中绑定值。

    使用ng-repeat 代替ng-options T

    试试这个

    <!DOCTYPE html>
    <html>
    
      <head>
        <link data-require="bootstrap@3.3.7" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
        
        <script data-require="jquery@3.1.1" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        <script data-require="bootstrap@3.3.7" data-semver="3.3.7" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script data-require="angularjs@1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
        <script data-require="ui-bootstrap@2.5.0" data-semver="2.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
        <link rel="stylesheet" href="style.css" />
        <script>
          (function (angular)
    {
    
        "use strict";
        // make sure you define all dependencies in main app only
        // you need NOT define these again in dependent components
        var addPerson = angular.module('addPerson', ['ui.bootstrap']);
    
        // only pass required dependencies in the controller
        // just because you've defined the dependency 'ui.bootstrap' in main app 
        // does NOT necessarily require you to pass it again in the controller 
        // when you do not use it here
        addPerson.controller('myCtrl', ['appFactory', '$scope', '$filter', '$log', function (appFactory, $scope, $filter, $log) {
            
            // functions must be defined before they are called
            var clearPerson = function () {
                $scope.selTitleVal = "";
                $scope.fname = "";
                $scope.mi = "";
                $scope.lname = "";
                return (null);
            };
            
            // clear all entries
            clearPerson();
        }])
        .factory('appFactory', function () {
            return {};
        });
    })(window.angular);
        </script>
        <script>
          /*
      Contains following custom angular components:
      1. addresses: Add Address button and displays the list of addresses added with Edit, Delete buttons
      2. addressModal: Modal dialog to add/edit an address
    */
    
    // 1. Angular Component: addresses
    (function (angular) {
        'use strict';
        
        var stmpl = '';
        stmpl += '<div><input type="button" class="btn btn-info" value="+ Address" ng-click="$ctrl.open();" /></div>';
        stmpl += '<table class="table table-striped table-bordered" ng-if="$ctrl.isShow">';
        stmpl += '  <thead>';
        stmpl += '    <tr>';
        stmpl += '      <th style="display:none">Address Type Id</th>';
        stmpl += '      <th>Address Type</th>';
        stmpl += '      <th>Address1</th>';
        stmpl += '      <th style="display:none">State Id</th>';
        stmpl += '      <th>Actions</th>';
        stmpl += '    </tr>';
        stmpl += '  </thead>';
        stmpl += '  <tbody>';
        stmpl += '    <tr ng-repeat="x in $ctrl.addresses track by $index">';
        stmpl += '      <td style="display:none">{{ x.addresstypeid }}</td>';
        stmpl += '      <td>{{ x.addresstype }}</td>';
        stmpl += '      <td>{{ x.address1 }}<br />{{ x.address2 }}<br />{{ x.city }} {{ x.state }} {{ x.zip }}</td>';
        stmpl += '      <td style="display:none">{{ x.stateid }}</td>';
        stmpl += '      <td><input type="button" class="btn-xs btn-info" style="width:60px" value="Edit..." ng-click="$ctrl.editAddress($index);" />&nbsp;<input type="button" class="btn-xs btn-info" style="width:60px" value="Delete..." ng-click="$ctrl.deleteAddress($index);" /></td>';
        stmpl += '    </tr>';
        stmpl += '  </tbody>';
        stmpl += '</table>';
        stmpl += '<br />';
    
        function tableRowController($scope, $uibModal) {
            this.$scope = $scope;
    
            // these are fields in modal dialog - format for json
            $scope.$ctrl.dataForModal = {
                addresstypeid: '',
                addresstype: '',
                address1: '',
                address2: '',
                city: '',
                stateid: '',
                state: '',
                zip: ''
            };
    
            $scope.$ctrl.title = "Addresses";
            $scope.$ctrl.addresses = [];
            $scope.$ctrl.isShow = false;   
    
            // below is how you call the dependent component 'addressModal'
            // +Address is button's click event is wired to this
            $scope.$ctrl.open = function () {
    
                $scope.$ctrl.title = "Add New Address";
                // read documentation for 'ui.bootstrap.modal'
                // open the modal dialog for Add Address
                $uibModal.open({
    
                    // addressModal.init() - initialize the modal dialog
                    component: "addressModal",
                    //windowClass: "my-dialog",
                    resolve: {
                        modalData: function () {
                            return $scope.$ctrl.dataForModal;
                        },
                        title: function(){
                            return $scope.$ctrl.title;
                        }
                    }
                }).result.then(function (result) {
                    $scope.$ctrl.result = result;
                    console.info(result);
                    $scope.$ctrl.addAddress();
                }, function (reason) {
                    // addressModal.closeAddress() is invoked here - same as cancel the modal dialog event
                });
            };
    
            $scope.$ctrl.addAddress = function () {
                $scope.$ctrl.addresses.push({
                    addresstypeid: $scope.$ctrl.result.addresstypeid,
                    addresstype: $scope.$ctrl.result.addresstype,
                    address1: $scope.$ctrl.result.address1,
                    address2: $scope.$ctrl.result.address2,
                    city: $scope.$ctrl.result.city,
                    stateid: $scope.$ctrl.result.stateid,
                    state: $scope.$ctrl.result.state,
                    zip: $scope.$ctrl.result.zip
                });
                $scope.$ctrl.isShow = true;
            }
    
            $scope.$ctrl.deleteAddress = function ($index) {
                if (confirm("Do you want to delete this address?\r\nOK: Yes     Cancel: No")) {
                    $scope.$ctrl.addresses.splice($index, 1);
                    if ($scope.$ctrl.addresses.length > 0) $scope.$ctrl.isShow = true;
                    else $scope.$ctrl.isShow = false;
                }
            }
    
            $scope.$ctrl.editAddress = function ($index) {
                $scope.$ctrl.title = "Edit Address";
                $scope.$ctrl.dataForModal = {
                    addresstypeid: $scope.$ctrl.addresses[$index].addresstypeid,
                    addresstype: $scope.$ctrl.addresses[$index].addresstype,
                    address1: $scope.$ctrl.addresses[$index].address1,
                    address2: $scope.$ctrl.addresses[$index].address2,
                    city: $scope.$ctrl.addresses[$index].city,
                    stateid: $scope.$ctrl.addresses[$index].stateid,
                    state: $scope.$ctrl.addresses[$index].state,
                    zip: $scope.$ctrl.addresses[$index].zip
                };
                
                $uibModal.open({
                    // addressModal.init() - initialize the modal dialog
                    component: "addressModal",
                    scope: $scope,
                    resolve: {
                        modalData: function () {
                            $scope.$ctrl.dataForModal.addresstypeid = "102";
                            $scope.$ctrl.dataForModal.addresstype = "PO Box";
                            return $scope.$ctrl.dataForModal;
                        },
                        title: function () {
                            return $scope.$ctrl.title;
                        }
                    }
                }).result.then(function (result) {
    
                    $scope.$ctrl.result = result;
                    console.info(result);
                    
                    $scope.$ctrl.addresses[$index].addresstypeid = $scope.$ctrl.result.addresstypeid;
                    $scope.$ctrl.addresses[$index].addresstype = $scope.$ctrl.result.addresstype;
                    $scope.$ctrl.addresses[$index].address1 = $scope.$ctrl.result.address1;
                    $scope.$ctrl.addresses[$index].address2 = $scope.$ctrl.result.address2;
                    $scope.$ctrl.addresses[$index].city = $scope.$ctrl.result.city;
                    $scope.$ctrl.addresses[$index].stateid = $scope.$ctrl.result.stateid;
                    $scope.$ctrl.addresses[$index].state = $scope.$ctrl.result.state;
                    $scope.$ctrl.addresses[$index].zip = $scope.$ctrl.result.zip;
                    $scope.$ctrl.isShow = true;
    
                }, function (reason) {
                    // addressModal.closeAddress() is invoked here - same as cancel the modal dialog event
                });
            }
        }
    
        angular.module('addPerson').component('addresses', {
            bindings: { title: '<' },   // two way data-binding
            template: stmpl,
            controller: tableRowController
        });    
    
    })(window.angular);
    
    // 2. Angular Component: addressModal
    (function (angular) {
        var stmpl = "";
        stmpl += '<!-- MODAL DIALOG: Add Address -->';
        stmpl += '      <div class="modal-content">';
        stmpl += '          <div class="modal-header">';
        stmpl += '              <button type="button" class="close" data-dismiss="modal" ng-click="$ctrl.closeAddress();">&times;</button>';
        stmpl += '              <h4 class="modal-title">{{ $ctrl.title }}</h4>';
        stmpl += '          </div>';
        stmpl += '          <div class="modal-body">';
        stmpl += '            <div class="row form-group">';    
        stmpl += '              <label class="control-label col-md-2" for="ddlAddressType">Address Type</label>';    
        stmpl += '              <div class="col-md-10">';
        stmpl += '                <select class="form-control" id="ddlAddressType" name="ddlAddressType" ng-model="$ctrl.modalData.addresstypeid" ng-change="$ctrl.changeAddressType();">';
        stmpl += '                          <option value="">** Select Address Type **</option >';
        stmpl += '                          <option ng-repeat="(id, value) in $ctrl.addresstypesjson track by id" value="{{id}}">{{value}}</option>';
        stmpl += '                </select>';
        stmpl += '                <span class="field-validation-valid text-danger" data-valmsg-for="ddlAddressType" data-valmsg-replace="true"></span>';
        stmpl += '                  </div> ';
        stmpl += '              </div>';
        stmpl += '              <div class="row form-group">';
        stmpl += '                  <label class="control-label col-md-2" for="Address1">Address1</label>';
        stmpl += '                  <div class="col-md-10">';
        stmpl += '                      <input class="form-control text-box single-line" id="Address1" name="Address1" ng-model="$ctrl.modalData.address1" type="text" value="" />';
        stmpl += '                      <span class="field-validation-valid text-danger" data-valmsg-for="Address1" data-valmsg-replace="true"></span>';
        stmpl += '                  </div> ';
        stmpl += '              </div>';
        stmpl += '              <div class="row form-group">';
        stmpl += '                <label class="control-label col-md-2" for="Address1">Address2</label>';    
        stmpl += '                <div class="col-md-10">';
        stmpl += '                  <input class="form-control text-box single-line" id="Address2" name="Address2" ng-model="$ctrl.modalData.address2" type="text" value="" />';
        stmpl += '                  <span class="field-validation-valid text-danger" data-valmsg-for="Address2" data-valmsg-replace="true"></span>';
        stmpl += '                </div>';
        stmpl += '              </div>';
        stmpl += '              <div class="row form-group">';
        stmpl += '                <label class="control-label col-md-2" for="City">City</label>';
        stmpl += '                <div class="col-md-10">';
        stmpl += '                  <input class="form-control text-box single-line" id="City" name="City" ng-model="$ctrl.modalData.city" type="text" value="" />';
        stmpl += '                  <span class="field-validation-valid text-danger" data-valmsg-for="City" data-valmsg-replace="true"></span>';
        stmpl += '                </div>';
        stmpl += '              </div>';
        stmpl += '              <div class="row form-group">';
        stmpl += '                <label class="control-label col-md-2" for="ddlState">State</label>';
        stmpl += '                <div class="col-md-10">{{getValue($ctrl.modalData.stateid)}}';
        stmpl += '                  <select class="form-control" id="ddlState" name="ddlState" ng-model="$ctrl.modalData.stateid">';
        stmpl += '                          <option value="">** Select State **</option>';
        stmpl += '                          <option ng-repeat="(id, value) in $ctrl.statesjson" value="{{id}}">{{value}}</option>';
        stmpl += '                  </select>';
        stmpl += '                  <span class="field-validation-valid text-danger" data-valmsg-for="ddlState" data-valmsg-replace="true"></span>';
        stmpl += '                  </div>';
        stmpl += '              </div>';
        stmpl += '              <div class="row form-group">';
        stmpl += '                <label class="control-label col-md-2" for="Zip">Zip</label>';
        stmpl += '                <div class="col-md-10">';
        stmpl += '                  <input class="form-control text-box single-line" id="Zip" name="Zip" ng-model="$ctrl.modalData.zip" type="text" value="" />';
        stmpl += '                  <span class="field-validation-valid text-danger" data-valmsg-for="Zip" data-valmsg-replace="true"></span>';
        stmpl += '                  </div> ';
        stmpl += '              </div>';
        stmpl += '          </div>';
        stmpl += '          <div class="modal-footer">';
        stmpl += '              <input type="button" value="Add Address" class="btn btn-success" ng-click="$ctrl.addAddress();"/>';
        stmpl += '              <input type="button" value="Close" class="btn btn-default" ng-click="$ctrl.closeAddress();" />';
        stmpl += '          </div>';
        stmpl += '      </div>  <!-- model - content -->';
        
        function tableRowController($scope, $http, $uibModal) {
            this.$scope = $scope;
            //var $ctrl = this;
            $scope.$ctrl.addresstypesjson = {"100": "Home", "101": "Work", "102": "PO Box"};
            $scope.$ctrl.statesjson = {"AN": "Andaman and Nicobar Islands", "AP": "Andhra Pradesh", "AR": "Arunachal Pradesh", "DD": "Daman and Diu", "DH": "Dadra and Nagar Haveli", "DL": "Delhi"};
            
            // Events
            // 1. init - initialize
            $scope.$ctrl.$onInit = function () {
                $scope.$ctrl.modalData = $scope.$ctrl.resolve.modalData;
                $scope.$ctrl.title = $scope.$ctrl.resolve.title;
                
                if ($scope.$ctrl.title != "Edit Address") {
                    $scope.$ctrl.modalData.addresstypeid = "";
                    $scope.$ctrl.modalData.addresstype = "";
                    $scope.$ctrl.modalData.address1 = "";
                    $scope.$ctrl.modalData.address2 = "";
                    $scope.$ctrl.modalData.city = "";
                    $scope.$ctrl.modalData.stateid = "";
                    $scope.$ctrl.modalData.state = "";
                    $scope.$ctrl.modalData.zip = "";
                }
            }
    
            // 2. dismiss - cancel model dialog
            $scope.$ctrl.closeAddress = function () {
                $scope.$ctrl.modalInstance.dismiss("cancel");
            }
    
            // 3. close - add new address and close the dialog
            $scope.$ctrl.addAddress = function () {
                // assign selected text for drop-down list items
                $scope.$ctrl.modalData.addresstype = $scope.$ctrl.addresstypesjson[$scope.$ctrl.modalData.addresstypeid];
                $scope.$ctrl.modalData.state = $scope.$ctrl.statesjson[$scope.$ctrl.modalData.stateid];
                $scope.$ctrl.modalInstance.close($scope.$ctrl.modalData);
            }
    
            $scope.getValue = function(id){
                debugger
            }
    
            $scope.$ctrl.changeAddressType = function () {
                console.info("Address Type drop-down list changed");
            }
        }
    
        // register the component - dependecies automatically follow from app (parent)
        angular.module('addPerson').component('addressModal', {
            bindings: {
                title: '<',
                modalInstance: "<",
                resolve: "<"
            },   // two way data-binding
            template: stmpl,
            controller: tableRowController
        });
    })(window.angular);
        </script>
      </head>
    
      <body>
        <h2>Add New Person</h2>
        <hr />
        <form action="#">
          <div class="form-horizontal"  ng-app="addPerson" ng-controller="myCtrl">
            
            <div class="form-group">
              <label class="control-label col-md-2" for="Title_Title_Title">Title</label>
              
              <div class="col-md-10">
                <select class="form-control" id="Title_Title_Title" name="Title.Title_Title" ng-value="selTitleVal"><option value="">** Select Title **</option>
                <option value="104">Dr.</option>
                <option value="103">Ma&#39;am</option>
                <option value="102">Miss</option>
                <option value="100">Mr.</option>
                <option value="101">Mrs.</option>
                <option value="106">Smt.</option>
                <option value="105">Sri</option>
                </select>
              <span class="field-validation-valid text-danger" data-valmsg-for="Title.Title_Title" data-valmsg-replace="true"></span>
              </div>
            </div>
            
            <div class="form-group">
              <label class="control-label col-md-2" for="Person_FName">First Name</label>
              <div class="col-md-10">
                <input class="form-control text-box single-line" id="Person_FName" name="Person_FName" ng-model="fname" type="text" value="" />
                <span class="field-validation-valid text-danger" data-valmsg-for="Person_FName" data-valmsg-replace="true"></span>
              </div>
            </div>
            
            <div class="form-group">
              <label class="control-label col-md-2" for="Person_MI">MI</label>
              <div class="col-md-10">
                <input class="form-control text-box single-line" id="Person_MI" name="Person_MI" ng-model="mi" type="text" value="" />
                <span class="field-validation-valid text-danger" data-valmsg-for="Person_MI" data-valmsg-replace="true"></span>
              </div>
            </div>
            
            <div class="form-group">
              <label class="control-label col-md-2" for="Person_LName">Last Name</label>
              <div class="col-md-10">
                <input class="form-control text-box single-line" id="Person_LName" name="Person_LName" ng-model="lname" type="text" value="" />
                <span class="field-validation-valid text-danger" data-valmsg-for="Person_LName" data-valmsg-replace="true"></span>
              </div>
            </div>
            
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Create Person" class="btn btn-primary" />
                </div>
            </div>
    
            <div class="container-fluid" style="padding:unset;margin:unset;">
                <div class="row" style="padding:unset;margin:unset;">
                    <div class="col-md-12" style="padding:unset;margin:unset;">
                        <addresses id="addresses1" title="'Addresses'"></addresses>
                    </div>
                </div>
            </div>
    
            
          </div>
        </form>
    
      </body>
    
    </html>

    Here 是工作人员。

    【讨论】:

    • 完美运行!在这种情况下使用 ng-repeat 应该没问题,因为每个下拉列表中的选项数量不会太多。谢谢@Saurabh!
    • @sosspyker 支持并接受我的回答,如果它适合你:)
    【解决方案2】:

    简单地从 ng-options 中删除 track by key 语法,一切都会好起来的。

    ng-options="key as value for (key, value) in $ctrl.statesjson" 会好的

    working exmaple

    【讨论】:

    • 这很好用!我会选择 ng-options 而不是 ng-repeat,因为根据文档,ng-options 似乎提供了更大的灵活性。谢谢!
    【解决方案3】:

    我不确定,但返回了旧字符串

      stmpl += '<option ng-repeat="(id, value) in $ctrl.addresstypesjson track by id" value="{{id}}">{{value}}</option>';
    

    我也在你的控制器中找到了这个

      modalData: function() {
            // $scope.$ctrl.dataForModal.addresstypeid = "102";
            // $scope.$ctrl.dataForModal.addresstype = "PO Box";
            return $scope.$ctrl.dataForModal;
     },
    

    所以,我评论了硬编码地址

    我的plunkr

    【讨论】:

    • 完美运行!谢谢!
    猜你喜欢
    • 2017-07-09
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 1970-01-01
    相关资源
    最近更新 更多