Leveraging a tool to dynamically modify the styles of the active elements based on user interactions

My goal is to enhance the flexibility of my service by enabling it to handle any input field dynamically. Currently, I find myself manually coding everything, which is becoming quite labor-intensive. Is there a way to pass the element object when the elements ng-change property is triggered? This way, I can update the elements ng-class accordingly.

Example HTML:

<input type="text" id="email" data-ng-model="email" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor">

In the controller:

$scope.changeEmail = function () {
    if ($checkInput.checkEmail($scope.email)) {
        // email input is valid
        $scope.emailFormControlColor = 'form-control-success'; // update class to success
    } else {
        // email input is invalid
        if ($scope.emailFormControlColor === 'form-control-success') 
            $scope.emailFormControlColor = 'form-control-error'; // update class to error
    }
};

The service (included in the controller arguments):

.service('checkInput', ['$controller', '$window', '$location', function ($controller, $window, $location) {
    return {
        checkEmail: function (email) {
            // <--- Here, I aim to update the ng-class of the focused element dynamically! This would eliminate the need for manual coding for each input field!
            var regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            return regex.test(email);
        }
    };
}])

Currently, I am manually updating the $scope.emailFormControlColor. But what if I have multiple input fields:

<input type="text" id="email1" data-ng-model="email1" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor1">
<input type="text" id="email2" data-ng-model="email2" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor2">
<input type="text" id="email3" data-ng-model="email3" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor3">

How can I modify my service to eliminate the need for manual coding like:

$scope.emailFormControlColor1 = 'form-control-success';
$scope.emailFormControlColor2 = 'form-control-success';
$scope.emailFormControlColor3 = 'form-control-success';

I hope my query is clear. If not, please let me know and I will clarify!

Answer №1

In my opinion, utilizing a directive to address this issue is the preferred approach. Firstly, it is generally discouraged to manipulate the DOM directly within a controller or service as it is considered an anti-pattern.

Another benefit of using a directive is that it provides access to the DOM element on which the directive is applied. Below is a snippet of untested code that can serve as a starting point:

myApp.directive('validateEmail', function() {
  require: 'ngModel',
  link: function(scope, element, attributes, ngModelController) {
    // Ensure ng-model is used on this element to interact with Angular's validator pipeline
    ngModelController.validators.validateEmail = function(modelValue, viewValue) {
      // Determine if the email is valid based on a regular expression
      var regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      var isValid = regex.test(viewValue);
      // Utilize this opportunity to manipulate the DOM
      element.toggleClass('valid-email', isValid);
      element.toggleClass('invalid-email', !isValid);
      return isValid;
    });
  }
});

Instead of directly adding CSS classes in the directive, you can leverage Angular's built-in validation feature. The directive remains the same, but the CSS classes are not applied within the directive. When the directive's validation logic returns false, Angular automatically marks the field as invalid, allowing you to style it in your HTML:

<form name="myForm">
  <input ng-model="userEmail"
         name="email" 
         validate-email
         ng-class="{'valid-email': myForm.email.$valid, 'invalid-email': myForm.email.$invalid}">
</form>

In the above code, the CSS classes are applied when the field is invalid. You can also target specific validation errors by referencing the validator name. For example:

<form name="myForm">
  <input ng-model="userEmail"
         name="email" 
         validate-email
         ng-class="{'valid-email': !myForm.email.$error.validateEmail, 'invalid-email': myForm.email.$error.validateEmail}">
</form>

Answer №2

To streamline the process, I suggest creating an object that consolidates all the necessary email information. Here's an example:

HTML:

<input type="text" id="email0" data-ng-model="emails[0].value" data-ng-change="changeEmail(emails[0])" placeholder="your email here" data-ng-class="emails[0].class">
<input type="text" id="email1" data-ng-model="emails[1].value" data-ng-change="changeEmail(emails[1])" placeholder="your email here" data-ng-class="emails[1].class">
<input type="text" id="email2" data-ng-model="emails[2].value" data-ng-change="changeEmail(emails[2])" placeholder="your email here" data-ng-class="emails[2].class">

JavaScript:

$scope.emails = [
    { value: '', class: '' },
    { value: '', class: '' },
    { value: '', class: '' },
];

$scope.changeEmail = function (email) {
    if ($checkInput.checkEmail(email)) {
        // email input is good
        email.class = 'form-control-success'; // change from error to success
    } else {
        // email input is bad
        if (email.class === 'form-control-success') {
            email.class = 'form-control-error'; // change from success to error
        }
    }
};

To avoid repetition in the HTML, consider using ng-repeat as a more efficient approach.

Answer №3

Although Sunil D. led me in the right direction, the code he provided was not correct. Below is the corrected code that successfully makes it work. http://codepen.io/basickarl/pen/MyoZNC

HTML:

<div ng-app="app" ng-controller="ctrl">
  <form name="myForm">
    <input ng-model="name" name="name">
    <input ng-model="email" name="email" check-email>
  </form>
</div>

CSS:

input {
  border: 5px;
  border-style: solid;
  border-color: silver;
}
.input-invalid {
  border-color: red;
}
.input-valid {
  border-color: lime;
}

JS:

var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function($scope) {
  $scope.name = "";
  $scope.email = "";
}]);
app.directive('checkEmail', [function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, el, attr, ctrl) {
      ctrl.$validators.checkEmail = function(modelVal, viewVal) {
        var regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        var isValid = regex.test(viewVal);
        el.toggleClass('input-valid', isValid);
        el.toggleClass('input-invalid', !isValid);
        return isValid;
      }
    }
  }
}]);

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

