GeckStar GeckStar - 13 days ago 8
AngularJS Question

Set initial value of text input field without triggering ng-change

The scenario is a Sudoku game with JavaScript and AngularJS.

The Sudoku field is an Array (rows) of Arrays (columns). All arrays have a length of 9. I name this Sudoku field

matrix
. The function
exampleMatrix()
returns such a matrix which already has some fields filled.

An
updateValue(sudokuMatrix, row, col, val)
function changes the field at position row
row
and column
col
in the matrix
sudokuMatrix
to the value
val
.

function TestController($scope) {
$scope.matrix = exampleMatrix();
$scope.updateValue = updateValue;
$scope.getMatrixVal = function getMatrixVal(row, col) {
return $scope.matrix[row][col];
};
}


What I want to do is to display every field of the matrix as an
<input type="text">
field in HTML. I want all the fields to be initially set to the values they have in the matrix. If the input of a text field is changed, I want the value to be updated in the
$scope.matrix
object.

I can fill the fields with the values of the matrix with no problem with the following HTML/AngularJS Code:

<div ng-repeat="(rowIndex,row) in matrix track by $index">
<input type="text" size="1" value="{{col}}"
ng-repeat="(colIndex,col) in row track by $index">
</div>


But I cannot update the values in the
$scope.matrix
object yet, of course.

The problems I am facing are


  1. If I change the value in an input field, the
    matrix
    should update that value. I can do this with
    ng-change="updateValue(matrix, rowIndex, colIndex, inputVal)"
    .

  2. In order to be able to change the
    matrix
    in the scope with
    ng-change
    , I need an
    ng-model
    , which binds the input of the field to a variable:
    ng-model="inputVal"

  3. If I add those two lines, the input fields are not filled initally with the values in the
    matrix
    object of the scope.



The current code looks like this:

<div ng-repeat="(rowIndex,row) in matrix track by $index">
<input type="text" size="1" value="{{getMatrixVal(rowIndex, colIndex)}}"
ng-model="inputVal"
ng-change="updateValue(matrix, rowIndex, colIndex, inputVal)"
ng-repeat="(colIndex,col) in row track by $index">
</div>


My guess is that when the site is generated,
ng-model
assigns the empty value of the input field to
inputVal
, and that
ng-change
is immediately triggered. Every field of the matrix would thus be populated with an empty value. AngularJS is not throwing any errors though, so I cannot be sure. Anyways, I'm at a loss here and do not know how to get the initial values to be written to the fields initially and
ng-change
to be only called afterwards. I appreciate every help.

JSFiddle: https://jsfiddle.net/30xkedmp/

JavaScript: http://pastebin.com/8cge8BXs
HTML: http://pastebin.com/X0YUPU4h

Answer

You can try this code and see,I have only replaced your value attribute with the ng-value attribute in input tag as shown below,

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
</head>
<body ng-controller="TestController">
<div ng-repeat="(rowIndex,row) in matrix track by $index">
  <input type="text" size="1" ng-value="getMatrixVal(rowIndex, colIndex)"
         ng-model="inputVal"
         ng-change="updateValue(matrix, rowIndex, colIndex, inputVal)"
         ng-repeat="(colIndex,col) in row track by $index">
</div>
<script>
angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
  $controllerProvider.allowGlobals();
}]);

function emptyRow() {
  return [0, 0, 0, 0, 0, 0, 0, 0, 0];
}

function emptyMatrix() {
  var sudokuMatrix = [];
  for (var i = 0; i < 9; i++) {
    sudokuMatrix[i] = emptyRow();
  }
  return sudokuMatrix;
}

function updateValue(sudokuMatrix, row, col, val) {
  row = parseInt(row);
  col = parseInt(col);
  val = parseInt(val);
  sudokuMatrix[row][col] = val;
}

function exampleMatrix() {
  matrix = emptyMatrix();
  updateValue(matrix, 0, 2, 6);
  updateValue(matrix, 0, 3, 3);
  updateValue(matrix, 0, 4, 2);

  updateValue(matrix, 1, 2, 1);
  updateValue(matrix, 1, 5, 5);
  updateValue(matrix, 1, 6, 3);
  updateValue(matrix, 1, 7, 6);

  updateValue(matrix, 2, 0, 9);
  updateValue(matrix, 2, 1, 4);
  updateValue(matrix, 2, 3, 6);

  updateValue(matrix, 3, 2, 4);

  updateValue(matrix, 4, 0, 8);
  updateValue(matrix, 4, 1, 7);
  updateValue(matrix, 4, 3, 1);
  updateValue(matrix, 4, 4, 3);
  updateValue(matrix, 4, 5, 4);
  updateValue(matrix, 4, 7, 5);
  updateValue(matrix, 4, 8, 6);

  updateValue(matrix, 5, 6, 1);

  updateValue(matrix, 6, 5, 9);
  updateValue(matrix, 6, 7, 4);
  updateValue(matrix, 6, 8, 7);

  updateValue(matrix, 7, 1, 1);
  updateValue(matrix, 7, 2, 7);
  updateValue(matrix, 7, 3, 5);
  updateValue(matrix, 7, 6, 2);

  updateValue(matrix, 8, 4, 7);
  updateValue(matrix, 8, 5, 2);
  updateValue(matrix, 8, 6, 5);

  return matrix;
}

function TestController($scope) {
  $scope.matrix = exampleMatrix();
  $scope.updateValue = updateValue;
  $scope.getMatrixVal = function(row, col) {
    return $scope.matrix[row][col];
  };
}

</script>
</body>
</html>

The code snippet won't function here because it doesn't seem to be accepting the version of angular js i have specified, but the rest of the code is functioning well.

You can try replacing the value attribute by the ng-value attribute in your fiddle and try

Comments