0

I've a long calculation form and want to prefill some values for displaying initial results. These initial values should live in the template to have these easily editable. It seems, the angular way is to use a directive which reads the input value fields and initializes the app with these values.

Here is one way to to set the model value from the input field:

<input name="card[description]" value="Visa-4242" ng-model="card.description" ng-initial>

Coffeescript:

app = angular.module 'forms', []

app.directive 'ngInitial', ->
  restrict: 'A'
  controller: ['$scope', '$element', '$attrs', '$parse', ($scope, $element, $attrs, $parse) ->
    val = $attrs.sbInitial || $attrs.value
    getter = $parse($attrs.ngModel)
    setter = getter.assign
    setter($scope, val)
]

Source: Angular js init ng-model from default values

Unfortunately this doesn't work in my app. The values are displayed but the results aren't calculated. I have to manual fill out the fields in the browser to start the calculation.

The input fields are watched in my controller, like so:

$scope.$watch(
  'inputValues.permeatCapacity',

  function (newValue, oldValue) {
    if (newValue === oldValue) {
      return;
    }

    permeatCapacity = $scope.inputValues.permeatCapacity;
    permeatPerDay = permeatFactory.getPermeatPerDay(permeatCapacity);

    $scope.permeatPerDay = $filter('number')(permeatPerDay, 2);
  }
);

What's the best directive for this problem or is there a better way in Angular.js?

UPDATE

I've just found a really dirty way in the controller to update the input fields after initialization that make use of the bound calculations. It not only feels like an bad idea, the initial values also don't live in the template:

$timeout(function () {
  $scope.inputValues.overallRecovery = 40;
  $scope.inputValues.permeatCapacity = 7.2;
}, 0);

In comparison, this initial object in my controller fills out the fields but doesn't trigger the watchers (important for the bound calculations):

$scope.inputValues = {
  overallRecovery: 40,
  permeatCapacity: 7.2
};

But there is a better way to do this, isn't it?

Community
  • 1
  • 1
rzschoch
  • 358
  • 5
  • 13
  • 1
    Can't you just initialize your form model in your controller? – Beterraba Sep 25 '13 at 19:22
  • Thanks for your time and idea. Unfortunately not, the values need to be configurable in the template and the calculation is only triggered through the watch methods. – rzschoch Sep 26 '13 at 10:56

2 Answers2

2

Ok, here's what I found out. The condition:

if (newValue === oldValue) {
  return;
}

in my watch methods blocked the initial calculation. I can now use a really simple directive for my usecase:

An input field in the template:

<input type="text" id="overall-recovery" value="40" ng-model="inputValues.overallRecovery" initial-value>

The directive:

angular.module('ksbApp')
 .directive('initialValue', function ($compile) {
   return {
     restrict: 'A',
     require: 'ngModel',
     link: function (scope, element, attrs, ngModel) {
       var initialValue = attrs.value;

       ngModel.$setViewValue(initialValue);
     }
   };
 });

In this case, the value "40" is pushed to the model during initialization.

Is there anything I could do better?

rzschoch
  • 358
  • 5
  • 13
0

Not sure why you would need a directive for this, unless I dont understand the question fully. Spin up the model in scope, setting the values where on the controller, and then bind them using ngmodel.

in the controller:

scope.inputValues = {permeatCapacity: 1};
scope.calc = function(){
 return permeatFactory(scope.inputValues.perMeatCapacity);
};

in the view:

<input ng-model="inputValues.permeatCapacity" type="text">

<button ng-click="calc()" />

In later versions of angular you can even have the calculation run AS the values in the model change using ng-change.

Fourth
  • 9,163
  • 1
  • 23
  • 28
  • Thanks. I'm looking for a solution that let's the user define the default values directly in the template. So an should output "30" in this field and also trigger my linked watch method which executes the calculation. This calculation fills other fields in the form with the results. How can I do that? The above linked solution is a good starting point but my watch methods aren't triggered which is the reason for the lacking results in my form. – rzschoch Sep 26 '13 at 12:28