Issue: It seems like there is an error with using functions as a React child. Uncertain about the exact location

This specific issue is one of the two errors I have come across in the same application referenced in my previous inquiry. The first error encountered is as follows: Warning: Functions are not valid as a React child. This may occur if you mistakenly return ...

What is the best way to deliver an HTML document in Express from a directory that is one level higher than my server folder?

I am facing an issue while trying to access an HTML file from my main directory through my Express server, which is located one level deeper in the server folder. Below is the configuration of my server code: const express = require('express') ...

The Bootstrap tooltip effectively fades away after displaying text, but it is not positioned correctly above the icon

Having some issues with my tooltip functionality. It seems to display the text on the left side and fades away upon mouseover, but it doesn't show up in a proper tooltip box over the icon as expected. I suspect that there might be a conflict between j ...

Simply click on the image to open it in a lightbox view with a thumbnail using jQuery

I have implemented a feature using fancybox to display images in a lightbox with thumbnail images. My requirement is that when a user clicks on an image, the clicked image should be displayed first in the lightbox and the rest of the images should not be s ...

shifting the length of o to the right by zero with the

While exploring the polyfill function for Array.includes, I stumbled upon the following lines of code: // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 4. Let n be ? ToInteger(fromIndex). // (If fromIndex is undef ...

Tips for transferring input values from a JavaScript function to a separate PHP page for storage in a database

This code snippet allows dynamic rows to be added to a table when the add button is clicked. Now, the goal is to retrieve the values entered into the text boxes and submit them to the database. <div id="addinput"> <p> <button name=" ...

Creating a case-insensitive path for pages in NextJS can be achieved by ensuring that all

I have a file named about.tsx under the pages folder. This means that the path for accessing the page is /about, allowing me to visit it through example.com/about. Strangely, attempting to access the same page via example.com/About results in a 404 error ...

Can the .scroll function be turned off when a user clicks on an anchor link that causes the page to scroll?

I am currently developing a timeline page and I want to implement a feature similar to the chronological list of years displayed on the right side of this webpage: As part of this feature, I have set up a click event which adds a circle border around the ...

Having trouble with Socket.io and its io.emit() method refusing to work? If communication from server to client isn't going smoothly, you may need a solution for sending data from the server to

My latest project is a document converter program that utilizes LibreOffice to convert documents to PDF format. Here's my server running on localhost:3000 import express from "express"; import bodyParser from "body-parser"; import ...

Does the `transitions.onStart` function in Angular 1.6 get called before or after the window load event?

Is there a way to ensure that my function is called before the window load event fires? I need a different transition method to achieve this. ...

Having issues with the jQuery toggle functionality

var resultsList = $("#test"); resultsList.text("Hello. This is jQuery!"); var tB = jQuery("#toggleButton"); tB.on("click", function() { resultsList.toggle(400); }); The syntax appears to be correct as there are no errors reported in the browser cons ...

Identifying the Click Event Within an ngx Bootstrap Modal

I recently set up an ngx bootstrap modal using the instructions provided in this helpful guide - . However, I'm facing a challenge in detecting click events within the modal body once it's open. Below is the code snippet from my app component. D ...

Unable to see the column filter in the data table

My datatable setup includes the column filter js on the page, everything is displaying and working smoothly without any errors in the console. However, after the smoothness loads, the inputs at the bottom are not visible. <body> <div id="stab ...

Changing a variable's value from within a Highmaps chart in Vue.js

Allow me to present my current project which involves the creation of a web application that displays data about devices spread across a country. To achieve this, I utilized Vue.js and HighCharts (employing HighMaps for the map component). The image below ...

Having trouble with ReactJS: Why is this.setState not working?

Hello there, I am currently learning ReactJS and struggling with an issue where I keep getting the error message "this.setState is not a function". constructor() { super(); this.state = { visible: false, navLinesShow: true }; ...

Error in React JS: SyntaxError - "Unexpected token '?'"

Following the guidelines on this website, I successfully set up a new reactJS application, proceeded to run npm i && npm run dev and encountered the following error message: /home/www/node_modules/next/dist/cli/next-dev.js:362 showAll ...

Using the $http Angular service does not alter the passed array

Currently diving into Angular and facing a roadblock with the $http service and a JSON array. Within my code, there's an array labeled names. While I'm able to display its content within the function, an error pops up when trying to do so outside ...

Material-ui Text Field

Is there anyone who can assist me in converting a TextField to a TextArea using the material-ui library? I am unable to find the parameter needed to personalize it as a TextArea: https://github.com/callemall/material-ui/blob/v1-beta/src/TextField/TextField ...

"Access Denied: Error 403 - Forbidden" encountered during the CSS minification and bundling process in ASP.NET Web Forms

After migrating my ASP.NET web forms application from a managed VPS to AWS EC2 using AWS Elastic Beanstalk, I encountered an issue with CSS bundling and minification. While the JavaScript was successfully bundled and minified on the Amazon server, the CSS ...

How to Use AJAX to Read a Text File in JavaScript

Having trouble with AJAX! I have successfully set up a marquee on my website, but now I want it to dynamically fetch the text from a text file. The goal is to read the text from the file (which contains only one line) and assign it to a global variable nam ...