Reputation: 15
I am new to angular and am trying to create a voting poll app. Right now I have 4 input boxes. 1 question and 3 answers to use when creating a new poll. I also have a button that adds a new input box if you want to add another answer. I read if I want to dynamically at content to the DOM I should use a directive. I created one that adds the new html content I want that should also add a ng-model attribute so I can access the content that is in an array along with the other content. The input boxes that were originally there work fine but when I add a new one it won't access it.
Directive/function code:
votingApp.directive('addAnswers', [function(){
return {
template:"<li><input type='text' ng-model='choices[3]' /></li>",
restrict: 'E'
}
}]);
Function that would add the new directive into the list of input boxes.
$scope.addAnswer = function(){
var node = document.createElement("LI");
var textnode = document.createElement("add-answers");
node.appendChild(textnode);
$scope.pollAnswers.appendChild(node);
};
Lastly where the it should be added to in the HTML.
<form ng-submit="createPoll()">
<p>Question</p>
<input type="text" ng-model="pollQuestion" />
<p>Answers</p>
<ul id="answers">
<li><input type="text" placeholder=" " ng-model="choices[0]" /></li>
<li><input type="text" placeholder=" " ng-model="choices[1]" /></li>
<li><input type="text" placeholder=" " ng-model="choices[2]" /> </li>
</ul>
<input id="create" type="submit" value="Create Poll" />
</form>
Basically as I add a new input I am going to make the ng-model = to the length of the array. However, when I do this the array doesn't get a slot bigger when adding a new element.
Upvotes: 0
Views: 57
Reputation: 129
Here's a plunk with a better example: http://plnkr.co/edit/gSWHCxgagMrF4OoEZDh1?p=preview
You could just ng-repeat based on your choices.
// controller
votingApp.controller('Controller', ['$scope', function($scope) {
$scope.choices = [];
$scope.addAnswer = function() {
$scope.choices.push('');
};
}]);
// html
<ul id="answers">
<li ng-repeat="answer in choices track by $index">
<input type="text" ng-model="choices[$index]" />
</li>
</ul>
Here's some stuff from my plunk so it's easier to see:
votingApp.directive('answers', function() {
return {
restrict: 'E',
scope: {
choices: '='
},
template: '<li ng-repeat="answer in choices track by $index"><input type="text" ng-model="choices[$index]" /></li>'
};
});
votingApp.controller('VotingController', [
'$scope',
function($scope) {
$scope.choices = [];
// if you want to start with some choices use this
// $scope.choices = new Array(3);
$scope.addAnswer = function() {
$scope.choices.push('');
};
}
]);
<body ng-app="votingApp" ng-controller="VotingController">
<ul>
<answers choices="choices"></answers>
</ul>
<button ng-click="addAnswer()">Add Answer</button>
</body>
Upvotes: 1
Reputation: 2947
That's because your HTML code you are injecting here
var textnode = document.createElement("add-answers");
isn't compiled by angular (and so your directive is not resolved).
My suggestion is to use a ng-repeat instead, so your content will be compiled (and your directive will be constructed properly, in a more angularjs way), like this:
<add-answers ng-repeat="answer in answers"> </add-answers>
By doing this, you need to have an array answers in your scope, that you can accomplish this way in your addAnswer function:
$scope.answers = [];
$scope.addAnswer = function(){
var node = document.createElement("LI");
$scope.answers.push({}); //new Answers
};
.
If you still need to use javascript to inject your components (sic!, don't do that!) then you will need to use the $compile service.
Upvotes: 2