Leverage the controller's properties and methods within the directive

My situation involves a variety of inputs, each with specific directives:

<input mask-value="ssn" validate="checkSsn"/>
<input mask-value="pin" validate="checkPin"/>

These properties are managed in the controller:

app.controller("Ctrl", ['$scope', function ($scope) {
    $scope.ssn = "";
    $scope.pin = "";

    $scope.checkSsn = function () { /* validate $scope.ssn */ };
    $scope.checkPin = function () { /* validate $scope.pin */ };
}]);

Next, we have the maskValue directive:

app.directive("maskValue", function () {
    return function (scope, element, attrs) {
        /* performs focus/blur actions and string manipulation */
        scope[attrs.maskValue] = this.value;
        scope[attrs.validate]();
    };
});

The current setup works, but it appears to be an inefficient use of Angular. It might be better to utilize an isolated scope like so:

    scope: {validate: "&"}

This way, I could call scope.validate() rather than scope[attrs.validate](). However, using an isolated scope prevents me from updating the corresponding value in the controller. Even setting {maskValue: "="} doesn't work as intended because it tries to update the parent's property instead. Using {ssn: "="} seems promising, but then I would only update a specific property of the controller, making the directive less flexible. Using $parent is also not recommended.

How can I dynamically access controller properties within an isolated scope directive?

EDIT: Using ng-model=ssn, etc. on the inputs is not viable because the actual input value changes during the focus/blur events in mask-value. For instance, it may be transformed to *****####, but the original value ######### needs to be stored somewhere for later use, preferably in the controller.

Answer №1

<div ng-app=bar>
  <div ng-controller=Controller>
  {{id}}
  <input data-mask="id" validate-input="checkId()">

app = angular.module("bar", []);

app.controller("Controller", ['$scope', function ($scope) {
    $scope.id = "";
    $scope.checkId = function () { console.log($scope.id); };
}]);

app.directive("dataMask", function () {
    return {
        scope: {
            validateInput: "&",
            maskValue: "="
        },
        link: function (scope, element, attrs) {
            element.bind("change", function () {
                scope.maskValue = this.value;
                scope.$apply();
                scope.validateInput();
            });
        },
    };
});

http://jsfiddle.net/abc123/

UPDATE:

it is recommended to pass the expression to evaluate as an argument to $apply for better error handling in AngularJS:

var val = this.value;
scope.$apply(function () {
    scope.maskValue = val;
});

Answer №2

Although you may have already found a solution for your query, I wanted to highlight the option of utilizing Angular's built-in functionalities to facilitate validation while still being able to apply ng-model. Below is an illustrative example:

app.directive("maskValue", function ($parse) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function (scope, element, attrs, ngModel) {
      if (!ngModel) return;
      var validator = $parse(attrs.validator)(scope);

      ngModel.$render = function() {
        var hasFocus = document.activeElement == element[0];
        if (ngModel.$valid || hasFocus) element.val(ngModel.$modelValue)
        else element.val('#######');
      };

      element.bind('blur', function() {
        ngModel.$setValidity('maskValue', validator(this.value))
        ngModel.$render();
      });

      element.bind('focus', function() {
        ngModel.$render();
      });
    }
  };
});

This directive leverages NgModelController in conjunction with ng-model to regulate view updates. In the given scenario, it will display ######## when the element loses focus and the validation function returns false. Upon refocusing the control, the actual value will be displayed enabling user modification. It is important to note that the scope property linked to the control remains unchanged while the view adapts based on the element's status (valid or invalid). For a demonstration, refer to the live example here.

Answer №3

My apologies, but have you considered implementing the following code snippet:

app = angular.module("foo", []);

app.controller("Ctrl", ['$scope', function ($scope) {
    $scope.ssn = "";
    $scope.validate = function () { console.log($scope.ssn); };
}]);

app.directive("maskValue", function () {
    return {
        link: function (scope, element, attrs) {
            element.bind("change", function () {  
                scope.validate();
            });
        },
    };
});

Furthermore, use this HTML structure:

<div ng-app=foo>
    <div ng-controller=Ctrl>
        <input ng-model="ssn" mask-value />
    </div>
</div>

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

How can you deduce the type from a different property in Typescript?

I have encountered obstacles in my development process and need assistance overcoming them. Currently, I am trying to configure TObject.props to only accept 'href' or 'download' if the condition TObject.name = 'a' is met, and ...

What is the best way to ensure consistency in a value across various browsers using Javascript?

I am currently developing a feature on a webpage that displays the last update date of the page. The functionality I am aiming for is to select a date in the first input box, click the update button, and have the second box populate the Last Updated field ...

Is there a way to retrieve the left offset of a floating element even when it is positioned outside the viewport?

