Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Testing dynamically named inputs inside ng-repeat using $setViewValue() #5125

Closed
bnppl opened this issue Nov 25, 2013 · 4 comments
Closed

Testing dynamically named inputs inside ng-repeat using $setViewValue() #5125

bnppl opened this issue Nov 25, 2013 · 4 comments

Comments

@bnppl
Copy link

bnppl commented Nov 25, 2013

Hi!
I cross posted this in stack overflow - I hope that isn't bad manners.

I am trying to test a directive that dynamically adds form inputs to a page using ng-repeat. The code runs fine in the browser but trying to test it with Jasmine I discovered what seems (to me) to be a bug or at least weird behaviour in Angular.

I'd expect to be able to set the view value on an input using

form.questions.answer1.$setViewValue();
but in my tests when I console log the form.questions object I get this:

form.questions.answer{{ question.questionId }}
i.e. The index of the object hasn't been parsed (although the html is output correctly).

Is there any other way of triggering the ng-change event? I have tried setting the value of the input using jQuery (inside my test) but although it successfully changes the value it doesn't fire off the ng-change event.

plunker (check the contents of your console to see what I mean.).

My code:

app.directive('repeatedInputs', function(){
  var template ='<div  ng-form name="questions">'+
  '<div ng-repeat="(key, question) in questions" >' +                                                   
    '<span id="question{{ question.questionId }}">{{ question.questionText }}</span>'+
    '<span><input type="text" name="answer{{ question.questionId }}"' +
     ' id="answer{{question.questionId}}"' +                                                                  
    '  ng-model="question.answer" ng-change="change()"/></span>' +
  '</div>' +
  '</div>';

  return {                                                                                                                             
      template: template,
      scope: {
        answers: '=',
        singleAnswer: '='
      },

      /**                                                                                                                                
       * Links the directive to the view.                                                                                                
       *                                                                                                                                 
       * @param {object} scope                                                                                                           
       * Reference to the directive scope.                                                                                               
       *                                                                                                                                 
       * @param {object} elm                                                                                                             
       * Reference to the directive element.                                                                                             
       */                                                                                                                                
      link: function (scope, element) {                                                                                                  

        scope.questions = [
          {
            questionId: '1',
            questionText: 'What is your name?',
            answer: null
          },
          { 
            questionId: '2',
            questionText: 'What is your quest?',
            answer: null
          },
          { 
            questionId: '3',
            questionText: 'What is your favourite colour?',
            answer: null
          }
        ];

        scope.change = function () {
          for (var i in scope.questions) {
            scope.answers[i] = scope.questions[i].answer;
          }
        };
      }
   };
});

Here is my spec file:

describe('repeating inputs directive', function () {                           

  var element, scope, $compile;                                                                     

  beforeEach(function(){
    module('plunker');
    inject(function ($rootScope, _$compile_) {                   

      scope = $rootScope.$new();                                                  
      scope.theAnswers = [];
      scope.singleAnswer = null;

      element = angular.element(                                                  
        '<form name="form">'
        +'<div repeated-inputs answers="theAnswers" single-answer="singleAnswer">'
        +'</div></form>'                 
      );                                                                          
      $compile = _$compile_;
      $compile(element)(scope);
      scope.$apply();
    })
  });

  it('should store the input from the answers in the parent scope',             
      function () {                                                             

    // I want to do this
    //scope.form.questions.answer1.$setViewValue('Ben');

    // but inside the object, the answers name field is not being parsed
    // I am expecting the path to the answer to look like this:
    // scope.form.questions.answer1
    // instead it looks like this:
    // scope.form.questions.answer{{ question.questionId }}
    console.log(scope.form.questions);

    expect(scope.theAnswers[0]).toEqual('Ben');

  }); 
});  
@caitp
Copy link
Contributor

caitp commented Nov 25, 2013

Interpolated names (for ngModel) are not currently supported. I have a patch to add this which awaits review, but it's a pretty simple change that should solve these problems for people.

@bnppl
Copy link
Author

bnppl commented Nov 25, 2013

Thanks for the advice! Do you know if there is another way of triggering the ng-change event on the input other than using $setViewValue() on the form?

@caitp
Copy link
Contributor

caitp commented Nov 25, 2013

ng-change is triggered by a function added to the $viewChangeListeners property of the ngModelController --- these are only called during $setViewValue(), I'm afraid.

@bnppl
Copy link
Author

bnppl commented Nov 25, 2013

OK thanks! I'll try re-factor it to make it testable some other way!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants