TietjeDK
TietjeDK

Reputation: 1207

AngularJS can't pass $index from bootstrap modal window

I'm banging my head against the wall here. I'm using ng-repeat to populate a table. Inside each row i have 2 buttons, one for updating the row content and for uploading files. The upload button opens a bootstrap modal window, where the user selects the files and clicks on submit.

The submit button uses ng-click to run a function which uses $index as parameter. But the $index value is always the same no matter which row is selected.

The thing I don't understand is that I use the exact same syntax (although outside of a modal window) on my update button, which works just fine.

HTML:

<tr ng-repeat="item in items | filter:search " ng-class="{'selected':$index == selectedRow}" ng-click="setClickedRow($index)">
   <td>{{$index}}</td>
   <td ng-hide="idHidden" ng-bind="item.Id"></td>
   <td ng-hide="titleHidden">
      <span  data-ng-hide="editMode">{{item.Title}}</span>
      <input  type="text" data-ng-show="editMode" data-ng-model="item.Title" data-ng-required />
   <td> 
      <button type="button" class="btn btn-primary uploadBtn" data-ng-show="editMode" data-toggle="modal" data-target="#uploadModal">Upload file  <i class="fa fa-cloud-upload"></i></button>
      <!-- Upload Modal -->
      <div class="modal fade" id="uploadModal" tabindex="-1" role="dialog" aria-labelledby="uploadModalLabel" aria-hidden="true">
         <div class="modal-dialog">
            <div class="modal-content">
               <div class="modal-header">
                  <h3 class="modal-title" id="uploadModalLabel">Options</h3>
               </div>
               <div class="modal-body">
                  <h4>Upload Documents</h4>
                  <form>
                     <div class="form-group">
                        <select  data-ng-model="type" class="form-control" id="fileTypeSelect">
                           <option value="Policy">Policy</option>
                           <option value="SOP">SOP</option>
                        </select>
                        <br>
                        <div class="input-group"> <span class="input-group-btn">
                           <input type="file" id="file">
                           </span>
                        </div>
                        <br>
                        <button  type="button" class="btn btn-default" data-ng-click="uploadAttachment($index, type)">Upload</button>
                  </form>
                  </div>
                  <div class="modal-footer">
                     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                  </div>
               </div>
            </div>
         </div>
      </div>
      <button type="button" data-ng-hide="editMode" data-ng-click="editMode = true;" class="btn btn-default pull-right">Edit <i class="fa fa-pencil-square-o"></i></button>
      <button type="button" data-ng-show="editMode" data-ng-click="editMode = false; updateItem($index)" class="btn btn-default">Save</button>
      <button type="button" data-ng-show="editMode" data-ng-click="editMode = false; cancel()" class="btn btn-default">Cancel</button>
      </td>`

JS:

$scope.uploadAttachment = function executeUploadAttachment(index, type) {
var listname = "Risk Register";
var id = $scope.items[index].Id;
console.log(indexID);
readFile("uploadControlId").done(function(buffer, fileName) {
    uploadAttachment(type, id, listname, fileName, buffer).done(function() {
        alert("success");
    }).fail(function() {
        alert("error in uploading attachment");
    })
}).fail(function(err) {
    alert("error in reading file content");
});
}

So the function uploadAttachment($index, type) which is triggered by ng-click doesn't pass the right index number. It always passes the same, no matter what row it is clicked in.

I have omitted some of the code that is irrelevant. If needed i can provide the whole thing.

Any suggestions to what I am missing?

Edit:

I have tried to implement DonJuwe suggestions.

I have added this inside my controller:

$scope.openModal = function(index) {
var modalInstance = $modal.open({
    templateUrl: 'www.test.xxx/App/uploadModal.html',
    controller: 'riskListCtrl',
    resolve: {
        index: function() {
            return index;
        }
    }
});
};

This is my modal template:

 <div class="modal-header">
   <h3 class="modal-title" id="uploadModalLabel">Options</h3>
</div>
<div class="modal-body">
   <h4>Upload Documents</h4>
   <form>
      <div class="form-group">
         <select  data-ng-model="type" class="form-control" id="fileTypeSelect">
            <option value="Policy">Policy</option>
            <option value="SOP">SOP</option>
         </select>
         <br>
         <div class="input-group"> <span class="input-group-btn">
            <input type="file" id="file">
            </span>
         </div>
         <br>
         <button  type="button" class="btn btn-default" data-ng-click="uploadAttachment($index, type)">Upload</button>
   </form>
   </div>
      <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
   </div>
</div>

And finally my function which resides inside RiskListCtrl (the only controller i use):

  $scope.uploadAttachment = function executeUploadAttachment(index, type) {
var listname = "Risk Register";
var id = $scope.items[index].Id;
console.log(indexID);
readFile("uploadControlId").done(function(buffer, fileName) {
    uploadAttachment(type, id, listname, fileName, buffer).done(function() {
        alert("success");
    }).fail(function() {
        alert("error in uploading attachment");
    })
}).fail(function(err) {
    alert("error in reading file content");
});
}

It seems that $scope.items[index].Id is empty. Error: Cannot read property 'Id' of undefined

Upvotes: 4

Views: 1988

Answers (2)

Humble Dolt
Humble Dolt

Reputation: 970

Since, you are getting the index value outside model then you can also use ng-click and then call a function in your controller and store the index value in a temporary variable and then when you are using submit button then just take make another variable and assign the value of temporary variable to your variable. for example:

     <button type="button" data-ng-show="editMode" data-ng-click="editMode = false; updateItem($index)" class="btn btn-default">Save</button>

and then make a function in your controller

$scope.updateItem = functon(index)
{
$scope.tempVar = index;
}

now use the value of tempVar in you function 

 $scope.uploadAttachment = function executeUploadAttachment(index, type) {
var index = tempVar;            //assign the value of tempvar to index
var listname = "Risk Register";
var id = $scope.items[index].Id;
console.log(indexID);
readFile("uploadControlId").done(function(buffer, fileName) {
    uploadAttachment(type, id, listname, fileName, buffer).done(function() {
        alert("success");
    }).fail(function() {
        alert("error in uploading attachment");
    })
}).fail(function(err) {
    alert("error in reading file content");
});
}

Upvotes: 1

DonJuwe
DonJuwe

Reputation: 4563

The modal window has its own scope. That means you need to resolve data you want to pass into the modal's scope. To do so, use resolve within the modals open(options) method.

Before I will give you an example, I want to suggest having only one modal for all your table items. This will let you keep a single template where you can easily use id (now, you create a template for each of your table items which is not valid). Just call a controller function and pass your $index:

<button type="button" class="btn btn-primary uploadBtn" data-ng-show="editMode" ng-click="openModal($index)">Upload file  <i class="fa fa-cloud-upload"></i></button>

In your controller, create the modal instance and refer to the template:

$scope.openModal = function(index) {
    var modalInstance = $modal.open({
        templateUrl: 'myPath/myTemplate.html',
        controller: 'MyModalCtrl',
        resolve: {
            index: function() {
                return index;
            }
        }
    });
};

Now you can access index in your MyModalCtrl's scope by injecting index:

angular.module('myModule', []).controller('MyModalCtrl', function($scope, index) {
    $scope.index = index;
});

Upvotes: 3

Related Questions