My current situation involves creating several panels that are stacked side by side within a main container. Each panel takes up 100% of the viewport width and height. I want to be able to horizontally scroll to each panel when clicking on their respective ...

Accessing the Parent Variable from a Function in JavaScript: A Guide

How can you properly retrieve the value of x? let x = 5 const f = (n:number) => { let x = "Welcome"; return x * n // Referring to the first x, not the second one } Also, what is the accurate technical term for this action? ...

Remove search results in real-time

I'm currently working on implementing a search feature for a web application. While I have made some progress, I am facing an issue with removing items when the user backspaces so that the displayed items match the current search query or if the searc ...

How do I navigate back to show the initial parent component instead of the nested child component in ReactJS?

The data flow in my React app goes like this: SubmitForm -parent-> Results -parent-> Presentation -parent-> ButtonBackToSearch I am delving into ReactJS and trying to adopt the right mindset for creating single-page applications. Currently, I am ...

The function crypto.randomUUID() does not exist in the Vitest library

vite.config.ts import { sveltekit } from '@sveltejs/kit/vite'; const config = { plugins: [sveltekit()], test: { include: ['**/*.spec.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], environment: 'jsdom', glo ...

Display only distinct dates in the ng-repeat list

I'm trying to display an unordered list created using ng-repeat. Each list item includes a month header and a blog post. I'm struggling to find a clean solution to only show one instance of each month name without resorting to complex jQuery hac ...

What could be the reason for my Angular website displaying a directory instead of the expected content when deployed on I

My current challenge involves publishing an Angular application to a Windows server through IIS. Upon opening the site, instead of displaying the actual content, it shows a directory. However, when I manually click on index.html, the site appears as intend ...

In Angular 2, property binding will not function properly when attempting to bind to an object

I have encountered a strange issue with Angular 2 property binding. Let's start with the Store class: export class Store { id: number; name: string; address: string; } This is the component code snippet: export class MyBuggyComponent i ...

I am encountering a problem while attempting to fetch information from Firestore through the Firebase JS SDK

My current challenge revolves around retrieving data from Firestore using the Firebase JS SDK. A specific error message persists: An unexpected issue arises: TypeError: firebase_firestore__WEBPACK_IMPORTED_MODULE_3__.getDoc(...).data is not a function I ...

What is the best way to add a constant value to all objects within an array without having to iterate through each one

Is there a more concise way to add a fixed value to each object in an array without using a loop in JavaScript? Programming Language used: JavaScript Example Array: "cars": [ { "name":"Ford", "models":"Fiesta" }, { "name":"BMW", "models":"X1" }, ...

What is the solution for fixing the '$ not defined error' in a .js file with $ajax code?

var example = document.createElement("SCRIPT"); example.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"; var nodeScript= document.createTextNode("function test() {console.log('test message');$.ajax({ type: \"POST&bs ...

Sorting through a list post a retrieval action

Could you guys please help me understand why my code is not functioning properly? I am receiving an array from my backend rails API, which is providing the data correctly. I have created an empty array where I filter the records based on their ID. The fi ...

Guide to creating two-way data binding using ngModel for custom input elements like radio buttons

I am currently facing an issue with implementing a custom radio button element in Angular. Below is the code snippet for the markup I want to make functional within the parent component: <form> <my-radio [(ngModel)]="radioBoundProperty" value= ...

Transform a Django/Python dictionary into a JavaScript dictionary using JSON

I need to convert a Python dictionary into a JavaScript dictionary. From what I understand, I have to first convert the Python dict into JSON format and then transform it into a JavaScript Object. view.py jsonheaderdict = json.dumps(headerdict) {{jsonhe ...

What is the best way to utilize regex to replace two elements simultaneously?

I am facing a challenge with manipulating a string of characters by adding span tags to highlight specific words and change their color. While I have successfully implemented the changes for one pattern using regex, I'm struggling to do the same for a ...

The issue of gallery image loading with the galleryView jQuery plugin is causing problems

Hi fellow developers, I could really use some assistance. I've been working on implementing the jquery galleryview plugin for my image gallery (check out my gallery here). Unfortunately, I'm running into an issue where the gallery is not loading ...

The while loop is unyielding, persisting beyond the realm of

After executing this script, it displays the HP values for both Pokemon. Pressing 1 and pressing enter subtracts your attack points from the enemy's hit points. The goal is to stop the battle when either you or the enemy reaches 0 or below hit points ...

The 'file' property of undefined throws an error in ng-file-upload

I am currently exploring the functionality of ng-file-upload from this repository: https://github.com/danialfarid/ng-file-upload I have successfully implemented the basic setup as follows: HTML: <section ng-controller="MyController"> ...