Using Angular's $scope.$watch to dynamically generate an array and calculate the total based on the ng-model's length

I am working on a form and aiming to develop a 'completion progress tracker'. The idea is that for every input field that is filled in, 10 points will be added to an array. When all ten inputs are completed, the text '100% complete' will be displayed. Conversely, if data is removed from any input, 10 points will be deducted from the array.

To break it down, my goal is:

  1. Monitor changes in certain items

  2. If an item meets a specific criteria (e.g., X length), add 10 points to the array

  3. If an item no longer meets the criteria, subtract 10 points from the array

  4. Calculate the total score of the array

I have been experimenting with $scope.$watch and various array methods like pop(), splice(), but I am struggling to make it work seamlessly with clean and DRY code.

Below is a simplified version of what I have tried so far (outside of the main app, focusing on just three 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);
  }

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

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

  // Checks URL length
  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>

It's evident that this current implementation has flaws as the array continuously adds points regardless of meeting the desired criteria. To tackle this issue, I acknowledge the behavior of $scope.$watch triggering changes. Is there a method to control the push() operation on the array?

Although combining pop() and push() somewhat resolves the issue, it lacks elegance and does not align with the intended functionality. How can I overcome this challenge? Should I rethink my approach with $scope.$watch and array methods or consider a different strategy altogether?

You can view the codepen here.

Answer №1

To optimize the code and avoid using an array for other purposes, you can simply increment a total variable based on certain conditions being 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;
  }

Take a look at this snippet.

Answer №2

Hey Tony, let's review your $watch function. For instance, when I modified the userName (which now has a length of less than 3), we triggered the $watch function:

  1. The initial if statement is bypassed (due to the length being less than 3)
  2. We move on to a second if statement and utilize the pop() method to remove a value from the array
  3. However, the algorithm proceeds to the
    if($scope.userDescription.length > 3)
    condition. Since I didn't alter the userDescription property and its length remains above 3, a new value is appended to the array.

This explains why new items are continuously being added to the array.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for preventing redundant methods in angular services

Is there a way to avoid repeating identical code in each service? I have multiple services for different API endpoints: getLecturesData(orderBy?: string, orderDirection = 'asc', page = 1, pageSize = 10): Observable<LecturesData> { l ...

What is the best way to manage json-parse errors in a node.js environment?

After countless hours of research, I am still unable to find a solution to my seemingly simple and common problem: In Node.js using Express, I want to retrieve JSON-data via http-POST. To simplify the process, I intend to utilize the app.use(express.json( ...

Issues with method invocation in jQuery's .ajax requestI am having

After reading this Stack Overflow post, I now understand how to retrieve a return value from an AJAX call: function GetIsDataReady(input) { $.ajax({ url: "http://www.blah.com/services/TestsService.svc/IsDataReady", ...

How to trigger a typescript function from an external JavaScript function

In my project, I have a TypeScript file called 'abc.ts' which includes a method named 'ScanCode()'. Additionally, I have a separate JavaScript file named "sample.js" with a method titled foo(). My goal is to invoke the ScanCode method f ...

Having trouble with Selenium WebDriverJS on both FireFox and Internet Explorer

Having developed multiple JavaScript tests using chromedriver to run them in Chrome, I am now facing the challenge of running these same tests in FireFox and IE. The test below is functional in Chrome: var assert = require('assert'), test = requ ...

`Generate JSON list`

How can I properly encode an array in PHP as JSON, ensuring it includes two variables? $var = 33; $last = 44; Here are the database results: foreach($query->result() as $r) { $data[]= $r; // Fills the array with results } I am attempting to cre ...

What causes the 'find' query to return a Query object instead of the expected data in MongoDB?

After researching extensively on SO, I have yet to find a solution to my ongoing issue. Currently, I am in the process of developing a project using node, express, and mongodb. To start off, I created a seeder file to populate some data into mongodb: var ...

JavaScript 'this' pointing to incorrect object

Unfortunately, this doesn't seem to be pointing to the correct object in this scenario. I'm having trouble figuring out how to reference the right one. function myObject() { this.someMethod1 = function() { var elementBtn = document.getEl ...

Summary Table Row Expansion and Contraction Feature in AngularJS

Looking for assistance in creating a table layout using angularJS? I'm having trouble figuring out the most efficient way to achieve this. Any ideas on how I can structure my table based on the following object? Here is the object I want to use: var ...

Tips for utilizing the Hook API design pattern

I'm currently learning how to customize Material UI components. The tutorial provides the following Hook API code: import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Button from '@materia ...

Tips for refreshing a GET request within a Vue.js application

I am receiving data from my Rails API backend and I would like to automatically refresh that GET request every 15 seconds. This way, if there are any changes on the backend (for example, if a POST request is made to another route), it will reload and retri ...

Is a pair of <type, type> or two 'type' variables more memory-efficient?

When comparing the memory usage, which of the following options requires less memory? short X; short Y; pair<short,short> Coords; ...

There was a TypeError encountered while trying to read properties of undefined in Next.js version 13

I've encountered a problem in the title with my post API endpoint that I created in Next.js. The purpose of my endpoint is for form submission, where I gather inputs and send them to my email. Currently, my code successfully sends the email and I rec ...

Prevent going back in the browser within the ui-router in AngularJS

After logging into the application, I want to make sure that when I click the back button in the browser, it doesn't take me back to the login page (the back button should be disabled at that point). $stateProvider(function('$stateProvider' ...

Does .NET MVC provide the necessary separation of HTML/CSS/JS for my project?

Currently, I am collaborating with my ASP.NET development team in an effort to improve the quality of our HTML output. We are facing challenges due to ASP.NET's tendency to insert JavaScript directly into the page, creating dependencies on JS for form ...

The animation in threejs using lerp and camera transitions lacks fluidity

Why does linear interpolation pose a problem? When calling zoomCamera() inside an update() function that is being animated, there is a smooth lerp effect. However, when called within the onObjectsClick() function, the lerp is sharp. function onObjectsCl ...

What is the best way to transfer the selected value from a dropdown to another component in React?

I am working on a select component where the values are fetched from useEffect data. When I select a value, I can see it in the console. const SelectName = () => { const [value, setValue] = useState(0); const [names, setNames] = useState([]); cons ...

Display bootstrap modal hyperlink in web browser search bar

Utilizing bootstrap cards with href tags allows users to click on them and open bootstrap modals. I want users to be able to copy the modal's URL link for sharing purposes, but the issue is that when the modal is opened, the URL remains unchanged. How ...

Load an external script once the page has finished loading by leveraging the power of $(document).ready() in conjunction with $.getScript()

Is it possible to load a script in the header of a website instead of at the bottom? I've been trying but it's not working as expected. Here is an example of what I'm attempting: HTML file: <!DOCTYPE html> <html lang="en"> < ...

Option to Exclude Files in Gulp-uncss

I've been trying to use the ignore option, but it doesn't appear to be functioning as expected. My code looks like this: .pipe(plugins.uncss({ html: glob.sync('./**/*.{csh,h}tml'), ignore: ['.active'] ...