0

I have an Object representing a "discussion" or a "debate" that has two children -- each child is a collection of child objects representing "contentions" in the debate. One child is a collection of "affirmative" contentions, the other is of "negative" contentions.

I'm using something like this:

<div ng-controller="contentionGroupCtrl" ng-repeat="(contentionType, contentionGroup) in debate.contentions_sorted" class="contention {[{contentionType}]}-section">
  <a class="button contention-new" ng-click="toggleEditForm()">+ Add New Contention</a>
  <div class="contention-new" ng-show="editing">
    <form ng-submit="formContentionSubmit()" class="ng-scope ng-pristine ng-invalid ng-invalid-required">
      <input type="text" id="contention_name" name="contention[name]" required="required" ng-model="edit.name" placeholder="New Contention" class="ng-pristine ng-invalid ng-invalid-required">
      <div>
        <input type="radio" id="contention_aff_0" name="contention[aff]" required="required" ng-model="edit.aff" value="1">
        <label for="contention_aff_0" class="required">Affirmative</label>
        <input type="radio" id="contention_aff_1" name="contention[aff]" required="required" ng-model="edit.aff" value="0">
        <label for="contention_aff_1" class="required">Negative</label>
      </div>
      <input type="button" ng-click="toggleEditForm()" value="Cancel">
      <input type="submit" value="Save">
    </form>
  </div>
  <div ng-controller="contentionCtrl" ng-repeat="contention in contentionGroup" class="contention" id="contention-{[{ contention.id }]}">
    EACH CONTENTION CONTENT STUFF HERE
  </div>
</div>

This displays two sets of contention, and each has a "Add New Contention" form at the top. The form is toggled based on the toggleEditForm() method. I'm using the same form template for "New Contention" and "Edit Contention", and hence that form has a model (radio buttons) for whether the contention is an "Affirmative" or "Negative" contention.

The controller "contentionGroupCtrl" is for the group of contentions, and its toggleEditForm method looks like this:

// Toggle New Contention Form
  $scope.toggleEditForm = function() {
    var ct;
    $scope.editing = !$scope.editing; // First display or hide the form
    if ($scope.editing == true) {  // If displaying the form, initialize 
      if ($scope.contentionType == 'aff') {
        ct = 1; // 'aff' equates to 1 in the model
      }
      else {
        ct = 0;
      }
      $scope.edit.aff = ct; // Sets the radio button appropriately

      // We are now editing
      $scope.edit.name = ''; // Blanks out the contention "Name" field for creating a new contention
    }
  };

Everything works great, except: Let's say you open the "Affirmative"-side "Add New Contention" form. It will present a blank Name, with the radio button "Affirmative" selected. If you then click the "Negative"-side "Add New Contention" button, the appropriate form will appear, but both "Name" fields will be blanked out, and the radio button will be selected for "Negative" in both.

$scope should be different on each side, shouldn't it? Each form uses its own $scope.edit model; why should modifying the Negative contention side's "edit.name" and "edit.aff" models affect the Affirmative side's?

Offlein
  • 665
  • 6
  • 22
  • 5
    simple demo in jsfiddle or plunker that replicates the issue and lets people see the cotrollers scope hierarchy better would help – charlietfl Apr 01 '13 at 03:28
  • OK! I will attempt this later. I tried just now but it's taking too long! Thank you for the great suggestion. – Offlein Apr 01 '13 at 14:44
  • 1
    Where is `$scope.edit` defined? If it is defined in a controller above `contentionGroupCtrl` (i.e., above your `ng-repeat`), then all child controllers will share the same single `$scope.edit` object, due to the way JavaScript prototypal inheritance works. – Mark Rajcok Apr 01 '13 at 17:13
  • @MarkRajcok Wow, I was just reading your [absurdly good answer here](http://stackoverflow.com/a/14049482/899003). I had $scope.edit defined in a parent "debateCtrl" controller which I didn't include here. I initialized it within contentionCtrl, however, and suddenly this issue stopped. The Aff and Neg contention groups no longer share scope! ...Unfortunately, the child scope (contentionCtrl) now opens all its Edit forms when click "Add New Contention". – Offlein Apr 02 '13 at 00:25
  • [Ran out of room.] However, what's more important is to note that, per that answer you wrote, I should **probably stop nesting controllers**! (I'm also putting ng-repeat and ng-controller on the same element, which, I think, is bad form too.) I think I am going to re-engineer this to use a service to handle CRUD on Debates, Contentions, and the rest. ...Now what do I do with this question then? Answer it myself? – Offlein Apr 02 '13 at 00:30
  • 1
    Yes, answer it yourself and accept the answer. – Mark Rajcok Apr 03 '13 at 02:48

1 Answers1

1

Based on what I've learned since asking this and from following Mark Rajcok's advice, the main thrust of the issue is that I am nesting Scopes and this is not best practice.

In my case, other $scope variables that I was relying on needed to be initialized within the child scope, or else they were inheriting from the parent scope. This is entirely what I was shooting for, but it ended up just getting confused in my implementation, and I missed fixing it.

More relevant than anything, however: try not to nest scopes! Instead, handle data interface between controllers using a custom Service.

Offlein
  • 665
  • 6
  • 22