简体   繁体   中英

Angular $scope.$watch - creating an array and total depending on ng-model/length

I have a form and want to create a 'completion progress tracker'. If we have ten inputs that are filled in, each input will add 10 to an array, which will render some text: '100% complete'. If you remove or don't have any data in an input, 10 will be remove from the array.

In other words I want to:

  1. Watch some items for changes

  2. If an item has X length (or some other argument), push 10 to an array

  3. If an item has X length removed, remove 10 from the array

  4. Create a total of the array

I've been trying things out with $scope.$watch and different array methods like pop() , splice() etc, but i'm not sure how to get this working correctly, and with nice, DRY code.

This is what I have so far (simplified outside of the app with just 3 items).

controller:

$scope.userName = 'homer';
$scope.userDescription = 'I really like...';
$scope.userUrl = 'http://something.com'
$scope.theArray = [];

$scope.$watch('userName + userDescription + userUrl', function(){

  $scope.theTotal = 0;

  if($scope.userName.length >= 3) {
    //$scope.theArray.pop(10);
    //$scope.theArray.splice(1,1);
    $scope.theArray.push(10);
  }

  if($scope.userName.length < 3) {
    console.info('oh no!');
    $scope.theArray.pop(10);
  }

  if($scope.userDescription.length > 3) {
    $scope.theArray.push(10);
  }

  if($scope.userUrl.length > 3) {
    $scope.theArray.push(10);
  }

  var x = 0;
  while (x < $scope.theArray.length) {
    $scope.theTotal += $scope.theArray[x];
    x++;
  }

  console.log($scope.theArray)

});

template:

<input type="text" ng-model="userName" placeholder="name" />
<input type="text" ng-model="userDescription" placeholder="description" />
<input type="url" ng-model="userUrl" placeholder="url" />

<p>userName length: {{userName.length}}</p>
<p>userDescription length: {{userDescription.length}}</p>
<p>userURL length: {{userUrl.length}}</p>
<br/>
<p><strong>completion: {{theTotal}}</strong></p>

But, obviously, this doesn't work correctly. Right now the array just keeps adding and adding, regardless of if the length is below or above the desired amount. I expect this with $scope.$watch , I know the changes are triggered when the $watch is in action - is there a way to limit an array push() here?

I've tried doing a pop() and push() at the same time and this 'works', to some degree, but it's not elegant and doesn't help to get it working as desired.

How can I achieve this? Do I need to approach $scope.$watch and array methods differently? Or maybe something completely different?

Here is a codepen.

If you don't the array for other purposes, you can avoid the array, and only add to the total if a condition is met:

$scope.theTotal = 0;
if($scope.userName.length >= 3) {
    $scope.theTotal += 10;
  }

  if($scope.userDescription.length > 3) {
    $scope.theTotal += 10;
  }

  if($scope.userUrl.length > 3) {
    $scope.theTotal += 10;
  }

Check this pen .

Tony, let's go through your $watch func. For example I've changed userName (and now it's length < 3) we getting into $watch function:

  1. The first if statement ignoring (we get length < 3)
  2. We go to a second if statement and pop() some val from the array
  3. And now your algorithm doesn't stop and gets into if($scope.userDescription.length > 3) . I didn't change userDescription and it's length > 3 - so we add some val to the array.

That's why you still keep adding new items to array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM