Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
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

Description

@bnppl

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');

  }); 
});  

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions