2

I've a button in my angular app that will add an input element to my app dynamically. I want to attach model to this element and put it to watch group for tracking any changes. If user add multiple input elements, I want to add all those models in watch group and track which element changed its value. How can I do this?

<body ng-app="myApp">

<div ng-controller="GpaController" > 
<form id="mform">
 <select name="grade" ng-model="grade" ng-options="key as key for (key,value) in gradePoints" ></select>    
<input type="number" min="1" max="4" ng-model="score">

</form>
<button type="button" ng-click="addElement()">Add</button>

</div>
<script type="text/javascript" src="./app/angular.min.js"></script>
<script type="text/javascript" src="./app/jquery-2.1.3.min.js"></script>
<script type="text/javascript">

angular.module('myApp', [])
.controller('GpaController', ['$scope', '$compile', function($scope, $compile){
    $scope.grade = 'A';
    $scope.score = 4;
    var gradePoints = { 'A': 4, 'A-': 3.7, 
                   'B+': 3.3, 'B': 3.0, 'B-': 2.7, 
                   'C+': 2.3, 'C': 2.0, 'C-': 1.7, 
                   'D': 1, 'F': 0 };
    $scope.gradePoints = gradePoints;
            $scope.$watchGroup(['grade', 'score'], function(){
                console.log($scope.grade)
                var n = $scope.gradePoints[$scope.grade] * $scope.score;
                    console.log(n);
            });
            $scope.addElement = function(){
                var val = '<div><select name="grade" ng-model="grade" ng-  options="key as key for (key, value) in gradePoints" > </select><input type="number" min="1" max="4" ng-model="score"><div>';
                var ele = $compile(val)($scope);
                    $("#mform").append(ele);
            }

}]);
</script>
</body>
1
  • could you please add some code.. Commented Apr 23, 2015 at 14:59

2 Answers 2

1

You could try below way to check which variable has changed.

$scope.$watchGroup(['grade', 'score'],
  function(newVal, oldVal) {
    var changed = ''
    if (newVal[0] != oldVal[0])
        changed = 'grade';
    if (newVal[1] != oldVal[1])
        changed = 'score';
});

Refer this SO Answer for more details.

Update

For adding new value you can use ng-repeat instead of adding element

Markup

<form id="mform">
    <div ng-repeat="obj in objects">
        <select name="grade" ng-model="grade[obj]" 
         ng-options="key as key for (key,value) in gradePoints">
        </select>
        <input type="number" min="1" max="4" ng-model="score" />
    <div>
</form>

Controller

$scope.objects = ["1"]; //i have given sample, you could try something like this.
$scope.addElement = function(){ 
  $scope.objects.push($scope.objects.length + 1) 
}
Sign up to request clarification or add additional context in comments.

7 Comments

this is working for grade and score, but when i add new element, I want to add changes of that newly added input and select element and put them in watch group.
you shouldn't add an new element, you should maintain a array & new element into that array. On UI you should render element using ng-repeat and ng-reapeat will take care of newly added element automatically
i don't know in advance how many inputs are required, its up to user how much he/she wants to add.
but will it be the same ng-model like you have score?
@mallaudin take a look at my udpate
|
1

First off you are breaking the #1 rule of Angular. No DOM manipulation or element lookup should ever be in a controller, that belongs in a directive.

Actually all of the logic in your controller actually belongs in a directive.

.directive('gradePoints', function($parse) {
    return {
        template: function($element, $attrs) {
            return '<div><select name="grade" ng-model="' + $attrs.ngModel + '.grade" ng-options="key as key for (key, value) in gradePoints" > </select><input type="number" min="1" max="4" ng-model="' + $attrs.ngModel + '.score"> <div>',
        }
        link: function(scope, element, attrs) {
            $scope.grade = 'A';
            $scope.score = 4;
            var gradePoints = { 'A': 4, 'A-': 3.7, 
            'B+': 3.3, 'B': 3.0, 'B-': 2.7, 
            'C+': 2.3, 'C': 2.0, 'C-': 1.7, 
            'D': 1, 'F': 0 };

            $scope.$watchGroup(['grade', 'score'], function(){
                console.log($scope.grade)
                var n = $scope.gradePoints[$scope.grade] * $scope.score;
                console.log(n);
            });
        }
    }
});

Then add new grade-points directive to the page and $compile them.

In response to the question of how to add this directive to the page:

There are multiple way to go about this but the easier would probably be to have the directive in an ng-repeat and the controller add a new entry to the array of grades.

in controller:

$scope.rows = [];
$scope.addRow = function() {
    $scope.rows.push({});
}

In HTML:

<button ng-click="addRow()"/>
<div ng-repeat="row in rows">
    <grade-point ng-model="row"/>
</div>

1 Comment

I want to add a directive in response to ng-click event. You are saying there should be no dom manipulation then how will I add <gradepoints> directive to the dom tree ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.