简体   繁体   中英

AngularJS <select> two way data binding for <option> coming from AJAX call

I have this Controller:

JApp.controller('WebsiteController', function($scope, $resource) {
    var UsersService = $resource('/auth/users', {});

    $scope.adding = false;
    $scope.users = [];

    $scope.addUser = function() {
        $scope.adding = true;

        UsersService.query({}, function(data) {
            $scope.users = data;
            $scope.selectedUser = data[0];
        });
    }

    $scope.cancelAddUser = function() {
        $scope.adding = false;
    }
});

My HTML:

<section class="vbox" ng-controller="WebsiteController">
<section class="panel animated fadeInDown">
    <header class="panel-heading">
      <h3>{{selectedUser.last_name}} </h3> <!-- Just to test I print it here -->
    </header>
    <div class="panel-body m-b">
        <div class="row text-sm wrapper">
            @if (role_admin())
                <a href="{{{URL::action('WebsiteController@getAddWebsite')}}}" class="btn btn-sm btn-info"> <i class="icon-plus"></i> New Website </a>
            @endif                  

        </div>
        <div class="table-responsive">
            <table class="table table-striped b-t text-sm">
              <thead>
                  <tr>
                    <th>URL</th>
                    <th>Assigned to</th>
                    <th>Action</th>
                  </tr>
                </thead>
                <tbody>
                                    <!-- Outside this <tr> doesn't work -->
                    <tr ng-repeat="website in websites">
                        <td> {{website.url}}</td>
                        <td>
                             <span ng-repeat="assigned in website.users"> <span class="label label-info"> {{assigned.first_name}} </span> &nbsp; </span>
                             <a ng-click="addUser()" ng-hide="adding" class="btn btn-success btn-xs"> Add new </a></span>                               
                                 <select ng-hide="!adding" 
                                            name="myselect" 
                                            ng-model="selectedUser" 
                                            ng-options="u.first_name for u in users">
                                 </select>
                             <a href="#" ng-hide="!adding" ng-click="cancelAddUser()" class="btn btn-warning btn-xs">Cancel</a>
                             <input type="text" ng-model="selectedUser.first_name"> <!-- It works here! -->
                        </td>
                        <td>
                            <a href="#" class="btn btn-xs btn-white"> <i class="icon-pencil"></i> Edit </a>
                        </td>
                    </tr>
                </tbody>                    
            </table>
        </div>
    </div>
</section>
</section>

Updated: Notice that it works in my <input> next to the <select> , but doesn't work in my <header> (only binds once)

So when I click on the add user, the AJAX call will retrieve list of users, and successfully show it in the <select> and by default, selectedUser will be pointing at data[0] which is the first user. But now the two way binding is now bound to data[0] instead. If I change my selection to other user, selectedUser is not updated. But if I update my selectedUser , let's say the name, the name in the dropdown list also change.

I have tried not using the line

$scope.selectedUser = data[0];

but still doesn't work anyway, it is not bound at all though I specify ng-model="selectedUser" .

The JSON returned:

[
    {
        "id": 1,
        "role_id": 1,
        "created_at": "2013-09-19 05:54:36",
        "updated_at": "2013-09-19 05:54:36",
        "email": "admin@admin.com",
        "username": "admin",
        "first_name": "Admin",
        "last_name": "Istrator"
    },
    {
        "id": 2,
        "role_id": 2,
        "created_at": "2013-09-19 05:54:36",
        "updated_at": "2013-09-19 05:54:36",
        "email": "johndoe@gmail.com",
        "username": "john",
        "first_name": "John",
        "last_name": "Doe"
    }
]

Anyone can help me with this? I am trying not to go down the $digest or $apply road if I don't have to.

UPDATE 2 The source of the problem is if I try to print out selectedUser outside of the following ng-repeat in my above HTML:

<tr ng-repeat="website in websites"> ...... </tr>

Fiddle to illustrate my problem: http://jsfiddle.net/jofrysutanto/4nfyV/3/

Try This

HTML:

   <div ng-app="myApp">
    <section class="vbox" ng-controller="WebsiteController">
   <section class="panel animated fadeInDown">
<header class="panel-heading">
  <h3>{{mySelectedUser.last_name}} </small> <!-- Just to test I print it here -->
</header>
<div class="panel-body m-b">
    <div class="table-responsive">
        <table class="table table-striped b-t text-sm">
          <thead>
              <tr>
                <th>URL</th>
                <th>Assigned to</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
                <tr ng-repeat="website in websites">
                    <td>
                         <span ng-repeat="assigned in website.users"> <span class="label label-info"> {{assigned.first_name}} </span> &nbsp; </span>
                         <a ng-click="addUser()" ng-hide="adding" class="btn btn-success btn-xs"> Add new </a></span>                               
                             <select ng-hide="!adding" 
                                        name="myselect" 
                                        ng-model="selectedUser" 
                                        ng-change="abc(selectedUser)"
                                        ng-options="u.first_name for u in users">
                             </select>
                         <a href="#" ng-hide="!adding" ng-click="cancelAddUser()" class="btn btn-warning btn-xs">Cancel</a>
                         <input type="text" ng-model="selectedUser.first_name"> <!-- It works here! -->
                    </td>
                    <td>
                        <a href="#" class="btn btn-xs btn-white"> <i class="icon-pencil"></i> Edit </a>
                    </td>
                </tr>
            </tbody>                    
        </table>
    </div>
</div>
 </section>
</section>
</div>    

Controller :

var JApp = angular.module('myApp', []);

 JApp.controller('WebsiteController', function($scope) {
//var UsersService = $resource('/auth/users', {});

$scope.adding = false;
$scope.users = [];

$scope.websites = [
    {
        "id": 1,
        "url": "www.google.com",
        "cms": "Wordpress"
    }
    ];

$scope.addUser = function() {
    $scope.adding = true;
   var data = [
   {
     "id": 1,
     "role_id": 1,
     "created_at": "2013-09-19 05:54:36",
     "updated_at": "2013-09-19 05:54:36",
     "email": "admin@admin.com",
     "username": "admin",
     "first_name": "Admin",
     "last_name": "Istrator"
   },
  {
     "id": 2,
     "role_id": 2,
     "created_at": "2013-09-19 05:54:36",
     "updated_at": "2013-09-19 05:54:36",
     "email": "johndoe@gmail.com",
     "username": "john",
     "first_name": "John",
     "last_name": "Doe"
  }
];
   // UsersService.query({}, function(data) {
        $scope.users = data; // suppose data is coming from UsersService.query
        $scope.selectedUser = data[1];
        $scope.mySelectedUser = $scope.selectedUser ;
  //  });
}
$scope.abc = function(a) {
    $scope.mySelectedUser = a;

 }
$scope.cancelAddUser = function() {
    $scope.adding = false;
}
});

See DEMO

The value of the select dropdown options is u.first_name, so either do this:

$scope.selectedUser = data[0].first_name;

Or change it to use ids or something like this.

ng-options="u.id as u.first_name for u in users"
$scope.selectedUser = data[0].id;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM